From 2059e7ae18fd7e4fc1419434df55cafc0106ed44 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 13 Dec 2022 17:41:39 +0200 Subject: [PATCH 001/421] UI: Add setting enable selection for flot widget --- .../home/components/widget/lib/flot-widget.models.ts | 1 + .../modules/home/components/widget/lib/flot-widget.ts | 7 +++++-- .../chart/flot-widget-settings.component.html | 11 ++++++++--- .../settings/chart/flot-widget-settings.component.ts | 2 ++ ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts index 78c9245614..0e6b5bb316 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts @@ -128,6 +128,7 @@ export interface TbFlotYAxisSettings { export interface TbFlotBaseSettings { stack: boolean; + enableSelection: boolean; shadowSize: number; fontColor: string; fontSize: number; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index d71d9e84f2..89d6ddfaf3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -118,6 +118,8 @@ export class TbFlot { private mouseleaveHandler = this.onFlotMouseLeave.bind(this); private flotClickHandler = this.onFlotClick.bind(this); + private enableSelection: boolean; + private readonly showTooltip: boolean; private readonly animatedPie: boolean; private pieDataAnimationDuration: number; @@ -132,6 +134,7 @@ export class TbFlot { this.chartType = this.chartType || 'line'; this.settings = ctx.settings as TbFlotSettings; this.utils = this.ctx.$injector.get(UtilsService); + this.enableSelection = isDefined(this.settings.enableSelection) ? this.settings.enableSelection : true; this.showTooltip = isDefined(this.settings.showTooltip) ? this.settings.showTooltip : true; this.tooltip = this.showTooltip ? $('#flot-series-tooltip') : null; if (this.tooltip?.length === 0) { @@ -168,7 +171,7 @@ export class TbFlot { }; if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'state') { - this.options.selection = { mode : 'x' }; + this.options.selection = { mode: this.enableSelection ? 'x' : null }; this.options.xaxes = []; this.xaxis = { mode: 'time', @@ -1251,7 +1254,7 @@ export class TbFlot { this.$element.css('pointer-events', ''); this.$element.addClass('mouse-events'); if (this.chartType !== 'pie') { - this.options.selection = {mode: 'x'}; + this.options.selection = {mode: this.enableSelection ? 'x' : null}; this.$element.bind('plotselected', this.flotSelectHandler); this.$element.bind('dblclick', this.dblclickHandler); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html index 06b9bc5f86..a3758665f0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html @@ -18,9 +18,14 @@
widgets.chart.common-settings - - {{ 'widgets.chart.enable-stacking-mode' | translate }} - +
+ + {{ 'widgets.chart.enable-stacking-mode' | translate }} + + + {{ 'widgets.chart.enable-selection' | translate }} + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts index 8d00d55b63..a9b2812d5d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts @@ -44,6 +44,7 @@ import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; export function flotDefaultSettings(chartType: ChartType): Partial { const settings: Partial = { stack: false, + enableSelection: true, fontColor: '#545454', fontSize: 10, showTooltip: true, @@ -145,6 +146,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit // Common settings stack: [false, []], + enableSelection: [true, []], fontSize: [10, [Validators.min(0)]], fontColor: ['#545454', []], 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 3df8a15e52..358cff401d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3764,6 +3764,7 @@ "chart": { "common-settings": "Common settings", "enable-stacking-mode": "Enable stacking mode", + "enable-selection": "Enable selection", "line-shadow-size": "Line shadow size", "display-smooth-lines": "Display smooth (curved) lines", "default-bar-width": "Default bar width for non-aggregated data (milliseconds)", From d5e6b8e7efca18b41f5263e363c8bcb19bf0ae43 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 19 Dec 2022 17:12:11 +0200 Subject: [PATCH 002/421] UI: Refactoring checkbox to select --- .../widget/lib/flot-widget.models.ts | 4 ++- .../home/components/widget/lib/flot-widget.ts | 30 +++++++++++++++---- .../chart/flot-widget-settings.component.html | 20 +++++++++++-- .../chart/flot-widget-settings.component.ts | 4 +-- .../assets/locale/locale.constant-en_US.json | 6 +++- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts index 0e6b5bb316..1ec9e7b994 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts @@ -128,7 +128,7 @@ export interface TbFlotYAxisSettings { export interface TbFlotBaseSettings { stack: boolean; - enableSelection: boolean; + enableSelection: FlotSelection; shadowSize: number; fontColor: string; fontSize: number; @@ -170,6 +170,8 @@ export interface TbFlotGraphSettings extends TbFlotBaseSettings, export declare type BarAlignment = 'left' | 'right' | 'center'; +export declare type FlotSelection = 'enable' | 'disable' | 'mobile' | 'desktop'; + export interface TbFlotBarSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings { defaultBarWidth: number; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index 89d6ddfaf3..19f667310b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -37,7 +37,7 @@ import { widgetType } from '@app/shared/models/widget.models'; import { - ChartType, + ChartType, FlotSelection, TbFlotAxisOptions, TbFlotHoverInfo, TbFlotKeySettings, @@ -118,7 +118,8 @@ export class TbFlot { private mouseleaveHandler = this.onFlotMouseLeave.bind(this); private flotClickHandler = this.onFlotClick.bind(this); - private enableSelection: boolean; + private enableSelection: FlotSelection; + private selectionMode: 'x' | null; private readonly showTooltip: boolean; private readonly animatedPie: boolean; @@ -134,7 +135,8 @@ export class TbFlot { this.chartType = this.chartType || 'line'; this.settings = ctx.settings as TbFlotSettings; this.utils = this.ctx.$injector.get(UtilsService); - this.enableSelection = isDefined(this.settings.enableSelection) ? this.settings.enableSelection : true; + this.enableSelection = isDefined(this.settings.enableSelection) ? this.settings.enableSelection : 'enable'; + this.checkSelectionMode(); this.showTooltip = isDefined(this.settings.showTooltip) ? this.settings.showTooltip : true; this.tooltip = this.showTooltip ? $('#flot-series-tooltip') : null; if (this.tooltip?.length === 0) { @@ -171,7 +173,7 @@ export class TbFlot { }; if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'state') { - this.options.selection = { mode: this.enableSelection ? 'x' : null }; + this.options.selection = { mode: this.selectionMode }; this.options.xaxes = []; this.xaxis = { mode: 'time', @@ -587,6 +589,24 @@ export class TbFlot { this.createPlot(); } + mobileModeChanged() { + this.checkSelectionMode(); + this.options.selection = { mode: this.selectionMode }; + this.redrawPlot(); + } + + private checkSelectionMode() { + if (this.enableSelection === 'enable') { + this.selectionMode = 'x'; + } else if (this.enableSelection === 'mobile' && this.ctx.isMobile) { + this.selectionMode = 'x'; + } else if (this.enableSelection === 'desktop' && !this.ctx.isMobile) { + this.selectionMode = 'x'; + } else { + this.selectionMode = null; + } + } + public update() { if (this.updateTimeoutHandle) { clearTimeout(this.updateTimeoutHandle); @@ -1254,7 +1274,7 @@ export class TbFlot { this.$element.css('pointer-events', ''); this.$element.addClass('mouse-events'); if (this.chartType !== 'pie') { - this.options.selection = {mode: this.enableSelection ? 'x' : null}; + this.options.selection = {mode: this.selectionMode}; this.$element.bind('plotselected', this.flotSelectHandler); this.$element.bind('dblclick', this.dblclickHandler); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html index a3758665f0..19280f8d45 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html @@ -22,9 +22,23 @@ {{ 'widgets.chart.enable-stacking-mode' | translate }} - - {{ 'widgets.chart.enable-selection' | translate }} - + + widgets.chart.selection + + + {{ 'widgets.chart.selection-enable' | translate }} + + + {{ 'widgets.chart.selection-disable' | translate }} + + + {{ 'widgets.chart.selection-mobile' | translate }} + + + {{ 'widgets.chart.selection-desktop' | translate }} + + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts index a9b2812d5d..ac137dc388 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts @@ -44,7 +44,7 @@ import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; export function flotDefaultSettings(chartType: ChartType): Partial { const settings: Partial = { stack: false, - enableSelection: true, + enableSelection: 'enable', fontColor: '#545454', fontSize: 10, showTooltip: true, @@ -146,7 +146,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit // Common settings stack: [false, []], - enableSelection: [true, []], + enableSelection: ['enable', []], fontSize: [10, [Validators.min(0)]], fontColor: ['#545454', []], 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 358cff401d..d8808cf5e9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3764,7 +3764,11 @@ "chart": { "common-settings": "Common settings", "enable-stacking-mode": "Enable stacking mode", - "enable-selection": "Enable selection", + "selection": "Time range selection", + "selection-enable": "Enable", + "selection-disable": "Disable", + "selection-mobile": "Only mobile", + "selection-desktop": "Only desktop", "line-shadow-size": "Line shadow size", "display-smooth-lines": "Display smooth (curved) lines", "default-bar-width": "Default bar width for non-aggregated data (milliseconds)", From 9a1546f2b95a68f8b5c132e2df7662926c9833b1 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 20 Dec 2022 12:50:53 +0200 Subject: [PATCH 003/421] UI: Upgrade widget bundles --- .../src/main/data/json/system/widget_bundles/charts.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/charts.json b/application/src/main/data/json/system/widget_bundles/charts.json index de32604dbb..452755f083 100644 --- a/application/src/main/data/json/system/widget_bundles/charts.json +++ b/application/src/main/data/json/system/widget_bundles/charts.json @@ -153,7 +153,7 @@ "resources": [], "templateHtml": "", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.mobileModeChanged();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "settingsDirective": "tb-flot-line-widget-settings", @@ -174,7 +174,7 @@ "resources": [], "templateHtml": "", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx);\n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.mobileModeChanged();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", @@ -196,7 +196,7 @@ "resources": [], "templateHtml": "", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar');\n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.mobileModeChanged();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.mobileModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "settingsDirective": "tb-flot-bar-widget-settings", From 245143a988d79fc52105fe5a7376ae4b1cb44d37 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 20 Dec 2022 16:23:21 +0200 Subject: [PATCH 004/421] UI: Refactoring --- .../modules/home/components/widget/lib/flot-widget.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index 19f667310b..c976118356 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -596,13 +596,11 @@ export class TbFlot { } private checkSelectionMode() { - if (this.enableSelection === 'enable') { + if (this.enableSelection === 'enable' || + this.enableSelection === 'mobile' && this.ctx.isMobile || + this.enableSelection === 'desktop' && !this.ctx.isMobile) { this.selectionMode = 'x'; - } else if (this.enableSelection === 'mobile' && this.ctx.isMobile) { - this.selectionMode = 'x'; - } else if (this.enableSelection === 'desktop' && !this.ctx.isMobile) { - this.selectionMode = 'x'; - } else { + } else { this.selectionMode = null; } } From e9a4bb6de2e918c2668a5aa5ff8131ca35ec5114 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 20 Dec 2022 17:15:29 +0200 Subject: [PATCH 005/421] UI: Fixed widget bundles --- .../src/main/data/json/system/widget_bundles/charts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_bundles/charts.json b/application/src/main/data/json/system/widget_bundles/charts.json index 452755f083..3910c9ec13 100644 --- a/application/src/main/data/json/system/widget_bundles/charts.json +++ b/application/src/main/data/json/system/widget_bundles/charts.json @@ -196,7 +196,7 @@ "resources": [], "templateHtml": "", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar');\n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.mobileModeChanged();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.mobileModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar');\n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.mobileModeChanged();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.flot.latestDataUpdate();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "settingsDirective": "tb-flot-bar-widget-settings", From 30b7d819ec95892817396b33e4512df07a0aad95 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 20 Feb 2023 16:30:32 +0200 Subject: [PATCH 006/421] enrichment nodes improvements --- .../server/common/data/EntityType.java | 33 ++++++- .../TbAbstractGetEntityDetailsNode.java | 31 +++--- .../metadata/TbGetCustomerDetailsNode.java | 94 +++++++------------ .../metadata/TbGetTenantAttributeNode.java | 1 + .../metadata/TbGetTenantDetailsNode.java | 11 +-- 5 files changed, 86 insertions(+), 84 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java index 4b5bb65bcb..044cc4556f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java @@ -19,5 +19,36 @@ package org.thingsboard.server.common.data; * @author Andrew Shvayka */ public enum EntityType { - TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, ASSET_PROFILE, API_USAGE_STATE, TB_RESOURCE, OTA_PACKAGE, EDGE, RPC, QUEUE; + + TENANT("Tenant"), + CUSTOMER("Customer"), + USER("User"), + DASHBOARD("Dashboard"), + ASSET("Asset"), + DEVICE("Device"), + ALARM("Alarm"), + RULE_CHAIN("Rule chain"), + RULE_NODE("Rule node"), + ENTITY_VIEW("Entity view"), + WIDGETS_BUNDLE("Widget bundle"), + WIDGET_TYPE("Widget type"), + TENANT_PROFILE("Tenant profile"), + DEVICE_PROFILE("Device profile"), + ASSET_PROFILE("Asset profile"), + API_USAGE_STATE("Api usage state"), + TB_RESOURCE("TB resource"), + OTA_PACKAGE("OTA package"), + EDGE("Edge"), + RPC("Rpc"), + QUEUE("Queue"); + + private final String displayName; + + EntityType(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return displayName; + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java index 928b49318e..c0848f4711 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java @@ -39,7 +39,6 @@ import java.lang.reflect.Type; import java.util.Map; import static org.thingsboard.common.util.DonAsynchron.withCallback; -import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; @Slf4j public abstract class TbAbstractGetEntityDetailsNode implements TbNode { @@ -71,47 +70,47 @@ public abstract class TbAbstractGetEntityDetailsNode getTbMsgListenableFuture(TbContext ctx, TbMsg msg, MessageData messageData, String prefix) { - if (!this.config.getDetailsList().isEmpty()) { + if (this.config.getDetailsList().isEmpty()) { + return Futures.immediateFuture(msg); + } else { ListenableFuture contactBasedListenableFuture = getContactBasedListenableFuture(ctx, msg); ListenableFuture resultObject = addContactProperties(messageData.getData(), contactBasedListenableFuture, prefix); return transformMsg(ctx, msg, resultObject, messageData); - } else { - return Futures.immediateFuture(msg); } } private ListenableFuture transformMsg(TbContext ctx, TbMsg msg, ListenableFuture propertiesFuture, MessageData messageData) { return Futures.transformAsync(propertiesFuture, jsonElement -> { - if (jsonElement != null) { - if (messageData.getDataType().equals("metadata")) { + if (jsonElement == null) { + return Futures.immediateFuture(null); + } else { + if (messageData.getDataSource().equals(DataSource.METADATA)) { Map metadataMap = gson.fromJson(jsonElement.toString(), TYPE); return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), new TbMsgMetaData(metadataMap), msg.getData())); } else { return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), gson.toJson(jsonElement))); } - } else { - return Futures.immediateFuture(null); } }, MoreExecutors.directExecutor()); } private ListenableFuture addContactProperties(JsonElement data, ListenableFuture entityFuture, String prefix) { return Futures.transformAsync(entityFuture, contactBased -> { - if (contactBased != null) { + if (contactBased == null) { + return Futures.immediateFuture(null); + } else { JsonElement jsonElement = null; for (EntityDetails entityDetails : this.config.getDetailsList()) { jsonElement = setProperties(contactBased, data, entityDetails, prefix); } return Futures.immediateFuture(jsonElement); - } else { - return Futures.immediateFuture(null); } }, MoreExecutors.directExecutor()); } @@ -175,7 +174,11 @@ public abstract class TbAbstractGetEntityDetailsNode getContactBasedListenableFuture(TbContext ctx, TbMsg msg) { - return Futures.transformAsync(getCustomer(ctx, msg), customer -> { - if (customer != null) { - return Futures.immediateFuture(customer); - } else { - return Futures.immediateFuture(null); - } - }, MoreExecutors.directExecutor()); + return Futures.transformAsync(getCustomer(ctx, msg), customer -> + customer == null ? Futures.immediateFuture(null) : Futures.immediateFuture(customer), + MoreExecutors.directExecutor()); } private ListenableFuture getCustomer(TbContext ctx, TbMsg msg) { switch (msg.getOriginator().getEntityType()) { case DEVICE: - return Futures.transformAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), new DeviceId(msg.getOriginator().getId())), device -> { - if (device != null) { - if (!device.getCustomerId().isNullUid()) { - return ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), device.getCustomerId()); - } else { - throw new RuntimeException("Device with name '" + device.getName() + "' is not assigned to Customer."); - } - } else { - return Futures.immediateFuture(null); - } - }, MoreExecutors.directExecutor()); + return Futures.transformAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), new DeviceId(msg.getOriginator().getId())), + device -> getCustomerFuture(ctx, device, msg.getOriginator()), MoreExecutors.directExecutor()); case ASSET: - return Futures.transformAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), new AssetId(msg.getOriginator().getId())), asset -> { - if (asset != null) { - if (!asset.getCustomerId().isNullUid()) { - return ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), asset.getCustomerId()); - } else { - throw new RuntimeException("Asset with name '" + asset.getName() + "' is not assigned to Customer."); - } - } else { - return Futures.immediateFuture(null); - } - }, MoreExecutors.directExecutor()); + return Futures.transformAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), new AssetId(msg.getOriginator().getId())), + asset -> getCustomerFuture(ctx, asset, msg.getOriginator()), MoreExecutors.directExecutor()); case ENTITY_VIEW: - return Futures.transformAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), new EntityViewId(msg.getOriginator().getId())), entityView -> { - if (entityView != null) { - if (!entityView.getCustomerId().isNullUid()) { - return ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), entityView.getCustomerId()); - } else { - throw new RuntimeException("EntityView with name '" + entityView.getName() + "' is not assigned to Customer."); - } - } else { - return Futures.immediateFuture(null); - } - }, MoreExecutors.directExecutor()); + return Futures.transformAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), new EntityViewId(msg.getOriginator().getId())), + entityView -> getCustomerFuture(ctx, entityView, msg.getOriginator()), MoreExecutors.directExecutor()); case USER: - return Futures.transformAsync(ctx.getUserService().findUserByIdAsync(ctx.getTenantId(), new UserId(msg.getOriginator().getId())), user -> { - if (user != null) { - if (!user.getCustomerId().isNullUid()) { - return ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), user.getCustomerId()); - } else { - throw new RuntimeException("User with name '" + user.getName() + "' is not assigned to Customer."); - } - } else { - return Futures.immediateFuture(null); - } - }, MoreExecutors.directExecutor()); + return Futures.transformAsync(ctx.getUserService().findUserByIdAsync(ctx.getTenantId(), new UserId(msg.getOriginator().getId())), + user -> getCustomerFuture(ctx, user, msg.getOriginator()), MoreExecutors.directExecutor()); case EDGE: - return Futures.transformAsync(ctx.getEdgeService().findEdgeByIdAsync(ctx.getTenantId(), new EdgeId(msg.getOriginator().getId())), edge -> { - if (edge != null) { - if (!edge.getCustomerId().isNullUid()) { - return ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), edge.getCustomerId()); - } else { - throw new RuntimeException("Edge with name '" + edge.getName() + "' is not assigned to Customer."); - } - } else { - return Futures.immediateFuture(null); - } - }, MoreExecutors.directExecutor()); + return Futures.transformAsync(ctx.getEdgeService().findEdgeByIdAsync(ctx.getTenantId(), new EdgeId(msg.getOriginator().getId())), + edge -> getCustomerFuture(ctx, edge, msg.getOriginator()), MoreExecutors.directExecutor()); default: throw new RuntimeException("Entity with entityType '" + msg.getOriginator().getEntityType() + "' is not supported."); } } + private ListenableFuture getCustomerFuture(TbContext ctx, HasCustomerId hasCustomerId, EntityId originator) { + if (hasCustomerId == null) { + return Futures.immediateFuture(null); + } else { + if (hasCustomerId.getCustomerId().isNullUid()) { + if (hasCustomerId instanceof HasName) { + HasName hasName = (HasName) hasCustomerId; + throw new RuntimeException(originator.getEntityType().getDisplayName() + " with name '" + hasName.getName() + "' is not assigned to Customer."); + } + throw new RuntimeException(originator.getEntityType().getDisplayName() + " with id '" + originator + "' is not assigned to Customer."); + } else { + return ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), hasCustomerId.getCustomerId()); + } + } + } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index 7b3f92c0aa..ab422eece8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -40,6 +40,7 @@ public class TbGetTenantAttributeNode extends TbEntityGetAttrNode { @Override protected ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { + ctx.checkTenantEntity(originator); return Futures.immediateFuture(ctx.getTenantId()); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index 2b7316a59b..52c32a5a1e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -54,12 +54,9 @@ public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode getContactBasedListenableFuture(TbContext ctx, TbMsg msg) { - return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), ctx.getTenantId()), tenant -> { - if (tenant != null) { - return Futures.immediateFuture(tenant); - } else { - return Futures.immediateFuture(null); - } - }, MoreExecutors.directExecutor()); + ctx.checkTenantEntity(msg.getOriginator()); + return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), ctx.getTenantId()), tenant -> + tenant == null ? Futures.immediateFuture(null) : Futures.immediateFuture(tenant), + MoreExecutors.directExecutor()); } } From 5cfcd1946d493618f297091e5edfdd545c8d257a Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 20 Feb 2023 16:34:24 +0200 Subject: [PATCH 007/421] merge else if into one for transformMsg method in TbAbstractGetEntityDetailsNode --- .../metadata/TbAbstractGetEntityDetailsNode.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java index c0848f4711..315da5f16a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java @@ -90,13 +90,11 @@ public abstract class TbAbstractGetEntityDetailsNode { if (jsonElement == null) { return Futures.immediateFuture(null); + } else if (messageData.getDataSource().equals(DataSource.METADATA)) { + Map metadataMap = gson.fromJson(jsonElement.toString(), TYPE); + return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), new TbMsgMetaData(metadataMap), msg.getData())); } else { - if (messageData.getDataSource().equals(DataSource.METADATA)) { - Map metadataMap = gson.fromJson(jsonElement.toString(), TYPE); - return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), new TbMsgMetaData(metadataMap), msg.getData())); - } else { - return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), gson.toJson(jsonElement))); - } + return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), gson.toJson(jsonElement))); } }, MoreExecutors.directExecutor()); } From f29e1f5feff55921339b6f0d34483919039830f3 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 23 Mar 2023 12:44:23 +0200 Subject: [PATCH 008/421] Add fetch to logic, fix and add tests for some rule nodes --- .../rule/engine/api/NodeConfiguration.java | 2 - .../thingsboard/rule/engine/api/TbNode.java | 8 +- .../rule/engine/metadata/FetchTo.java | 21 + .../TbAbstractFetchToNodeConfiguration.java | 23 ++ .../metadata/TbAbstractGetAttributesNode.java | 46 +-- .../metadata/TbAbstractGetEntityAttrNode.java | 110 +++++ .../TbAbstractGetEntityDetailsNode.java | 25 +- ...ractGetEntityDetailsNodeConfiguration.java | 9 +- .../metadata/TbAbstractNodeWithFetchTo.java | 50 +++ .../engine/metadata/TbEntityGetAttrNode.java | 109 ----- .../TbFetchDeviceCredentialsNode.java | 36 +- ...tchDeviceCredentialsNodeConfiguration.java | 9 +- .../engine/metadata/TbGetAttributesNode.java | 15 +- .../TbGetAttributesNodeConfiguration.java | 9 +- .../metadata/TbGetCustomerAttributeNode.java | 17 +- .../metadata/TbGetCustomerDetailsNode.java | 5 +- ...TbGetCustomerDetailsNodeConfiguration.java | 5 +- .../engine/metadata/TbGetDeviceAttrNode.java | 5 +- .../TbGetDeviceAttrNodeConfiguration.java | 5 +- .../TbGetEntityAttrNodeConfiguration.java | 7 +- .../TbGetOriginatorFieldsConfiguration.java | 6 +- .../metadata/TbGetOriginatorFieldsNode.java | 80 ++-- .../TbGetRelatedAttrNodeConfiguration.java | 3 +- .../metadata/TbGetRelatedAttributeNode.java | 25 +- .../metadata/TbGetTenantAttributeNode.java | 18 +- .../metadata/TbGetTenantDetailsNode.java | 4 +- .../TbGetTenantDetailsNodeConfiguration.java | 5 +- .../util/EntitiesFieldsAsyncLoader.java | 42 +- ....java => TbAbstractAttributeNodeTest.java} | 20 +- .../TbAbstractGetAttributesNodeTest.java | 58 +-- .../TbFetchDeviceCredentialsNodeTest.java | 6 +- .../TbGetCustomerAttributeNodeTest.java | 81 +++- .../TbGetOriginatorFieldsNodeTest.java | 376 ++++++++++++++++++ .../TbGetRelatedAttributeNodeTest.java | 83 +++- .../TbGetTenantAttributeNodeTest.java | 85 +++- .../util/EntitiesFieldsAsyncLoaderTest.java | 231 +++++++++++ .../rule/engine/util/TenantIdLoaderTest.java | 7 +- 37 files changed, 1277 insertions(+), 369 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/FetchTo.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java rename rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/{AbstractAttributeNodeTest.java => TbAbstractAttributeNodeTest.java} (96%) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoaderTest.java diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java index 12a25b517c..8c11ddc110 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java @@ -16,7 +16,5 @@ package org.thingsboard.rule.engine.api; public interface NodeConfiguration { - T defaultConfiguration(); - } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java index 18044eb05c..a0fbdaf8e1 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java @@ -24,13 +24,13 @@ import java.util.concurrent.ExecutionException; * Created by ashvayka on 19.01.18. */ public interface TbNode { - void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException; void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException; - default void destroy() {} - - default void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) {} + default void destroy() { + } + default void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) { + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/FetchTo.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/FetchTo.java new file mode 100644 index 0000000000..dcd8c81477 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/FetchTo.java @@ -0,0 +1,21 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.metadata; + +public enum FetchTo { + DATA, + METADATA +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java new file mode 100644 index 0000000000..63ddf9be5f --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.metadata; + +import lombok.Data; + +@Data +public abstract class TbAbstractFetchToNodeConfiguration { + private FetchTo fetchTo; +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java index e5ef68e421..378e7d1358 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java @@ -22,10 +22,8 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.BooleanUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; @@ -53,26 +51,19 @@ import static org.thingsboard.server.common.data.DataConstants.LATEST_TS; import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; import static org.thingsboard.server.common.data.DataConstants.SHARED_SCOPE; -public abstract class TbAbstractGetAttributesNode implements TbNode { - +public abstract class TbAbstractGetAttributesNode extends TbAbstractNodeWithFetchTo { private static final String VALUE = "value"; private static final String TS = "ts"; - - protected C config; - private boolean fetchToData; private boolean isTellFailureIfAbsent; private boolean getLatestValueWithTs; @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = loadGetAttributesNodeConfig(configuration); - this.fetchToData = config.isFetchToData(); - this.getLatestValueWithTs = config.isGetLatestValueWithTs(); - this.isTellFailureIfAbsent = BooleanUtils.toBooleanDefaultIfNull(this.config.isTellFailureIfAbsent(), true); + super.init(ctx, configuration); + getLatestValueWithTs = config.isGetLatestValueWithTs(); + isTellFailureIfAbsent = config.isTellFailureIfAbsent(); } - protected abstract C loadGetAttributesNodeConfig(TbNodeConfiguration configuration) throws TbNodeException; - @Override public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException { try { @@ -92,13 +83,9 @@ public abstract class TbAbstractGetAttributesNode { String key = prefix + kvEntry.getKey(); - if (fetchToData) { - JacksonUtil.addKvEntry((ObjectNode) msgDataNode, kvEntry, key); - } else { + if (FetchTo.DATA.equals(fetchTo)) { + JacksonUtil.addKvEntry(msgDataNode, kvEntry, key); + } else if (FetchTo.METADATA.equals(fetchTo)) { msgMetaData.putValue(key, kvEntry.getValueAsString()); } }); }); }); - TbMsg outMsg = fetchToData ? - TbMsg.transformMsgData(msg, JacksonUtil.toString(msgDataNode)) : - TbMsg.transformMsg(msg, msgMetaData); + + TbMsg outMsg = null; + if (FetchTo.DATA.equals(fetchTo)) { + outMsg = TbMsg.transformMsgData(msg, JacksonUtil.toString(msgDataNode)); + } else if (FetchTo.METADATA.equals(fetchTo)) { + outMsg = TbMsg.transformMsg(msg, msgMetaData); + } + if (failuresMap.isEmpty()) { ctx.tellSuccess(outMsg); } else { @@ -175,7 +167,7 @@ public abstract class TbAbstractGetAttributesNode extends TbAbstractNodeWithFetchTo { + @Override + public void onMsg(TbContext ctx, TbMsg msg) { + ObjectNode msgDataAsJsonNode; + if (FetchTo.DATA.equals(fetchTo)) { + msgDataAsJsonNode = getMsgDataAsObjectNode(msg); + } else { + msgDataAsJsonNode = null; + } + ctx.checkTenantEntity(msg.getOriginator()); + withCallback(findEntityAsync(ctx, msg.getOriginator()), + entityId -> safeGetAttributes(ctx, msg, entityId, msgDataAsJsonNode), + t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); + } + + protected abstract ListenableFuture findEntityAsync(TbContext ctx, EntityId originator); + + private void safeGetAttributes(TbContext ctx, TbMsg msg, T entityId, ObjectNode msgDataAsJsonNode) { + if (entityId == null || entityId.isNullUid()) { + ctx.tellNext(msg, FAILURE); + return; + } + + Map mappingsMap = new HashMap<>(); + config.getAttrMapping().forEach((key, value) -> { + String patternProcessedSourceKey = TbNodeUtils.processPattern(key, msg); + String patternProcessedTargetKey = TbNodeUtils.processPattern(value, msg); + mappingsMap.put(patternProcessedSourceKey, patternProcessedTargetKey); + }); + + var sourceKeys = List.copyOf(mappingsMap.keySet()); + withCallback(config.isTelemetry() ? getLatestTelemetryAsync(ctx, entityId, sourceKeys) : getAttributesAsync(ctx, entityId, sourceKeys), + data -> putDataAndTell(ctx, msg, data, mappingsMap, msgDataAsJsonNode), + t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); + } + + private ListenableFuture> getAttributesAsync(TbContext ctx, EntityId entityId, List attrKeys) { + var latest = ctx.getAttributesService().find(ctx.getTenantId(), entityId, SERVER_SCOPE, attrKeys); + return Futures.transform(latest, l -> + l.stream() + .map(i -> (KvEntry) i) + .collect(Collectors.toList()), + MoreExecutors.directExecutor()); + } + + private ListenableFuture> getLatestTelemetryAsync(TbContext ctx, EntityId entityId, List timeseriesKeys) { + var latest = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, timeseriesKeys); + return Futures.transform(latest, l -> + l.stream() + .map(i -> (KvEntry) i) + .collect(Collectors.toList()), + MoreExecutors.directExecutor()); + } + + private void putDataAndTell(TbContext ctx, TbMsg msg, List data, Map map, ObjectNode msgDataAsJsonNode) { + for (KvEntry entry : data) { + String targetKey = map.get(entry.getKey()); + String value = entry.getValueAsString(); + if (FetchTo.DATA.equals(fetchTo)) { + msgDataAsJsonNode.put(targetKey, value); + } else if (FetchTo.METADATA.equals(fetchTo)) { + msg.getMetaData().putValue(targetKey, value); + } + } + if (FetchTo.DATA.equals(fetchTo)) { + ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(msgDataAsJsonNode))); + } else if (FetchTo.METADATA.equals(fetchTo)) { + ctx.tellSuccess(msg); + } + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java index 315da5f16a..21918029ef 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java @@ -27,11 +27,9 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; -import org.thingsboard.rule.engine.api.TbNodeConfiguration; -import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.util.EntityDetails; import org.thingsboard.server.common.data.ContactBased; +import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -41,20 +39,11 @@ import java.util.Map; import static org.thingsboard.common.util.DonAsynchron.withCallback; @Slf4j -public abstract class TbAbstractGetEntityDetailsNode implements TbNode { - +public abstract class TbAbstractGetEntityDetailsNode extends TbAbstractNodeWithFetchTo { private static final Gson gson = new Gson(); - private static final JsonParser jsonParser = new JsonParser(); private static final Type TYPE = new TypeToken>() { }.getType(); - protected C config; - - @Override - public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = loadGetEntityDetailsNodeConfiguration(configuration); - } - @Override public void onMsg(TbContext ctx, TbMsg msg) { withCallback(getDetails(ctx, msg), @@ -62,22 +51,20 @@ public abstract class TbAbstractGetEntityDetailsNode ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } - protected abstract C loadGetEntityDetailsNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException; - protected abstract ListenableFuture getDetails(TbContext ctx, TbMsg msg); protected abstract ListenableFuture getContactBasedListenableFuture(TbContext ctx, TbMsg msg); protected MessageData getDataAsJson(TbMsg msg) { - if (this.config.isAddToMetadata()) { + if (config.getFetchTo() == FetchTo.METADATA) { return new MessageData(gson.toJsonTree(msg.getMetaData().getData(), TYPE), DataSource.METADATA); } else { - return new MessageData(jsonParser.parse(msg.getData()), DataSource.DATA); + return new MessageData(JsonParser.parseString(msg.getData()), DataSource.DATA); } } protected ListenableFuture getTbMsgListenableFuture(TbContext ctx, TbMsg msg, MessageData messageData, String prefix) { - if (this.config.getDetailsList().isEmpty()) { + if (config.getDetailsList().isEmpty()) { return Futures.immediateFuture(msg); } else { ListenableFuture contactBasedListenableFuture = getContactBasedListenableFuture(ctx, msg); @@ -178,6 +165,4 @@ public abstract class TbAbstractGetEntityDetailsNode detailsList; - - private boolean addToMetadata; - } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java new file mode 100644 index 0000000000..3cf6300b77 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java @@ -0,0 +1,50 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.metadata; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.msg.TbMsg; + +public abstract class TbAbstractNodeWithFetchTo implements TbNode { + protected C config; + protected FetchTo fetchTo; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + config = loadNodeConfiguration(configuration); + if (config.getFetchTo() == null) { + throw new TbNodeException("FetchTo cannot be NULL!"); + } else { + fetchTo = config.getFetchTo(); + } + } + + protected abstract C loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException; + + protected ObjectNode getMsgDataAsObjectNode(TbMsg msg) { + JsonNode msgDataNode = JacksonUtil.toJsonNode(msg.getData()); + if (!msgDataNode.isObject()) { + throw new IllegalArgumentException("Message body is not an object!"); + } + return (ObjectNode) msgDataNode; + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java deleted file mode 100644 index 8031939c7d..0000000000 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbEntityGetAttrNode.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright © 2016-2023 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.rule.engine.metadata; - -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.MoreExecutors; -import lombok.extern.slf4j.Slf4j; -import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; -import org.thingsboard.rule.engine.api.TbNodeConfiguration; -import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.util.TbNodeUtils; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.KvEntry; -import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.server.common.msg.TbMsg; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.thingsboard.common.util.DonAsynchron.withCallback; -import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; - -@Slf4j -public abstract class TbEntityGetAttrNode implements TbNode { - - private TbGetEntityAttrNodeConfiguration config; - - @Override - public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, TbGetEntityAttrNodeConfiguration.class); - } - - @Override - public void onMsg(TbContext ctx, TbMsg msg) { - try { - withCallback(findEntityAsync(ctx, msg.getOriginator()), - entityId -> safeGetAttributes(ctx, msg, entityId), - t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); - } catch (Throwable th) { - ctx.tellFailure(msg, th); - } - } - - private void safeGetAttributes(TbContext ctx, TbMsg msg, T entityId) { - if (entityId == null || entityId.isNullUid()) { - ctx.tellNext(msg, FAILURE); - return; - } - - Map mappingsMap = new HashMap<>(); - config.getAttrMapping().forEach((key, value) -> { - String processPatternKey = TbNodeUtils.processPattern(key, msg); - String processPatternValue = TbNodeUtils.processPattern(value, msg); - mappingsMap.put(processPatternKey, processPatternValue); - }); - - List keys = List.copyOf(mappingsMap.keySet()); - withCallback(config.isTelemetry() ? getLatestTelemetry(ctx, entityId, keys) : getAttributesAsync(ctx, entityId, keys), - attributes -> putAttributesAndTell(ctx, msg, attributes, mappingsMap), - t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); - } - - private ListenableFuture> getAttributesAsync(TbContext ctx, EntityId entityId, List attrKeys) { - ListenableFuture> latest = ctx.getAttributesService().find(ctx.getTenantId(), entityId, SERVER_SCOPE, attrKeys); - return Futures.transform(latest, l -> - l.stream().map(i -> (KvEntry) i).collect(Collectors.toList()), MoreExecutors.directExecutor()); - } - - private ListenableFuture> getLatestTelemetry(TbContext ctx, EntityId entityId, List timeseriesKeys) { - ListenableFuture> latest = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, timeseriesKeys); - return Futures.transform(latest, l -> - l.stream().map(i -> (KvEntry) i).collect(Collectors.toList()), MoreExecutors.directExecutor()); - } - - - private void putAttributesAndTell(TbContext ctx, TbMsg msg, List attributes, Map map) { - attributes.forEach(r -> { - String attrName = map.get(r.getKey()); - msg.getMetaData().putValue(attrName, r.getValueAsString()); - }); - ctx.tellSuccess(msg); - } - - protected abstract ListenableFuture findEntityAsync(TbContext ctx, EntityId originator); - - public void setConfig(TbGetEntityAttrNodeConfiguration config) { - this.config = config; - } - -} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java index 2aa3b7a837..abded26923 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java @@ -15,24 +15,19 @@ */ package org.thingsboard.rule.engine.metadata; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.plugin.ComponentType; -import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgMetaData; import java.util.concurrent.ExecutionException; @@ -48,39 +43,36 @@ import java.util.concurrent.ExecutionException; "- send Message via Failure chain, otherwise Success chain is used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeFetchDeviceCredentialsConfig") -public class TbFetchDeviceCredentialsNode implements TbNode { - +public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo { private static final String CREDENTIALS = "credentials"; private static final String CREDENTIALS_TYPE = "credentialsType"; - TbFetchDeviceCredentialsNodeConfiguration config; - boolean fetchToMetadata; - @Override - public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, TbFetchDeviceCredentialsNodeConfiguration.class); - this.fetchToMetadata = config.isFetchToMetadata(); + protected TbFetchDeviceCredentialsNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { + return TbNodeUtils.convert(configuration, TbFetchDeviceCredentialsNodeConfiguration.class); } @Override public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { - EntityId originator = msg.getOriginator(); + var originator = msg.getOriginator(); if (!EntityType.DEVICE.equals(originator.getEntityType())) { ctx.tellFailure(msg, new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "!")); return; } - DeviceId deviceId = new DeviceId(msg.getOriginator().getId()); - DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(ctx.getTenantId(), deviceId); + + var deviceId = new DeviceId(msg.getOriginator().getId()); + var deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(ctx.getTenantId(), deviceId); if (deviceCredentials == null) { ctx.tellFailure(msg, new RuntimeException("Failed to get Device Credentials for device: " + deviceId + "!")); return; } - TbMsg transformedMsg; - DeviceCredentialsType credentialsType = deviceCredentials.getCredentialsType(); - JsonNode credentialsInfo = ctx.getDeviceCredentialsService().toCredentialsInfo(deviceCredentials); - if (fetchToMetadata) { - TbMsgMetaData metaData = msg.getMetaData(); + TbMsg transformedMsg = null; + var credentialsType = deviceCredentials.getCredentialsType(); + var credentialsInfo = ctx.getDeviceCredentialsService().toCredentialsInfo(deviceCredentials); + + if (FetchTo.METADATA.equals(fetchTo)) { + var metaData = msg.getMetaData(); metaData.putValue(CREDENTIALS_TYPE, credentialsType.name()); if (credentialsType.equals(DeviceCredentialsType.ACCESS_TOKEN) || credentialsType.equals(DeviceCredentialsType.X509_CERTIFICATE)) { metaData.putValue(CREDENTIALS, credentialsInfo.asText()); @@ -88,7 +80,7 @@ public class TbFetchDeviceCredentialsNode implements TbNode { metaData.putValue(CREDENTIALS, JacksonUtil.toString(credentialsInfo)); } transformedMsg = TbMsg.transformMsg(msg, msg.getType(), originator, metaData, msg.getData()); - } else { + } else if (FetchTo.DATA.equals(fetchTo)) { ObjectNode data = (ObjectNode) JacksonUtil.toJsonNode(msg.getData()); data.put(CREDENTIALS_TYPE, credentialsType.name()); data.set(CREDENTIALS, credentialsInfo); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java index 66fddb0770..5f8b5921f8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java @@ -17,18 +17,17 @@ package org.thingsboard.rule.engine.metadata; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; +import lombok.EqualsAndHashCode; import org.thingsboard.rule.engine.api.NodeConfiguration; @Data +@EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties(ignoreUnknown = true) -public class TbFetchDeviceCredentialsNodeConfiguration implements NodeConfiguration { - - private boolean fetchToMetadata; - +public class TbFetchDeviceCredentialsNodeConfiguration extends TbAbstractFetchToNodeConfiguration implements NodeConfiguration { @Override public TbFetchDeviceCredentialsNodeConfiguration defaultConfiguration() { TbFetchDeviceCredentialsNodeConfiguration configuration = new TbFetchDeviceCredentialsNodeConfiguration(); - configuration.setFetchToMetadata(true); + configuration.setFetchTo(FetchTo.METADATA); return configuration; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java index 7e42105e5d..0cd8b9cade 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java @@ -32,25 +32,24 @@ import org.thingsboard.server.common.msg.TbMsg; */ @Slf4j @RuleNode(type = ComponentType.ENRICHMENT, - name = "originator attributes", - configClazz = TbGetAttributesNodeConfiguration.class, - nodeDescription = "Enrich the message body or metadata with the originator attributes and/or timeseries data", - nodeDetails = "If Attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into Message data/metadata " + + name = "originator attributes", + configClazz = TbGetAttributesNodeConfiguration.class, + nodeDescription = "Enrich the message body or metadata with the originator attributes and/or timeseries data", + nodeDetails = "If Attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into Message data/metadata " + "with specific prefix: cs/shared/ss. Latest telemetry value added into Message data/metadata without prefix. " + - "To access those attributes in other nodes this template can be used " + + "To access those attributes in other nodes this template can be used " + "metadata.cs_temperature or metadata.shared_limit ", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeOriginatorAttributesConfig") public class TbGetAttributesNode extends TbAbstractGetAttributesNode { - @Override - protected TbGetAttributesNodeConfiguration loadGetAttributesNodeConfig(TbNodeConfiguration configuration) throws TbNodeException { + protected TbGetAttributesNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { return TbNodeUtils.convert(configuration, TbGetAttributesNodeConfiguration.class); } @Override protected ListenableFuture findEntityIdAsync(TbContext ctx, TbMsg msg) { + ctx.checkTenantEntity(msg.getOriginator()); return Futures.immediateFuture(msg.getOriginator()); } - } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java index e587fb9c7a..7c2b515668 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java @@ -16,8 +16,8 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; +import lombok.EqualsAndHashCode; import org.thingsboard.rule.engine.api.NodeConfiguration; - import java.util.Collections; import java.util.List; @@ -25,8 +25,8 @@ import java.util.List; * Created by ashvayka on 19.01.18. */ @Data -public class TbGetAttributesNodeConfiguration implements NodeConfiguration { - +@EqualsAndHashCode(callSuper = true) +public class TbGetAttributesNodeConfiguration extends TbAbstractFetchToNodeConfiguration implements NodeConfiguration { private List clientAttributeNames; private List sharedAttributeNames; private List serverAttributeNames; @@ -35,7 +35,6 @@ public class TbGetAttributesNodeConfiguration implements NodeConfiguration" + "Useful when you store some parameters on the customer level and would like to use them for message processing.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeCustomerAttributesConfig") -public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode { - +public class TbGetCustomerAttributeNode extends TbAbstractGetEntityAttrNode { @Override protected ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { + ctx.checkTenantEntity(originator); return EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctx, originator); } + @Override + protected TbGetEntityAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { + return TbNodeUtils.convert(configuration, TbGetEntityAttrNodeConfiguration.class); + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java index 3afc66c4dc..cdcf522876 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java @@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -48,16 +49,16 @@ import org.thingsboard.server.common.msg.TbMsg; uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode { - private static final String CUSTOMER_PREFIX = "customer_"; @Override - protected TbGetCustomerDetailsNodeConfiguration loadGetEntityDetailsNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { + protected TbGetCustomerDetailsNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { return TbNodeUtils.convert(configuration, TbGetCustomerDetailsNodeConfiguration.class); } @Override protected ListenableFuture getDetails(TbContext ctx, TbMsg msg) { + ctx.checkTenantEntity(msg.getOriginator()); return getTbMsgListenableFuture(ctx, msg, getDataAsJson(msg), CUSTOMER_PREFIX); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java index 0d74d49942..91587e18f2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java @@ -16,18 +16,19 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; +import lombok.EqualsAndHashCode; import org.thingsboard.rule.engine.api.NodeConfiguration; import java.util.Collections; @Data +@EqualsAndHashCode(callSuper = true) public class TbGetCustomerDetailsNodeConfiguration extends TbAbstractGetEntityDetailsNodeConfiguration implements NodeConfiguration { - - @Override public TbGetCustomerDetailsNodeConfiguration defaultConfiguration() { TbGetCustomerDetailsNodeConfiguration configuration = new TbGetCustomerDetailsNodeConfiguration(); configuration.setDetailsList(Collections.emptyList()); + configuration.setFetchTo(FetchTo.METADATA); return configuration; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java index b0a221e46e..96230ae28f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java @@ -39,15 +39,14 @@ import org.thingsboard.server.common.msg.TbMsg; uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeDeviceAttributesConfig") public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode { - @Override - protected TbGetDeviceAttrNodeConfiguration loadGetAttributesNodeConfig(TbNodeConfiguration configuration) throws TbNodeException { + protected TbGetDeviceAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { return TbNodeUtils.convert(configuration, TbGetDeviceAttrNodeConfiguration.class); } @Override protected ListenableFuture findEntityIdAsync(TbContext ctx, TbMsg msg) { + ctx.checkTenantEntity(msg.getOriginator()); return EntitiesRelatedDeviceIdAsyncLoader.findDeviceAsync(ctx, msg.getOriginator(), config.getDeviceRelationsQuery()); } - } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java index ac5b98134a..f3ba3651cc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java @@ -16,6 +16,7 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; +import lombok.EqualsAndHashCode; import org.thingsboard.rule.engine.data.DeviceRelationsQuery; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; @@ -23,8 +24,8 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection; import java.util.Collections; @Data +@EqualsAndHashCode(callSuper = true) public class TbGetDeviceAttrNodeConfiguration extends TbGetAttributesNodeConfiguration { - private DeviceRelationsQuery deviceRelationsQuery; @Override @@ -36,7 +37,7 @@ public class TbGetDeviceAttrNodeConfiguration extends TbGetAttributesNodeConfigu configuration.setLatestTsKeyNames(Collections.emptyList()); configuration.setTellFailureIfAbsent(true); configuration.setGetLatestValueWithTs(false); - configuration.setFetchToData(false); + configuration.setFetchTo(FetchTo.METADATA); DeviceRelationsQuery deviceRelationsQuery = new DeviceRelationsQuery(); deviceRelationsQuery.setDirection(EntitySearchDirection.FROM); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java index be2eab5bb0..12a94e227f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java @@ -16,15 +16,15 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; +import lombok.EqualsAndHashCode; import org.thingsboard.rule.engine.api.NodeConfiguration; import java.util.HashMap; import java.util.Map; -import java.util.Optional; @Data -public class TbGetEntityAttrNodeConfiguration implements NodeConfiguration { - +@EqualsAndHashCode(callSuper = true) +public class TbGetEntityAttrNodeConfiguration extends TbAbstractFetchToNodeConfiguration implements NodeConfiguration { private Map attrMapping; private boolean isTelemetry = false; @@ -35,6 +35,7 @@ public class TbGetEntityAttrNodeConfiguration implements NodeConfiguration { - +@EqualsAndHashCode(callSuper = true) +public class TbGetOriginatorFieldsConfiguration extends TbAbstractFetchToNodeConfiguration implements NodeConfiguration { private Map fieldsMapping; private boolean ignoreNullStrings; @@ -35,6 +36,7 @@ public class TbGetOriginatorFieldsConfiguration implements NodeConfiguration { @Override - public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - config = TbNodeUtils.convert(configuration, TbGetOriginatorFieldsConfiguration.class); - ignoreNullStrings = config.isIgnoreNullStrings(); + protected TbGetOriginatorFieldsConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { + return TbNodeUtils.convert(configuration, TbGetOriginatorFieldsConfiguration.class); } @Override public void onMsg(TbContext ctx, TbMsg msg) { - try { - withCallback(putEntityFields(ctx, msg.getOriginator(), msg), - i -> ctx.tellSuccess(msg), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); - } catch (Throwable th) { - ctx.tellFailure(msg, th); + ObjectNode msgDataAsJsonNode; + if (FetchTo.DATA.equals(fetchTo)) { + msgDataAsJsonNode = getMsgDataAsObjectNode(msg); + } else { + msgDataAsJsonNode = null; } + ctx.checkTenantEntity(msg.getOriginator()); + withCallback(collectMappedEntityFieldsAsync(ctx, msg.getOriginator()), + targetKeysToSourceValuesMap -> { + for (var entry : targetKeysToSourceValuesMap.entrySet()) { + var targetKeyName = entry.getKey(); + var sourceFieldValue = entry.getValue(); + if (FetchTo.DATA.equals(fetchTo)) { + msgDataAsJsonNode.put(targetKeyName, sourceFieldValue); + } else if (FetchTo.METADATA.equals(fetchTo)) { + msg.getMetaData().putValue(targetKeyName, sourceFieldValue); + } + } + + if (FetchTo.DATA.equals(fetchTo)) { + ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(msgDataAsJsonNode))); + } else if (FetchTo.METADATA.equals(fetchTo)) { + ctx.tellSuccess(msg); + } + }, + t -> ctx.tellFailure(msg, t), + MoreExecutors.directExecutor()); } - private ListenableFuture putEntityFields(TbContext ctx, EntityId entityId, TbMsg msg) { + private ListenableFuture> collectMappedEntityFieldsAsync(TbContext ctx, EntityId entityId) { if (config.getFieldsMapping().isEmpty()) { - return Futures.immediateFuture(null); + return Futures.immediateFuture(Collections.emptyMap()); } else { return Futures.transform(EntitiesFieldsAsyncLoader.findAsync(ctx, entityId), - data -> { - config.getFieldsMapping().forEach((field, metaKey) -> { - String val = data.getFieldValue(field, ignoreNullStrings); - if (val != null) { - msg.getMetaData().putValue(metaKey, val); + fieldsData -> { + var targetKeysToSourceValuesMap = new HashMap(); + for (var mappingEntry : config.getFieldsMapping().entrySet()) { + var sourceFieldName = mappingEntry.getKey(); + var targetKeyName = mappingEntry.getValue(); + var sourceFieldValue = fieldsData.getFieldValue(sourceFieldName, config.isIgnoreNullStrings()); + if (sourceFieldValue != null) { + targetKeysToSourceValuesMap.put(targetKeyName, sourceFieldValue); } - }); - return null; - }, MoreExecutors.directExecutor() + } + return targetKeysToSourceValuesMap; + }, ctx.getDbCallbackExecutor() ); } } - } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java index 489e04f60e..8df69c67af 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java @@ -16,6 +16,7 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; +import lombok.EqualsAndHashCode; import org.thingsboard.rule.engine.data.RelationsQuery; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; @@ -26,8 +27,8 @@ import java.util.HashMap; import java.util.Map; @Data +@EqualsAndHashCode(callSuper = true) public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfiguration { - private RelationsQuery relationsQuery; @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index b7ef24f36b..d722d1c62b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -27,30 +27,27 @@ import org.thingsboard.server.common.data.plugin.ComponentType; @RuleNode( type = ComponentType.ENRICHMENT, - name="related attributes", + name = "related attributes", configClazz = TbGetRelatedAttrNodeConfiguration.class, - nodeDescription = "Add Originators Related Entity Attributes or Latest Telemetry into Message Metadata", + nodeDescription = "Add Originators Related Entity Attributes or Latest Telemetry into Message Metadata/Data", nodeDetails = "Related Entity found using configured relation direction and Relation Type. " + "If multiple Related Entities are found, only first Entity is used for attributes enrichment, other entities are discarded. " + - "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + - "If Latest Telemetry enrichment configured, latest telemetry added into metadata. " + + "If Attributes enrichment configured, server scope attributes are added into Message Metadata/Data. " + + "If Latest Telemetry enrichment configured, latest telemetry added into Metadata/Data. " + "To access those attributes in other nodes this template can be used " + "metadata.temperature.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeRelatedAttributesConfig") - -public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode { - - private TbGetRelatedAttrNodeConfiguration config; - +public class TbGetRelatedAttributeNode extends TbAbstractGetEntityAttrNode { @Override - public void init(TbContext context, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, TbGetRelatedAttrNodeConfiguration.class); - setConfig(config); + public TbGetRelatedAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { + return TbNodeUtils.convert(configuration, TbGetRelatedAttrNodeConfiguration.class); } @Override - protected ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { - return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, originator, config.getRelationsQuery()); + public ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { + ctx.checkTenantEntity(originator); + var relatedAttrConfig = (TbGetRelatedAttrNodeConfiguration) config; + return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, originator, relatedAttrConfig.getRelationsQuery()); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index ab422eece8..87b60dfdaf 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -20,6 +20,9 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -29,19 +32,22 @@ import org.thingsboard.server.common.data.plugin.ComponentType; type = ComponentType.ENRICHMENT, name="tenant attributes", configClazz = TbGetEntityAttrNodeConfiguration.class, - nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata", - nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + - "If Latest Telemetry enrichment configured, latest telemetry added into metadata. " + + nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata/Data", + nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message Metadata/Data. " + + "If Latest Telemetry enrichment configured, latest telemetry added into Metadata/Data. " + "To access those attributes in other nodes this template can be used " + "metadata.temperature.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeTenantAttributesConfig") -public class TbGetTenantAttributeNode extends TbEntityGetAttrNode { - +public class TbGetTenantAttributeNode extends TbAbstractGetEntityAttrNode { @Override - protected ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { + public ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { ctx.checkTenantEntity(originator); return Futures.immediateFuture(ctx.getTenantId()); } + @Override + public TbGetEntityAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { + return TbNodeUtils.convert(configuration, TbGetEntityAttrNodeConfiguration.class); + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index 52c32a5a1e..983b17e61e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -25,6 +25,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.ContactBased; +import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -39,11 +40,10 @@ import org.thingsboard.server.common.msg.TbMsg; uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode { - private static final String TENANT_PREFIX = "tenant_"; @Override - protected TbGetTenantDetailsNodeConfiguration loadGetEntityDetailsNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { + protected TbGetTenantDetailsNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { return TbNodeUtils.convert(configuration, TbGetTenantDetailsNodeConfiguration.class); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeConfiguration.java index 7770d6acb1..e3608abbbd 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeConfiguration.java @@ -16,18 +16,19 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; +import lombok.EqualsAndHashCode; import org.thingsboard.rule.engine.api.NodeConfiguration; import java.util.Collections; @Data +@EqualsAndHashCode(callSuper = true) public class TbGetTenantDetailsNodeConfiguration extends TbAbstractGetEntityDetailsNodeConfiguration implements NodeConfiguration { - - @Override public TbGetTenantDetailsNodeConfiguration defaultConfiguration() { TbGetTenantDetailsNodeConfiguration configuration = new TbGetTenantDetailsNodeConfiguration(); configuration.setDetailsList(Collections.emptyList()); + configuration.setFetchTo(FetchTo.METADATA); return configuration; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java index cb9ee7c8b6..9d78005e23 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -18,6 +18,7 @@ package org.thingsboard.rule.engine.util; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.BaseData; @@ -30,47 +31,50 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.id.UserId; import java.util.function.Function; +@Slf4j public class EntitiesFieldsAsyncLoader { - - public static ListenableFuture findAsync(TbContext ctx, EntityId original) { - switch (original.getEntityType()) { + public static ListenableFuture findAsync(TbContext ctx, EntityId originatorId) { + switch (originatorId.getEntityType()) { case TENANT: - return getAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), (TenantId) original), + return toEntityFieldsDataAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), (TenantId) originatorId), EntityFieldsData::new); case CUSTOMER: - return getAsync(ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), (CustomerId) original), + return toEntityFieldsDataAsync(ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), (CustomerId) originatorId), EntityFieldsData::new); case USER: - return getAsync(ctx.getUserService().findUserByIdAsync(ctx.getTenantId(), (UserId) original), + return toEntityFieldsDataAsync(ctx.getUserService().findUserByIdAsync(ctx.getTenantId(), (UserId) originatorId), EntityFieldsData::new); case ASSET: - return getAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), (AssetId) original), + return toEntityFieldsDataAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), (AssetId) originatorId), EntityFieldsData::new); case DEVICE: - return getAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), (DeviceId) original), + return toEntityFieldsDataAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), (DeviceId) originatorId), EntityFieldsData::new); case ALARM: - return getAsync(ctx.getAlarmService().findAlarmByIdAsync(ctx.getTenantId(), (AlarmId) original), + return toEntityFieldsDataAsync(ctx.getAlarmService().findAlarmByIdAsync(ctx.getTenantId(), (AlarmId) originatorId), EntityFieldsData::new); case RULE_CHAIN: - return getAsync(ctx.getRuleChainService().findRuleChainByIdAsync(ctx.getTenantId(), (RuleChainId) original), + return toEntityFieldsDataAsync(ctx.getRuleChainService().findRuleChainByIdAsync(ctx.getTenantId(), (RuleChainId) originatorId), EntityFieldsData::new); case ENTITY_VIEW: - return getAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), (EntityViewId) original), + return toEntityFieldsDataAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), (EntityViewId) originatorId), EntityFieldsData::new); default: - return Futures.immediateFailedFuture(new TbNodeException("Unexpected original EntityType " + original.getEntityType())); + return Futures.immediateFailedFuture(new TbNodeException("Unexpected originator EntityType: " + originatorId.getEntityType())); } } - private static ListenableFuture getAsync( - ListenableFuture future, Function converter) { + private static > ListenableFuture toEntityFieldsDataAsync( + ListenableFuture future, + Function converter + ) { return Futures.transformAsync(future, in -> in != null ? Futures.immediateFuture(converter.apply(in)) - : Futures.immediateFailedFuture(new RuntimeException("Entity not found!")), MoreExecutors.directExecutor()); + : Futures.immediateFailedFuture(new TbNodeException("Entity not found!")), MoreExecutors.directExecutor()); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java similarity index 96% rename from rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java rename to rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java index 45e4f1c27f..a3949587b9 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/AbstractAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -65,7 +65,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.class) -public abstract class AbstractAttributeNodeTest { +public abstract class TbAbstractAttributeNodeTest { final CustomerId customerId = new CustomerId(Uuids.timeBased()); final TenantId tenantId = TenantId.fromUUID(Uuids.timeBased()); final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); @@ -86,9 +86,9 @@ public abstract class AbstractAttributeNodeTest { DeviceService deviceService; TbMsg msg; Map metaData; - TbEntityGetAttrNode node; + TbAbstractGetEntityAttrNode node; - void init(TbEntityGetAttrNode node) throws TbNodeException { + void init(TbAbstractGetEntityAttrNode node) throws TbNodeException { ObjectMapper mapper = JacksonUtil.OBJECT_MAPPER; TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(getTbNodeConfig())); @@ -117,7 +117,6 @@ public abstract class AbstractAttributeNodeTest { } void errorThrownIfCannotLoadAttributesAsync(User user) { - msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getAttributesService()).thenReturn(attributesService); @@ -168,7 +167,7 @@ public abstract class AbstractAttributeNodeTest { ObjectMapper mapper = JacksonUtil.OBJECT_MAPPER; TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(getTbNodeConfigForTelemetry())); - TbEntityGetAttrNode node = getEmptyNode(); + TbAbstractGetEntityAttrNode node = getEmptyNode(); node.init(null, nodeConfiguration); msg = TbMsg.newMsg("DEVICE", device.getId(), new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); @@ -210,10 +209,11 @@ public abstract class AbstractAttributeNodeTest { conf.put(keyAttrConf, valueAttrConf); config.setAttrMapping(conf); config.setTelemetry(isTelemetry); + config.setFetchTo(FetchTo.METADATA); return config; } - protected abstract TbEntityGetAttrNode getEmptyNode(); + protected abstract TbAbstractGetEntityAttrNode getEmptyNode(); abstract EntityId getEntityId(); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNodeTest.java index cfcf1c64a1..853818f226 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNodeTest.java @@ -130,7 +130,7 @@ public class TbAbstractGetAttributesNodeTest { @Test public void fetchToMetadata_whenOnMsg_then_success() throws Exception { - TbGetAttributesNode node = initNode(false, false, false); + TbGetAttributesNode node = initNode(FetchTo.METADATA, false, false); TbMsg msg = getTbMsg(originator); node.onMsg(ctx, msg); @@ -138,9 +138,9 @@ public class TbAbstractGetAttributesNodeTest { TbMsg resultMsg = checkMsg(true); //check attributes - checkAttributes(resultMsg, false, "cs_", clientAttributes); - checkAttributes(resultMsg, false, "ss_", serverAttributes); - checkAttributes(resultMsg, false, "shared_", sharedAttributes); + checkAttributes(resultMsg, FetchTo.METADATA, "cs_", clientAttributes); + checkAttributes(resultMsg, FetchTo.METADATA, "ss_", serverAttributes); + checkAttributes(resultMsg, FetchTo.METADATA, "shared_", sharedAttributes); //check timeseries checkTs(resultMsg, false, false, tsKeys); @@ -148,7 +148,7 @@ public class TbAbstractGetAttributesNodeTest { @Test public void fetchToMetadata_latestWithTs_whenOnMsg_then_success() throws Exception { - TbGetAttributesNode node = initNode(false, true, false); + TbGetAttributesNode node = initNode(FetchTo.METADATA, true, false); TbMsg msg = getTbMsg(originator); node.onMsg(ctx, msg); @@ -156,9 +156,9 @@ public class TbAbstractGetAttributesNodeTest { TbMsg resultMsg = checkMsg(true); //check attributes - checkAttributes(resultMsg, false, "cs_", clientAttributes); - checkAttributes(resultMsg, false, "ss_", serverAttributes); - checkAttributes(resultMsg, false, "shared_", sharedAttributes); + checkAttributes(resultMsg, FetchTo.METADATA, "cs_", clientAttributes); + checkAttributes(resultMsg, FetchTo.METADATA, "ss_", serverAttributes); + checkAttributes(resultMsg, FetchTo.METADATA, "shared_", sharedAttributes); //check timeseries with ts checkTs(resultMsg, false, true, tsKeys); @@ -166,7 +166,7 @@ public class TbAbstractGetAttributesNodeTest { @Test public void fetchToData_whenOnMsg_then_success() throws Exception { - TbGetAttributesNode node = initNode(true, false, false); + TbGetAttributesNode node = initNode(FetchTo.DATA, false, false); TbMsg msg = getTbMsg(originator); node.onMsg(ctx, msg); @@ -174,9 +174,9 @@ public class TbAbstractGetAttributesNodeTest { TbMsg resultMsg = checkMsg(true); //check attributes - checkAttributes(resultMsg, true, "cs_", clientAttributes); - checkAttributes(resultMsg, true, "ss_", serverAttributes); - checkAttributes(resultMsg, true, "shared_", sharedAttributes); + checkAttributes(resultMsg, FetchTo.DATA, "cs_", clientAttributes); + checkAttributes(resultMsg, FetchTo.DATA, "ss_", serverAttributes); + checkAttributes(resultMsg, FetchTo.DATA, "shared_", sharedAttributes); //check timeseries checkTs(resultMsg, true, false, tsKeys); @@ -184,7 +184,7 @@ public class TbAbstractGetAttributesNodeTest { @Test public void fetchToData_latestWithTs_whenOnMsg_then_success() throws Exception { - TbGetAttributesNode node = initNode(true, true, false); + TbGetAttributesNode node = initNode(FetchTo.DATA, true, false); TbMsg msg = getTbMsg(originator); node.onMsg(ctx, msg); @@ -192,9 +192,9 @@ public class TbAbstractGetAttributesNodeTest { TbMsg resultMsg = checkMsg(true); //check attributes - checkAttributes(resultMsg, true, "cs_", clientAttributes); - checkAttributes(resultMsg, true, "ss_", serverAttributes); - checkAttributes(resultMsg, true, "shared_", sharedAttributes); + checkAttributes(resultMsg, FetchTo.DATA, "cs_", clientAttributes); + checkAttributes(resultMsg, FetchTo.DATA, "ss_", serverAttributes); + checkAttributes(resultMsg, FetchTo.DATA, "shared_", sharedAttributes); //check timeseries with ts checkTs(resultMsg, true, true, tsKeys); @@ -202,7 +202,7 @@ public class TbAbstractGetAttributesNodeTest { @Test public void fetchToMetadata_whenOnMsg_then_failure() throws Exception { - TbGetAttributesNode node = initNode(false, false, true); + TbGetAttributesNode node = initNode(FetchTo.METADATA, false, true); TbMsg msg = getTbMsg(originator); node.onMsg(ctx, msg); @@ -210,9 +210,9 @@ public class TbAbstractGetAttributesNodeTest { TbMsg actualMsg = checkMsg(false); //check attributes - checkAttributes(actualMsg, false, "cs_", clientAttributes); - checkAttributes(actualMsg, false, "ss_", serverAttributes); - checkAttributes(actualMsg, false, "shared_", sharedAttributes); + checkAttributes(actualMsg, FetchTo.METADATA, "cs_", clientAttributes); + checkAttributes(actualMsg, FetchTo.METADATA, "ss_", serverAttributes); + checkAttributes(actualMsg, FetchTo.METADATA, "shared_", sharedAttributes); //check timeseries with ts checkTs(actualMsg, false, false, tsKeys); @@ -220,7 +220,7 @@ public class TbAbstractGetAttributesNodeTest { @Test public void fetchToData_whenOnMsg_then_failure() throws Exception { - TbGetAttributesNode node = initNode(true, true, true); + TbGetAttributesNode node = initNode(FetchTo.DATA, true, true); TbMsg msg = getTbMsg(originator); node.onMsg(ctx, msg); @@ -228,9 +228,9 @@ public class TbAbstractGetAttributesNodeTest { TbMsg actualMsg = checkMsg(false); //check attributes - checkAttributes(actualMsg, true, "cs_", clientAttributes); - checkAttributes(actualMsg, true, "ss_", serverAttributes); - checkAttributes(actualMsg, true, "shared_", sharedAttributes); + checkAttributes(actualMsg, FetchTo.DATA, "cs_", clientAttributes); + checkAttributes(actualMsg, FetchTo.DATA, "ss_", serverAttributes); + checkAttributes(actualMsg, FetchTo.DATA, "shared_", sharedAttributes); //check timeseries with ts checkTs(actualMsg, true, true, tsKeys); @@ -238,7 +238,7 @@ public class TbAbstractGetAttributesNodeTest { @Test public void fetchToData_whenOnMsg_and_data_is_not_object_then_failure() throws Exception { - TbGetAttributesNode node = initNode(true, true, true); + TbGetAttributesNode node = initNode(FetchTo.DATA, true, true); TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), "[]"); node.onMsg(ctx, msg); @@ -272,13 +272,13 @@ public class TbAbstractGetAttributesNodeTest { return resultMsg; } - private void checkAttributes(TbMsg actualMsg, boolean fetchToData, String prefix, List attributes) { + private void checkAttributes(TbMsg actualMsg, FetchTo fetchTo, String prefix, List attributes) { JsonNode msgData = JacksonUtil.toJsonNode(actualMsg.getData()); attributes.stream() .filter(attribute -> !attribute.equals("unknown")) .forEach(attribute -> { String result; - if (fetchToData) { + if (FetchTo.DATA.equals(fetchTo)) { result = msgData.get(prefix + attribute).asText(); } else { result = actualMsg.getMetaData().getValue(prefix + attribute); @@ -313,13 +313,13 @@ public class TbAbstractGetAttributesNodeTest { } } - private TbGetAttributesNode initNode(boolean fetchToData, boolean getLatestValueWithTs, boolean isTellFailureIfAbsent) throws TbNodeException { + private TbGetAttributesNode initNode(FetchTo fetchTo, boolean getLatestValueWithTs, boolean isTellFailureIfAbsent) throws TbNodeException { TbGetAttributesNodeConfiguration config = new TbGetAttributesNodeConfiguration(); config.setClientAttributeNames(List.of("client_attr_1", "client_attr_2", "${client_attr_metadata}", "unknown")); config.setServerAttributeNames(List.of("server_attr_1", "server_attr_2", "${server_attr_metadata}", "unknown")); config.setSharedAttributeNames(List.of("shared_attr_1", "shared_attr_2", "$[shared_attr_data]", "unknown")); config.setLatestTsKeyNames(List.of("temperature", "humidity", "unknown")); - config.setFetchToData(fetchToData); + config.setFetchTo(fetchTo); config.setGetLatestValueWithTs(getLatestValueWithTs); config.setTellFailureIfAbsent(isTellFailureIfAbsent); TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java index 1d291545ba..344ce20c20 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java @@ -64,7 +64,7 @@ public class TbFetchDeviceCredentialsNodeTest { callback = mock(TbMsgCallback.class); ctx = mock(TbContext.class); config = new TbFetchDeviceCredentialsNodeConfiguration().defaultConfiguration(); - config.setFetchToMetadata(true); + config.setFetchTo(FetchTo.METADATA); nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); node = spy(new TbFetchDeviceCredentialsNode()); node.init(ctx, nodeConfiguration); @@ -89,13 +89,13 @@ public class TbFetchDeviceCredentialsNodeTest { @Test void givenDefaultConfig_whenInit_thenOK() { assertThat(node.config).isEqualTo(config); - assertThat(node.fetchToMetadata).isEqualTo(true); + assertThat(node.fetchTo).isEqualTo(FetchTo.METADATA); } @Test void givenDefaultConfig_whenVerify_thenOK() { TbFetchDeviceCredentialsNodeConfiguration defaultConfig = new TbFetchDeviceCredentialsNodeConfiguration().defaultConfiguration(); - assertThat(defaultConfig.isFetchToMetadata()).isEqualTo(true); + assertThat(defaultConfig.getFetchTo()).isEqualTo(FetchTo.METADATA); } @Test diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 10b19add34..f18ac3299b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -16,28 +16,47 @@ package org.thingsboard.rule.engine.metadata; import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.UserId; - +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.List; import java.util.UUID; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.class) -public class TbGetCustomerAttributeNodeTest extends AbstractAttributeNodeTest { +public class TbGetCustomerAttributeNodeTest extends TbAbstractAttributeNodeTest { User user = new User(); Asset asset = new Asset(); Device device = new Device(); @@ -56,7 +75,7 @@ public class TbGetCustomerAttributeNodeTest extends AbstractAttributeNodeTest { } @Override - protected TbEntityGetAttrNode getEmptyNode() { + protected TbAbstractGetEntityAttrNode getEmptyNode() { return new TbGetCustomerAttributeNode(); } @@ -65,6 +84,31 @@ public class TbGetCustomerAttributeNodeTest extends AbstractAttributeNodeTest { return customerId; } + @Test + public void errorThrownIfFetchToIsNull() { + var node = new TbGetCustomerAttributeNode(); + var config = new TbGetEntityAttrNodeConfiguration().defaultConfiguration(); + config.setFetchTo(null); + var nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + + var exception = assertThrows(TbNodeException.class, () -> node.init(ctx, nodeConfiguration)); + + assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be NULL!"); + verify(ctx, never()).tellSuccess(any()); + } + + @Test + public void errorThrownIfMsgDataIsNotAnObjectAndFetchToData() { + node.fetchTo = FetchTo.DATA; + node.config.setFetchTo(FetchTo.DATA); + msg = TbMsg.newMsg("SOME_MESSAGE_TYPE", new CustomerId(UUID.randomUUID()), new TbMsgMetaData(), "[]"); + + var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctx, msg)); + + assertThat(exception.getMessage()).isEqualTo("Message body is not an object!"); + verify(ctx, never()).tellSuccess(any()); + } + @Test public void errorThrownIfCannotLoadAttributes() { mockFindUser(user); @@ -89,6 +133,29 @@ public class TbGetCustomerAttributeNodeTest extends AbstractAttributeNodeTest { entityAttributeAddedInMetadata(customerId, "CUSTOMER"); } + @Test + public void customerAttributeAddedInData() { + node.fetchTo = FetchTo.DATA; + node.config.setFetchTo(FetchTo.DATA); + + msg = TbMsg.newMsg("CUSTOMER", customerId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) + .thenReturn(Futures.immediateFuture(attributes)); + + node.onMsg(ctx, msg); + + var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(actualMessageCaptor.capture()); + + var expectedMsgData = "{\"answer\":\"high\"}"; + + assertThat(actualMessageCaptor.getValue().getData()).isEqualTo(expectedMsgData); + } + @Test public void usersCustomerAttributesFetched() { mockFindUser(user); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java new file mode 100644 index 0000000000..77c2cd3130 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java @@ -0,0 +1,376 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.metadata; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.common.util.ListeningExecutor; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.id.DashboardId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.dao.device.DeviceService; + +import java.util.Collections; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class TbGetOriginatorFieldsNodeTest { + private static final EntityId DUMMY_ENTITY_ID = new DeviceId(UUID.randomUUID()); + public static final ListeningExecutor DB_EXECUTOR = new ListeningExecutor() { + @Override + public ListenableFuture executeAsync(Callable task) { + try { + return Futures.immediateFuture(task.call()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void execute(@NotNull Runnable command) { + command.run(); + } + }; + @Mock + private TbContext ctxMock; + @Mock + private DeviceService deviceService; + private TbGetOriginatorFieldsNode node; + private TbGetOriginatorFieldsConfiguration config; + private TbNodeConfiguration nodeConfiguration; + private TbMsg msg; + + @BeforeEach + public void setUp() { + config = new TbGetOriginatorFieldsConfiguration(); + node = new TbGetOriginatorFieldsNode(); + nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + } + + @Test + public void givenConfigWithNullFetchTo_whenOnInit_thenException() { + // GIVEN + config = config.defaultConfiguration(); + config.setFetchTo(null); + nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + + // WHEN + var exception = assertThrows(TbNodeException.class, () -> node.init(ctxMock, nodeConfiguration)); + + // THEN + assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be NULL!"); + verify(ctxMock, never()).tellSuccess(any()); + } + + @Test + public void givenDefaultConfig_whenInit_thenOK() throws TbNodeException { + // GIVEN + config = config.defaultConfiguration(); + nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + + // WHEN + node.init(ctxMock, nodeConfiguration); + + // THEN + assertThat(node.config).isEqualTo(config); + assertThat(config.getFieldsMapping()).isEqualTo(Map.of( + "name", "originatorName", + "type", "originatorType")); + assertThat(config.isIgnoreNullStrings()).isEqualTo(false); + assertThat(node.fetchTo).isEqualTo(FetchTo.METADATA); + } + + @Test + public void givenCustomConfig_whenInit_thenOK() throws TbNodeException { + // GIVEN + config.setFieldsMapping(Map.of( + "sourceField1", "targetKey1", + "sourceField2", "targetKey2", + "sourceField3", "targetKey3")); + config.setIgnoreNullStrings(true); + config.setFetchTo(FetchTo.DATA); + nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + + // WHEN + node.init(ctxMock, nodeConfiguration); + + // THEN + assertThat(node.config).isEqualTo(config); + assertThat(config.getFieldsMapping()).isEqualTo(Map.of( + "sourceField1", "targetKey1", + "sourceField2", "targetKey2", + "sourceField3", "targetKey3")); + assertThat(config.isIgnoreNullStrings()).isEqualTo(true); + assertThat(node.fetchTo).isEqualTo(FetchTo.DATA); + } + + @Test + public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { + // GIVEN + node.fetchTo = FetchTo.DATA; + msg = TbMsg.newMsg("SOME_MESSAGE_TYPE", DUMMY_ENTITY_ID, new TbMsgMetaData(), "[]"); + + // WHEN + var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); + + // THEN + assertThat(exception.getMessage()).isEqualTo("Message body is not an object!"); + verify(ctxMock, never()).tellSuccess(any()); + } + + @Test + public void givenEntityThatDoesNotBelongToTheCurrentTenant_whenOnMsg_thenException() { + // SETUP + var expectedExceptionMessage = "Entity with id: '" + DUMMY_ENTITY_ID + + "' specified in the configuration doesn't belong to the current tenant."; + + // GIVEN + doThrow(new RuntimeException(expectedExceptionMessage)).when(ctxMock).checkTenantEntity(DUMMY_ENTITY_ID); + msg = TbMsg.newMsg("SOME_MESSAGE_TYPE", DUMMY_ENTITY_ID, new TbMsgMetaData(), "{}"); + + // WHEN + var exception = assertThrows(RuntimeException.class, () -> node.onMsg(ctxMock, msg)); + + // THEN + assertThat(exception.getMessage()).isEqualTo(expectedExceptionMessage); + verify(ctxMock, never()).tellSuccess(any()); + } + + @Test + public void givenValidMsgAndFetchToData_whenOnMsg_thenShouldTellSuccessAndFetchToData() { + // GIVEN + var device = new Device(); + device.setId((DeviceId) DUMMY_ENTITY_ID); + device.setName("Test device"); + device.setType("Test device type"); + + config.setFieldsMapping(Map.of( + "name", "originatorName", + "type", "originatorType", + "label", "originatorLabel")); + config.setIgnoreNullStrings(true); + config.setFetchTo(FetchTo.DATA); + + node.config = config; + node.fetchTo = FetchTo.DATA; + var msgMetaData = new TbMsgMetaData(); + var msgData = "{\"temp\":42,\"humidity\":77}"; + msg = TbMsg.newMsg("POST_TELEMETRY_REQUEST", DUMMY_ENTITY_ID, msgMetaData, msgData); + + when(ctxMock.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(device.getId()))).thenReturn(Futures.immediateFuture(device)); + + when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + + // WHEN + node.onMsg(ctxMock, msg); + + // THEN + var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctxMock, times(1)).tellSuccess(actualMessageCaptor.capture()); + verify(ctxMock, never()).tellFailure(any(), any()); + + var expectedMsgData = "{\"temp\":42,\"humidity\":77,\"originatorName\":\"Test device\",\"originatorType\":\"Test device type\"}"; + + assertThat(actualMessageCaptor.getValue().getData()).isEqualTo(expectedMsgData); + assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(msgMetaData); + } + + @Test + public void givenValidMsgAndFetchToMetaData_whenOnMsg_thenShouldTellSuccessAndFetchToMetaData() { + // GIVEN + var device = new Device(); + device.setId((DeviceId) DUMMY_ENTITY_ID); + device.setName("Test device"); + device.setType("Test device type"); + + config.setFieldsMapping(Map.of( + "name", "originatorName", + "type", "originatorType", + "label", "originatorLabel")); + config.setIgnoreNullStrings(true); + config.setFetchTo(FetchTo.METADATA); + + node.config = config; + node.fetchTo = FetchTo.METADATA; + var msgMetaData = new TbMsgMetaData(Map.of( + "testKey1", "testValue1", + "testKey2", "123")); + var msgData = "[\"value1\",\"value2\"]"; + msg = TbMsg.newMsg("POST_TELEMETRY_REQUEST", DUMMY_ENTITY_ID, msgMetaData, msgData); + + when(ctxMock.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(device.getId()))).thenReturn(Futures.immediateFuture(device)); + + when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + + // WHEN + node.onMsg(ctxMock, msg); + + // THEN + var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctxMock, times(1)).tellSuccess(actualMessageCaptor.capture()); + verify(ctxMock, never()).tellFailure(any(), any()); + + var expectedMsgMetaData = new TbMsgMetaData(Map.of( + "testKey1", "testValue1", + "testKey2", "123", + "originatorName", "Test device", + "originatorType", "Test device type" + )); + + assertThat(actualMessageCaptor.getValue().getData()).isEqualTo(msgData); + assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(expectedMsgMetaData); + } + + @Test + public void givenNullEntityFieldsAndIgnoreNullStringsFalse_whenOnMsg_thenShouldTellSuccessAndFetchNullField() { + // GIVEN + var device = new Device(); + device.setId((DeviceId) DUMMY_ENTITY_ID); + device.setName("Test device"); + device.setType("Test device type"); + + config.setFieldsMapping(Map.of( + "name", "originatorName", + "type", "originatorType", + "label", "originatorLabel")); + config.setIgnoreNullStrings(false); + config.setFetchTo(FetchTo.METADATA); + + node.config = config; + node.fetchTo = FetchTo.METADATA; + var msgMetaData = new TbMsgMetaData(Map.of( + "testKey1", "testValue1", + "testKey2", "123")); + var msgData = "[\"value1\",\"value2\"]"; + msg = TbMsg.newMsg("POST_TELEMETRY_REQUEST", DUMMY_ENTITY_ID, msgMetaData, msgData); + + when(ctxMock.getDeviceService()).thenReturn(deviceService); + when(deviceService.findDeviceByIdAsync(any(), eq(device.getId()))).thenReturn(Futures.immediateFuture(device)); + + when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + + // WHEN + node.onMsg(ctxMock, msg); + + // THEN + var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctxMock, times(1)).tellSuccess(actualMessageCaptor.capture()); + verify(ctxMock, never()).tellFailure(any(), any()); + + var expectedMsgMetaData = new TbMsgMetaData(Map.of( + "testKey1", "testValue1", + "testKey2", "123", + "originatorName", "Test device", + "originatorType", "Test device type", + "originatorLabel", "null" + )); + + assertThat(actualMessageCaptor.getValue().getData()).isEqualTo(msgData); + assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(expectedMsgMetaData); + } + + @Test + public void givenEmptyFieldsMapping_whenOnMsg_thenShouldTellSuccessWithSameMsg() { + // GIVEN + config.setFieldsMapping(Collections.emptyMap()); + config.setIgnoreNullStrings(false); + config.setFetchTo(FetchTo.METADATA); + + node.config = config; + node.fetchTo = FetchTo.METADATA; + var msgMetaData = new TbMsgMetaData(Map.of( + "testKey1", "testValue1", + "testKey2", "123")); + var msgData = "[\"value1\",\"value2\"]"; + msg = TbMsg.newMsg("POST_TELEMETRY_REQUEST", DUMMY_ENTITY_ID, msgMetaData, msgData); + + // WHEN + node.onMsg(ctxMock, msg); + + // THEN + var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctxMock, times(1)).tellSuccess(actualMessageCaptor.capture()); + verify(ctxMock, never()).tellFailure(any(), any()); + + var expectedMsgMetaData = new TbMsgMetaData(Map.of( + "testKey1", "testValue1", + "testKey2", "123" + )); + + assertThat(actualMessageCaptor.getValue().getData()).isEqualTo(msgData); + assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(expectedMsgMetaData); + } + + @Test + public void givenUnsupportedEntityType_whenOnMsg_thenShouldTellFailureWithSameMsg() { + // GIVEN + config.setFieldsMapping(Map.of( + "name", "originatorName", + "type", "originatorType", + "label", "originatorLabel")); + config.setIgnoreNullStrings(false); + config.setFetchTo(FetchTo.METADATA); + + node.config = config; + node.fetchTo = FetchTo.METADATA; + var msgMetaData = new TbMsgMetaData(Map.of( + "testKey1", "testValue1", + "testKey2", "123")); + var msgData = "[\"value1\",\"value2\"]"; + msg = TbMsg.newMsg("POST_TELEMETRY_REQUEST", new DashboardId(UUID.randomUUID()), msgMetaData, msgData); + + when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + + // WHEN + node.onMsg(ctxMock, msg); + + // THEN + var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctxMock, times(1)).tellFailure(actualMessageCaptor.capture(), any()); + verify(ctxMock, never()).tellSuccess(any()); + + assertThat(actualMessageCaptor.getValue().getData()).isEqualTo(msgData); + assertThat(actualMessageCaptor.getValue().getMetaData()).isEqualTo(msgMetaData); + } +} \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index 8a41805d26..ef0e94d545 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -15,12 +15,16 @@ */ package org.thingsboard.rule.engine.metadata; +import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.User; @@ -29,7 +33,13 @@ import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.relation.RelationService; import java.util.HashMap; @@ -37,11 +47,19 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.class) -public class TbGetRelatedAttributeNodeTest extends AbstractAttributeNodeTest { +public class TbGetRelatedAttributeNodeTest extends TbAbstractAttributeNodeTest { User user = new User(); Asset asset = new Asset(); Device device = new Device(); @@ -69,7 +87,7 @@ public class TbGetRelatedAttributeNodeTest extends AbstractAttributeNodeTest { } @Override - protected TbEntityGetAttrNode getEmptyNode() { + protected TbAbstractGetEntityAttrNode getEmptyNode() { return new TbGetRelatedAttributeNode(); } @@ -90,6 +108,7 @@ public class TbGetRelatedAttributeNodeTest extends AbstractAttributeNodeTest { conf.put(keyAttrConf, valueAttrConf); config.setAttrMapping(conf); config.setTelemetry(isTelemetry); + config.setFetchTo(FetchTo.METADATA); return config; } @@ -98,6 +117,31 @@ public class TbGetRelatedAttributeNodeTest extends AbstractAttributeNodeTest { return customerId; } + @Test + public void errorThrownIfFetchToIsNull() { + var node = new TbGetRelatedAttributeNode(); + var config = new TbGetRelatedAttrNodeConfiguration().defaultConfiguration(); + config.setFetchTo(null); + var nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + + var exception = assertThrows(TbNodeException.class, () -> node.init(ctx, nodeConfiguration)); + + assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be NULL!"); + verify(ctx, never()).tellSuccess(any()); + } + + @Test + public void errorThrownIfMsgDataIsNotAnObjectAndFetchToData() { + node.fetchTo = FetchTo.DATA; + node.config.setFetchTo(FetchTo.DATA); + msg = TbMsg.newMsg("SOME_MESSAGE_TYPE", new DeviceId(UUID.randomUUID()), new TbMsgMetaData(), "[]"); + + var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctx, msg)); + + assertThat(exception.getMessage()).isEqualTo("Message body is not an object!"); + verify(ctx, never()).tellSuccess(any()); + } + @Test public void errorThrownIfCannotLoadAttributes() { entityRelation.setFrom(user.getId()); @@ -130,6 +174,33 @@ public class TbGetRelatedAttributeNodeTest extends AbstractAttributeNodeTest { entityAttributeAddedInMetadata(customerId, "CUSTOMER"); } + @Test + public void customerAttributeAddedInData() { + node.fetchTo = FetchTo.DATA; + node.config.setFetchTo(FetchTo.DATA); + + entityRelation.setFrom(customerId); + entityRelation.setTo(customerId); + when(relationService.findByQuery(any(), any())).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + + msg = TbMsg.newMsg("CUSTOMER", customerId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(customerId), eq(SERVER_SCOPE), anyCollection())) + .thenReturn(Futures.immediateFuture(attributes)); + + node.onMsg(ctx, msg); + + var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(actualMessageCaptor.capture()); + + var expectedMsgData = "{\"answer\":\"high\"}"; + + assertThat(actualMessageCaptor.getValue().getData()).isEqualTo(expectedMsgData); + } + @Test public void usersCustomerAttributesFetched() { entityRelation.setFrom(user.getId()); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index 510e97dd9c..ce4dde791a 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -15,10 +15,15 @@ */ package org.thingsboard.rule.engine.metadata; +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.Futures; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.User; @@ -26,15 +31,31 @@ import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; - +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.List; import java.util.UUID; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.class) -public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { - +public class TbGetTenantAttributeNodeTest extends TbAbstractAttributeNodeTest { User user = new User(); Asset asset = new Asset(); Device device = new Device(); @@ -56,7 +77,7 @@ public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { } @Override - protected TbEntityGetAttrNode getEmptyNode() { + protected TbAbstractGetEntityAttrNode getEmptyNode() { return new TbGetTenantAttributeNode(); } @@ -65,6 +86,31 @@ public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { return tenantId; } + @Test + public void errorThrownIfFetchToIsNull() { + var node = new TbGetTenantAttributeNode(); + var config = new TbGetEntityAttrNodeConfiguration().defaultConfiguration(); + config.setFetchTo(null); + var nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); + + var exception = assertThrows(TbNodeException.class, () -> node.init(ctx, nodeConfiguration)); + + assertThat(exception.getMessage()).isEqualTo("FetchTo cannot be NULL!"); + verify(ctx, never()).tellSuccess(any()); + } + + @Test + public void errorThrownIfMsgDataIsNotAnObjectAndFetchToData() { + node.fetchTo = FetchTo.DATA; + node.config.setFetchTo(FetchTo.DATA); + msg = TbMsg.newMsg("SOME_MESSAGE_TYPE", new TenantId(UUID.randomUUID()), new TbMsgMetaData(), "[]"); + + var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctx, msg)); + + assertThat(exception.getMessage()).isEqualTo("Message body is not an object!"); + verify(ctx, never()).tellSuccess(any()); + } + @Test public void errorThrownIfCannotLoadAttributes() { errorThrownIfCannotLoadAttributes(user); @@ -86,6 +132,29 @@ public class TbGetTenantAttributeNodeTest extends AbstractAttributeNodeTest { entityAttributeAddedInMetadata(tenantId, "TENANT"); } + @Test + public void customerAttributeAddedInData() { + node.fetchTo = FetchTo.DATA; + node.config.setFetchTo(FetchTo.DATA); + + msg = TbMsg.newMsg("TENANT", tenantId, new TbMsgMetaData(metaData), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + + List attributes = Lists.newArrayList(new BaseAttributeKvEntry(new StringDataEntry("temperature", "high"), 1L)); + + when(ctx.getAttributesService()).thenReturn(attributesService); + when(attributesService.find(any(), eq(tenantId), eq(SERVER_SCOPE), anyCollection())) + .thenReturn(Futures.immediateFuture(attributes)); + + node.onMsg(ctx, msg); + + var actualMessageCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellSuccess(actualMessageCaptor.capture()); + + var expectedMsgData = "{\"answer\":\"high\"}"; + + assertThat(actualMessageCaptor.getValue().getData()).isEqualTo(expectedMsgData); + } + @Test public void usersCustomerAttributesFetched() { usersCustomerAttributesFetched(user); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoaderTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoaderTest.java new file mode 100644 index 0000000000..3374e8e011 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoaderTest.java @@ -0,0 +1,231 @@ +package org.thingsboard.rule.engine.util; + +import com.google.common.util.concurrent.Futures; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.thingsboard.rule.engine.api.RuleEngineAlarmService; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.EntityFieldsData; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UUIDBased; +import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.customer.CustomerService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.entityview.EntityViewService; +import org.thingsboard.server.dao.rule.RuleChainService; +import org.thingsboard.server.dao.tenant.TenantService; +import org.thingsboard.server.dao.user.UserService; + +import java.util.EnumSet; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class EntitiesFieldsAsyncLoaderTest { + private static EnumSet SUPPORTED_ENTITY_TYPES; + private static UUID RANDOM_UUID; + private static TenantId TENANT_ID; + @Mock + private TbContext ctxMock; + @Mock + private TenantService tenantServiceMock; + @Mock + private CustomerService customerServiceMock; + @Mock + private UserService userServiceMock; + @Mock + private AssetService assetServiceMock; + @Mock + private DeviceService deviceServiceMock; + @Mock + private RuleEngineAlarmService ruleEngineAlarmServiceMock; + @Mock + private RuleChainService ruleChainServiceMock; + @Mock + private EntityViewService entityViewServiceMock; + + @BeforeAll + public static void setup() { + RANDOM_UUID = UUID.randomUUID(); + TENANT_ID = new TenantId(UUID.randomUUID()); + SUPPORTED_ENTITY_TYPES = EnumSet.of( + EntityType.TENANT, + EntityType.CUSTOMER, + EntityType.USER, + EntityType.ASSET, + EntityType.DEVICE, + EntityType.ALARM, + EntityType.RULE_CHAIN, + EntityType.ENTITY_VIEW + ); + } + + @Test + public void givenSupportedEntityTypes_whenFindAsync_thenOK() throws ExecutionException, InterruptedException { + for (var entityType : SUPPORTED_ENTITY_TYPES) { + var entityId = EntityIdFactory.getByTypeAndUuid(entityType, RANDOM_UUID); + + initMocks(entityType, false); + + when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + + var actualEntityFieldsData = EntitiesFieldsAsyncLoader.findAsync(ctxMock, entityId).get(); + var expectedEntityFieldsData = new EntityFieldsData(getEntityFromEntityId(entityId)); + + Assertions.assertEquals(expectedEntityFieldsData, actualEntityFieldsData); + } + } + + @Test + public void givenUnsupportedEntityTypes_whenFindAsync_thenException() { + for (var entityType : EntityType.values()) { + if (!SUPPORTED_ENTITY_TYPES.contains(entityType)) { + var entityId = EntityIdFactory.getByTypeAndUuid(entityType, RANDOM_UUID); + + var expectedExceptionMsg = "org.thingsboard.rule.engine.api.TbNodeException: Unexpected originator EntityType: " + entityType; + + var exception = assertThrows(ExecutionException.class, + () -> EntitiesFieldsAsyncLoader.findAsync(ctxMock, entityId).get()); + + assertInstanceOf(TbNodeException.class, exception.getCause()); + assertThat(exception.getMessage()).isEqualTo(expectedExceptionMsg); + } + } + } + + @Test + public void givenSupportedTypeButEntityDoesNotExist_whenFindAsync_thenException() { + for (var entityType : SUPPORTED_ENTITY_TYPES) { + var entityId = EntityIdFactory.getByTypeAndUuid(entityType, RANDOM_UUID); + + initMocks(entityType, true); + when(ctxMock.getTenantId()).thenReturn(TENANT_ID); + + var expectedExceptionMsg = "org.thingsboard.rule.engine.api.TbNodeException: Entity not found!"; + + var exception = assertThrows(ExecutionException.class, + () -> EntitiesFieldsAsyncLoader.findAsync(ctxMock, entityId).get()); + + assertInstanceOf(TbNodeException.class, exception.getCause()); + assertThat(exception.getMessage()).isEqualTo(expectedExceptionMsg); + } + } + + private void initMocks(EntityType entityType, boolean entityDoesNotExist) { + switch (entityType) { + case TENANT: + var tenant = Futures.immediateFuture(entityDoesNotExist ? null : new Tenant(new TenantId(RANDOM_UUID))); + + when(ctxMock.getTenantService()).thenReturn(tenantServiceMock); + doReturn(tenant).when(tenantServiceMock).findTenantByIdAsync(eq(TENANT_ID), any()); + + break; + case CUSTOMER: + var customer = Futures.immediateFuture(entityDoesNotExist ? null : new Customer(new CustomerId(RANDOM_UUID))); + + when(ctxMock.getCustomerService()).thenReturn(customerServiceMock); + doReturn(customer).when(customerServiceMock).findCustomerByIdAsync(eq(TENANT_ID), any()); + + break; + case USER: + var user = Futures.immediateFuture(entityDoesNotExist ? null : new User(new UserId(RANDOM_UUID))); + + when(ctxMock.getUserService()).thenReturn(userServiceMock); + doReturn(user).when(userServiceMock).findUserByIdAsync(eq(TENANT_ID), any()); + + break; + case ASSET: + var asset = Futures.immediateFuture(entityDoesNotExist ? null : new Asset(new AssetId(RANDOM_UUID))); + + when(ctxMock.getAssetService()).thenReturn(assetServiceMock); + doReturn(asset).when(assetServiceMock).findAssetByIdAsync(eq(TENANT_ID), any()); + + break; + case DEVICE: + var device = Futures.immediateFuture(entityDoesNotExist ? null : new Device(new DeviceId(RANDOM_UUID))); + + when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); + doReturn(device).when(deviceServiceMock).findDeviceByIdAsync(eq(TENANT_ID), any()); + + break; + case ALARM: + var alarm = Futures.immediateFuture(entityDoesNotExist ? null : new Alarm(new AlarmId(RANDOM_UUID))); + + when(ctxMock.getAlarmService()).thenReturn(ruleEngineAlarmServiceMock); + doReturn(alarm).when(ruleEngineAlarmServiceMock).findAlarmByIdAsync(eq(TENANT_ID), any()); + + break; + case RULE_CHAIN: + var ruleChain = Futures.immediateFuture(entityDoesNotExist ? null : new RuleChain(new RuleChainId(RANDOM_UUID))); + + when(ctxMock.getRuleChainService()).thenReturn(ruleChainServiceMock); + doReturn(ruleChain).when(ruleChainServiceMock).findRuleChainByIdAsync(eq(TENANT_ID), any()); + + break; + case ENTITY_VIEW: + var entityView = Futures.immediateFuture(entityDoesNotExist ? null : new EntityView(new EntityViewId(RANDOM_UUID))); + + when(ctxMock.getEntityViewService()).thenReturn(entityViewServiceMock); + doReturn(entityView).when(entityViewServiceMock).findEntityViewByIdAsync(eq(TENANT_ID), any()); + + break; + default: + throw new RuntimeException("Unexpected EntityType: " + entityType); + } + } + + private BaseData getEntityFromEntityId(EntityId entityId) { + switch (entityId.getEntityType()) { + case TENANT: + return new Tenant((TenantId) entityId); + case CUSTOMER: + return new Customer((CustomerId) entityId); + case USER: + return new User((UserId) entityId); + case ASSET: + return new Asset((AssetId) entityId); + case DEVICE: + return new Device((DeviceId) entityId); + case ALARM: + return new Alarm((AlarmId) entityId); + case RULE_CHAIN: + return new RuleChain((RuleChainId) entityId); + case ENTITY_VIEW: + return new EntityView((EntityViewId) entityId); + default: + throw new RuntimeException("Unexpected EntityType: " + entityId.getEntityType()); + } + } +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/TenantIdLoaderTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/TenantIdLoaderTest.java index 6f937d7e18..4675784bc8 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/TenantIdLoaderTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/TenantIdLoaderTest.java @@ -56,7 +56,6 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetsBundle; -import org.thingsboard.server.dao.alarm.AlarmCommentService; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; @@ -94,8 +93,6 @@ public class TenantIdLoaderTest { @Mock private RuleEngineAlarmService alarmService; @Mock - private AlarmCommentService alarmCommentService; - @Mock private RuleChainService ruleChainService; @Mock private EntityViewService entityViewService; @@ -312,9 +309,8 @@ public class TenantIdLoaderTest { break; default: - throw new RuntimeException("Unexpected original EntityType " + entityType); + throw new RuntimeException("Unexpected originator EntityType " + entityType); } - } private EntityId getEntityId(EntityType entityType) { @@ -350,5 +346,4 @@ public class TenantIdLoaderTest { public void test_findEntityIdAsync_other_tenant() { checkTenant(new TenantId(UUID.randomUUID()), false); } - } From 89a504da6694537c3da9a66feb93292c2ab99d67 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 23 Mar 2023 12:58:14 +0200 Subject: [PATCH 009/421] Format license headers --- .../engine/util/EntitiesFieldsAsyncLoader.java | 8 ++++---- .../metadata/TbAbstractAttributeNodeTest.java | 8 ++++---- .../metadata/TbGetCustomerAttributeNodeTest.java | 8 ++++---- .../metadata/TbGetOriginatorFieldsNodeTest.java | 8 ++++---- .../metadata/TbGetRelatedAttributeNodeTest.java | 8 ++++---- .../metadata/TbGetTenantAttributeNodeTest.java | 8 ++++---- .../util/EntitiesFieldsAsyncLoaderTest.java | 15 +++++++++++++++ 7 files changed, 39 insertions(+), 24 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java index 9d78005e23..0d54e5ddc1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java index a3949587b9..8ff873ceb4 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index f18ac3299b..16c3219c6e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java index 77c2cd3130..a258cf4c94 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index ef0e94d545..0ed1296d18 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index ce4dde791a..6537657a7f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoaderTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoaderTest.java index 3374e8e011..5dfd8be03f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoaderTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoaderTest.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.thingsboard.rule.engine.util; import com.google.common.util.concurrent.Futures; From 63e01ec38e2f03c9f023450997549e36616a70e5 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 23 Mar 2023 17:16:45 +0200 Subject: [PATCH 010/421] Add update script --- .../install/ThingsboardInstallService.java | 1 + .../update/DefaultDataUpdateService.java | 98 +++++++++++++++++++ .../metadata/TbGetTenantDetailsNode.java | 2 +- 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index c0f4bd5cf4..a1a55f5e14 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -242,6 +242,7 @@ public class ThingsboardInstallService { databaseEntitiesUpgradeService.upgradeDatabase("3.4.4"); log.info("Updating system data..."); systemDataLoaderService.updateSystemWidgets(); + dataUpdateService.updateData("3.4.4"); break; //TODO update CacheCleanupService on the next version upgrade default: diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 43d6a4df0a..08fa99233a 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -28,6 +28,16 @@ import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; +import org.thingsboard.rule.engine.metadata.FetchTo; +import org.thingsboard.rule.engine.metadata.TbFetchDeviceCredentialsNode; +import org.thingsboard.rule.engine.metadata.TbGetAttributesNode; +import org.thingsboard.rule.engine.metadata.TbGetCustomerAttributeNode; +import org.thingsboard.rule.engine.metadata.TbGetCustomerDetailsNode; +import org.thingsboard.rule.engine.metadata.TbGetDeviceAttrNode; +import org.thingsboard.rule.engine.metadata.TbGetOriginatorFieldsNode; +import org.thingsboard.rule.engine.metadata.TbGetRelatedAttributeNode; +import org.thingsboard.rule.engine.metadata.TbGetTenantAttributeNode; +import org.thingsboard.rule.engine.metadata.TbGetTenantDetailsNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; import org.thingsboard.server.common.data.DataConstants; @@ -46,6 +56,7 @@ import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.query.DynamicValue; @@ -83,6 +94,7 @@ import org.thingsboard.server.service.install.TbRuleEngineQueueConfigService; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicLong; @@ -203,11 +215,97 @@ public class DefaultDataUpdateService implements DataUpdateService { log.info("Skipping edge events migration"); } break; + case "3.4.4": + log.info("Updating data from version 3.4.4 to 3.5.0 ..."); + log.info("Started enrichment rule nodes update ..."); + updateEnrichmentRuleNodes(); + log.info("Finished enrichment rule nodes update ..."); + break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } } + private void updateEnrichmentRuleNodes() { + try { + var ruleNodeTypesToUpdate = List.of( + TbGetOriginatorFieldsNode.class.getName(), + TbFetchDeviceCredentialsNode.class.getName(), + TbGetAttributesNode.class.getName(), + TbGetDeviceAttrNode.class.getName(), + TbGetRelatedAttributeNode.class.getName(), + TbGetTenantAttributeNode.class.getName(), + TbGetCustomerAttributeNode.class.getName(), + TbGetCustomerDetailsNode.class.getName(), + TbGetTenantDetailsNode.class.getName() + ); + var ruleChainIdToTenantId = new HashMap(); + ruleNodeTypesToUpdate.forEach(ruleNodeType -> { + var ruleNodes = new PageDataIterable<>( + pageLink -> ruleChainService.findAllRuleNodesByType(ruleNodeType, pageLink), 1024 + ); + for (var ruleNode : ruleNodes) { + var configuration = ruleNode.getConfiguration(); + if (configuration == null) { + log.error("Unable to update [{}] rule node with ID [{}]! Node configuration is null! Skipping this node!", + ruleNodeType, ruleNode.getId()); + continue; + } + if (!configuration.isObject()) { + log.error("Unable to update [{}] rule node with ID [{}]! Node configuration is not an object! Skipping this node!", + ruleNodeType, ruleNode.getId()); + continue; + } + var configObjectNode = (ObjectNode) configuration; + var fetchTo = FetchTo.METADATA; + if (configObjectNode.has("fetchToMetadata")) { + var fetchToMetadata = configObjectNode.get("fetchToMetadata").asText(); + if ("true".equals(fetchToMetadata)) { + fetchTo = FetchTo.METADATA; + } else if ("false".equals(fetchToMetadata)) { + fetchTo = FetchTo.DATA; + } else { + log.error("[fetchToMetadata] property has unexpected value: {}! Expected true or false! Skipping this node ID[{}]!", + fetchToMetadata, ruleNode.getId()); + } + configObjectNode.remove("fetchToMetadata"); + } + if (configObjectNode.has("fetchToData")) { + var fetchToData = configObjectNode.get("fetchToData").asText(); + if ("true".equals(fetchToData)) { + fetchTo = FetchTo.DATA; + } else if ("false".equals(fetchToData)) { + fetchTo = FetchTo.METADATA; + } else { + log.error("[fetchToData] property has unexpected value: {}! Expected true or false! Skipping this node ID[{}]!", + fetchToData, ruleNode.getId()); + } + configObjectNode.remove("fetchToData"); + } + if (configObjectNode.has("addToMetadata")) { + var addToMetadata = configObjectNode.get("addToMetadata").asText(); + if ("true".equals(addToMetadata)) { + fetchTo = FetchTo.METADATA; + } else if ("false".equals(addToMetadata)) { + fetchTo = FetchTo.DATA; + } else { + log.error("[addToMetadata] property has unexpected value: {}! Skipping Expected true or false! Skipping this node ID[{}]!", + addToMetadata, ruleNode.getId()); + } + configObjectNode.remove("addToMetadata"); + } + configObjectNode.put("fetchTo", fetchTo.toString()); + ruleNode.setConfiguration(configObjectNode); + ruleChainIdToTenantId.computeIfAbsent(ruleNode.getRuleChainId(), + ruleChainId -> ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, ruleNode.getRuleChainId()).getTenantId()); + ruleChainService.saveRuleNode(ruleChainIdToTenantId.get(ruleNode.getRuleChainId()), ruleNode); + } + }); + } catch (Exception e) { + log.error("Unexpected error during enrichment rule nodes updating!", e); + } + } + private final PaginatedUpdater deviceProfileEntityDynamicConditionsUpdater = new PaginatedUpdater<>() { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index 983b17e61e..4091226020 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -38,7 +38,7 @@ import org.thingsboard.server.common.msg.TbMsg; "Note: only Device, Asset, and Entity View type are allowed.

" + "If the originator of the message is not assigned to Tenant, or originator type is not supported - Message will be forwarded to Failure chain, otherwise, Success chain will be used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, - configDirective = "tbEnrichmentNodeEntityDetailsConfig") + configDirective = "") // tbEnrichmentNodeEntityDetailsConfig public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode { private static final String TENANT_PREFIX = "tenant_"; From 85e40e78c4bb541e55b2aa3ad85243a95aef0053 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 23 Mar 2023 17:21:57 +0200 Subject: [PATCH 011/421] Fix "Unknown" error cause in enrichment rule nodes --- .../rule/engine/metadata/TbAbstractGetAttributesNode.java | 4 ++-- .../rule/engine/metadata/TbAbstractGetEntityAttrNode.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java index 378e7d1358..866fbfd190 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java @@ -40,12 +40,12 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import static org.thingsboard.common.util.DonAsynchron.withCallback; -import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; import static org.thingsboard.server.common.data.DataConstants.CLIENT_SCOPE; import static org.thingsboard.server.common.data.DataConstants.LATEST_TS; import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @@ -80,7 +80,7 @@ public abstract class TbAbstractGetAttributesNode extends Tb private void safeGetAttributes(TbContext ctx, TbMsg msg, T entityId, ObjectNode msgDataAsJsonNode) { if (entityId == null || entityId.isNullUid()) { - ctx.tellNext(msg, FAILURE); + ctx.tellFailure(msg, new NoSuchElementException("Did not find entity! Msg ID: " + msg.getId())); return; } From f5285ab4855aebef9f043a710b6ed61163a2f01c Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Fri, 24 Mar 2023 12:22:03 +0200 Subject: [PATCH 012/421] Minor fixes and improvements --- .../TbAbstractFetchToNodeConfiguration.java | 8 ++--- .../metadata/TbAbstractGetAttributesNode.java | 35 +++++++++---------- .../metadata/TbAbstractGetEntityAttrNode.java | 8 ++--- .../TbAbstractGetEntityDetailsNode.java | 19 ++++++---- ...ractGetEntityDetailsNodeConfiguration.java | 8 ++--- .../TbFetchDeviceCredentialsNode.java | 12 +++---- ...tchDeviceCredentialsNodeConfiguration.java | 10 +++--- .../engine/metadata/TbGetAttributesNode.java | 8 ++--- .../TbGetAttributesNodeConfiguration.java | 11 +++--- .../metadata/TbGetCustomerAttributeNode.java | 8 ++--- .../metadata/TbGetCustomerDetailsNode.java | 11 +++--- ...TbGetCustomerDetailsNodeConfiguration.java | 10 +++--- .../engine/metadata/TbGetDeviceAttrNode.java | 8 ++--- .../TbGetDeviceAttrNodeConfiguration.java | 12 +++---- .../TbGetEntityAttrNodeConfiguration.java | 14 ++++---- .../TbGetOriginatorFieldsConfiguration.java | 12 +++---- .../metadata/TbGetOriginatorFieldsNode.java | 8 ++--- .../TbGetRelatedAttrNodeConfiguration.java | 19 +++++----- .../metadata/TbGetRelatedAttributeNode.java | 8 ++--- .../metadata/TbGetTenantAttributeNode.java | 10 +++--- .../metadata/TbGetTenantDetailsNode.java | 12 +++---- .../transform/TbAbstractTransformNode.java | 14 ++++---- .../metadata/TbAbstractAttributeNodeTest.java | 16 +++++---- 23 files changed, 142 insertions(+), 139 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java index 63ddf9be5f..ff335d824b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java index 866fbfd190..0a9c3c8703 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -15,8 +15,6 @@ */ package org.thingsboard.rule.engine.metadata; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -34,7 +32,6 @@ import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgMetaData; import java.util.ArrayList; import java.util.HashMap; @@ -89,7 +86,7 @@ public abstract class TbAbstractGetAttributesNode> failuresMap = new ConcurrentHashMap<>(); + var failuresMap = new ConcurrentHashMap>(); ListenableFuture>>> allFutures = Futures.allAsList( getLatestTelemetry(ctx, entityId, TbNodeUtils.processPatterns(config.getLatestTsKeyNames(), msg), failuresMap), getAttrAsync(ctx, entityId, CLIENT_SCOPE, TbNodeUtils.processPatterns(config.getClientAttributeNames(), msg), failuresMap), @@ -97,12 +94,12 @@ public abstract class TbAbstractGetAttributesNode { - TbMsgMetaData msgMetaData = msg.getMetaData().copy(); + var msgMetaData = msg.getMetaData().copy(); futuresList.stream().filter(Objects::nonNull).forEach(kvEntriesMap -> { kvEntriesMap.forEach((keyScope, kvEntryList) -> { - String prefix = getPrefix(keyScope); + var prefix = getPrefix(keyScope); kvEntryList.forEach(kvEntry -> { - String key = prefix + kvEntry.getKey(); + var key = prefix + kvEntry.getKey(); if (FetchTo.DATA.equals(fetchTo)) { JacksonUtil.addKvEntry(msgDataNode, kvEntry, key); } else if (FetchTo.METADATA.equals(fetchTo)) { @@ -131,12 +128,12 @@ public abstract class TbAbstractGetAttributesNode> attributeKvEntryListFuture = ctx.getAttributesService().find(ctx.getTenantId(), entityId, scope, keys); + var attributeKvEntryListFuture = ctx.getAttributesService().find(ctx.getTenantId(), entityId, scope, keys); return Futures.transform(attributeKvEntryListFuture, attributeKvEntryList -> { if (isTellFailureIfAbsent && attributeKvEntryList.size() != keys.size()) { getNotExistingKeys(attributeKvEntryList, keys).forEach(key -> computeFailuresMap(scope, failuresMap, key)); } - Map> mapAttributeKvEntry = new HashMap<>(); + var mapAttributeKvEntry = new HashMap>(); mapAttributeKvEntry.put(scope, attributeKvEntryList); return mapAttributeKvEntry; }, MoreExecutors.directExecutor()); @@ -148,7 +145,7 @@ public abstract class TbAbstractGetAttributesNode> latestTelemetryFutures = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, keys); return Futures.transform(latestTelemetryFutures, tsKvEntries -> { - List listTsKvEntry = new ArrayList<>(); + var listTsKvEntry = new ArrayList(); tsKvEntries.forEach(tsKvEntry -> { if (tsKvEntry.getValue() == null) { if (isTellFailureIfAbsent) { @@ -160,22 +157,22 @@ public abstract class TbAbstractGetAttributesNode> mapTsKvEntry = new HashMap<>(); + var mapTsKvEntry = new HashMap>(); mapTsKvEntry.put(LATEST_TS, listTsKvEntry); return mapTsKvEntry; }, MoreExecutors.directExecutor()); } private TsKvEntry getValueWithTs(TsKvEntry tsKvEntry) { - ObjectMapper mapper = FetchTo.DATA.equals(fetchTo) ? JacksonUtil.OBJECT_MAPPER : JacksonUtil.ALLOW_UNQUOTED_FIELD_NAMES_MAPPER; - ObjectNode value = JacksonUtil.newObjectNode(mapper); + var mapper = FetchTo.DATA.equals(fetchTo) ? JacksonUtil.OBJECT_MAPPER : JacksonUtil.ALLOW_UNQUOTED_FIELD_NAMES_MAPPER; + var value = JacksonUtil.newObjectNode(mapper); value.put(TS, tsKvEntry.getTs()); JacksonUtil.addKvEntry(value, tsKvEntry, VALUE, mapper); return new BasicTsKvEntry(tsKvEntry.getTs(), new JsonDataEntry(tsKvEntry.getKey(), value.toString())); } private String getPrefix(String scope) { - String prefix = ""; + var prefix = ""; switch (scope) { case CLIENT_SCOPE: prefix = "cs_"; @@ -201,7 +198,7 @@ public abstract class TbAbstractGetAttributesNode> failuresMap) { - StringBuilder errorMessage = new StringBuilder("The following attribute/telemetry keys is not present in the DB: ").append("\n"); + var errorMessage = new StringBuilder("The following attribute/telemetry keys is not present in the DB: ").append("\n"); if (failuresMap.containsKey(CLIENT_SCOPE)) { errorMessage.append("\t").append("[" + CLIENT_SCOPE + "]:").append(failuresMap.get(CLIENT_SCOPE).toString()).append("\n"); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java index 874cee2e75..3a02bfa4d5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java index 21918029ef..df46e35226 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -29,7 +29,6 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.util.EntityDetails; import org.thingsboard.server.common.data.ContactBased; -import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -56,10 +55,16 @@ public abstract class TbAbstractGetEntityDetailsNode getContactBasedListenableFuture(TbContext ctx, TbMsg msg); protected MessageData getDataAsJson(TbMsg msg) { - if (config.getFetchTo() == FetchTo.METADATA) { + if (fetchTo == FetchTo.METADATA) { return new MessageData(gson.toJsonTree(msg.getMetaData().getData(), TYPE), DataSource.METADATA); + } else if (fetchTo == FetchTo.DATA) { + var msgDataJsonElement = JsonParser.parseString(msg.getData()); + if (!msgDataJsonElement.isJsonObject()) { + throw new IllegalArgumentException("Message body is not an object!"); + } + return new MessageData(msgDataJsonElement, DataSource.DATA); } else { - return new MessageData(JsonParser.parseString(msg.getData()), DataSource.DATA); + throw new IllegalArgumentException("Unsupported fetchTo value!"); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java index 1da798ae82..0d2840d35c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java index abded26923..99bba12229 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -15,7 +15,6 @@ */ package org.thingsboard.rule.engine.metadata; -import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleNode; @@ -55,6 +54,7 @@ public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo * 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 - * + *

+ * 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. @@ -26,7 +26,7 @@ import org.thingsboard.rule.engine.api.NodeConfiguration; public class TbFetchDeviceCredentialsNodeConfiguration extends TbAbstractFetchToNodeConfiguration implements NodeConfiguration { @Override public TbFetchDeviceCredentialsNodeConfiguration defaultConfiguration() { - TbFetchDeviceCredentialsNodeConfiguration configuration = new TbFetchDeviceCredentialsNodeConfiguration(); + var configuration = new TbFetchDeviceCredentialsNodeConfiguration(); configuration.setFetchTo(FetchTo.METADATA); return configuration; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java index 0cd8b9cade..a280442052 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java index 7c2b515668..4dbb5f98a4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -18,6 +18,7 @@ package org.thingsboard.rule.engine.metadata; import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.rule.engine.api.NodeConfiguration; + import java.util.Collections; import java.util.List; @@ -38,7 +39,7 @@ public class TbGetAttributesNodeConfiguration extends TbAbstractFetchToNodeConfi @Override public TbGetAttributesNodeConfiguration defaultConfiguration() { - TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration(); + var configuration = new TbGetAttributesNodeConfiguration(); configuration.setClientAttributeNames(Collections.emptyList()); configuration.setSharedAttributeNames(Collections.emptyList()); configuration.setServerAttributeNames(Collections.emptyList()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index d00de4dd0e..9796289ba5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java index cdcf522876..18e5c76c10 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; -import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -97,7 +96,7 @@ public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode * 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 - * + *

+ * 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. @@ -26,7 +26,7 @@ import java.util.Collections; public class TbGetCustomerDetailsNodeConfiguration extends TbAbstractGetEntityDetailsNodeConfiguration implements NodeConfiguration { @Override public TbGetCustomerDetailsNodeConfiguration defaultConfiguration() { - TbGetCustomerDetailsNodeConfiguration configuration = new TbGetCustomerDetailsNodeConfiguration(); + var configuration = new TbGetCustomerDetailsNodeConfiguration(); configuration.setDetailsList(Collections.emptyList()); configuration.setFetchTo(FetchTo.METADATA); return configuration; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java index 96230ae28f..20eae3ec99 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java index f3ba3651cc..0dffad1884 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -30,7 +30,7 @@ public class TbGetDeviceAttrNodeConfiguration extends TbGetAttributesNodeConfigu @Override public TbGetDeviceAttrNodeConfiguration defaultConfiguration() { - TbGetDeviceAttrNodeConfiguration configuration = new TbGetDeviceAttrNodeConfiguration(); + var configuration = new TbGetDeviceAttrNodeConfiguration(); configuration.setClientAttributeNames(Collections.emptyList()); configuration.setSharedAttributeNames(Collections.emptyList()); configuration.setServerAttributeNames(Collections.emptyList()); @@ -39,7 +39,7 @@ public class TbGetDeviceAttrNodeConfiguration extends TbGetAttributesNodeConfigu configuration.setGetLatestValueWithTs(false); configuration.setFetchTo(FetchTo.METADATA); - DeviceRelationsQuery deviceRelationsQuery = new DeviceRelationsQuery(); + var deviceRelationsQuery = new DeviceRelationsQuery(); deviceRelationsQuery.setDirection(EntitySearchDirection.FROM); deviceRelationsQuery.setMaxLevel(1); deviceRelationsQuery.setRelationType(EntityRelation.CONTAINS_TYPE); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java index 12a94e227f..c6f6b36f72 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -30,9 +30,9 @@ public class TbGetEntityAttrNodeConfiguration extends TbAbstractFetchToNodeConfi @Override public TbGetEntityAttrNodeConfiguration defaultConfiguration() { - TbGetEntityAttrNodeConfiguration configuration = new TbGetEntityAttrNodeConfiguration(); - Map attrMapping = new HashMap<>(); - attrMapping.putIfAbsent("temperature", "tempo"); + var configuration = new TbGetEntityAttrNodeConfiguration(); + var attrMapping = new HashMap(); + attrMapping.putIfAbsent("serialNumber", "sn"); configuration.setAttrMapping(attrMapping); configuration.setTelemetry(false); configuration.setFetchTo(FetchTo.METADATA); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java index b2f7ea2b26..5d1dd87237 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -30,8 +30,8 @@ public class TbGetOriginatorFieldsConfiguration extends TbAbstractFetchToNodeCon @Override public TbGetOriginatorFieldsConfiguration defaultConfiguration() { - TbGetOriginatorFieldsConfiguration configuration = new TbGetOriginatorFieldsConfiguration(); - Map fieldsMapping = new HashMap<>(); + var configuration = new TbGetOriginatorFieldsConfiguration(); + var fieldsMapping = new HashMap(); fieldsMapping.put("name", "originatorName"); fieldsMapping.put("type", "originatorType"); configuration.setFieldsMapping(fieldsMapping); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java index 7dee45aae0..5012ccacc5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java index 8df69c67af..7207fadb80 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -24,7 +24,6 @@ import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; import java.util.Collections; import java.util.HashMap; -import java.util.Map; @Data @EqualsAndHashCode(callSuper = true) @@ -33,16 +32,16 @@ public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfig @Override public TbGetRelatedAttrNodeConfiguration defaultConfiguration() { - TbGetRelatedAttrNodeConfiguration configuration = new TbGetRelatedAttrNodeConfiguration(); - Map attrMapping = new HashMap<>(); - attrMapping.putIfAbsent("temperature", "tempo"); + var configuration = new TbGetRelatedAttrNodeConfiguration(); + var attrMapping = new HashMap(); + attrMapping.putIfAbsent("serialNumber", "sn"); configuration.setAttrMapping(attrMapping); configuration.setTelemetry(false); - RelationsQuery relationsQuery = new RelationsQuery(); + var relationsQuery = new RelationsQuery(); relationsQuery.setDirection(EntitySearchDirection.FROM); relationsQuery.setMaxLevel(1); - RelationEntityTypeFilter relationEntityTypeFilter = new RelationEntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.emptyList()); + var relationEntityTypeFilter = new RelationEntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.emptyList()); relationsQuery.setFilters(Collections.singletonList(relationEntityTypeFilter)); configuration.setRelationsQuery(relationsQuery); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index d722d1c62b..dc9175eab7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index 87b60dfdaf..c31d6b6f12 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; @Slf4j @RuleNode( type = ComponentType.ENRICHMENT, - name="tenant attributes", + name = "tenant attributes", configClazz = TbGetEntityAttrNodeConfiguration.class, nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata/Data", nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message Metadata/Data. " + diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index 4091226020..f8716d4cb2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -25,7 +25,6 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.ContactBased; -import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -38,7 +37,7 @@ import org.thingsboard.server.common.msg.TbMsg; "Note: only Device, Asset, and Entity View type are allowed.

" + "If the originator of the message is not assigned to Tenant, or originator type is not supported - Message will be forwarded to Failure chain, otherwise, Success chain will be used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, - configDirective = "") // tbEnrichmentNodeEntityDetailsConfig + configDirective = "tbEnrichmentNodeEntityDetailsConfig") public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode { private static final String TENANT_PREFIX = "tenant_"; @@ -49,6 +48,7 @@ public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode getDetails(TbContext ctx, TbMsg msg) { + ctx.checkTenantEntity(msg.getOriginator()); return getTbMsgListenableFuture(ctx, msg, getDataAsJson(msg), TENANT_PREFIX); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java index 042c4c0c38..b90a03a432 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -31,14 +31,12 @@ import org.thingsboard.server.common.msg.queue.TbMsgCallback; import java.util.List; import static org.thingsboard.common.util.DonAsynchron.withCallback; -import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; /** * Created by ashvayka on 19.01.18. */ @Slf4j public abstract class TbAbstractTransformNode implements TbNode { - private TbTransformNodeConfiguration config; @Override @@ -62,7 +60,7 @@ public abstract class TbAbstractTransformNode implements TbNode { if (m != null) { ctx.tellSuccess(m); } else { - ctx.tellNext(msg, FAILURE); + ctx.tellFailure(msg, new RuntimeException("Message is null!")); } } @@ -85,7 +83,7 @@ public abstract class TbAbstractTransformNode implements TbNode { msgs.forEach(newMsg -> ctx.enqueueForTellNext(newMsg, TbRelationTypes.SUCCESS, wrapper::onSuccess, wrapper::onFailure)); } } else { - ctx.tellNext(msg, FAILURE); + ctx.tellFailure(msg, new RuntimeException("Message or messages list are empty!")); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java index 8ff873ceb4..fee6ad38c9 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - * + *

+ * 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. @@ -52,7 +52,9 @@ import org.thingsboard.server.dao.user.UserService; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -61,7 +63,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @RunWith(MockitoJUnitRunner.class) @@ -136,7 +137,10 @@ public abstract class TbAbstractAttributeNodeTest { msg = TbMsg.newMsg("USER", user.getId(), new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); node.onMsg(ctx, msg); - verify(ctx).tellNext(msg, FAILURE); + var exceptionCaptor = ArgumentCaptor.forClass(NoSuchElementException.class); + verify(ctx).tellFailure(eq(msg), exceptionCaptor.capture()); + + assertThat(exceptionCaptor.getValue().getMessage()).contains("Did not find entity! Msg ID: "); assertTrue(msg.getMetaData().getData().isEmpty()); } From dc8e9bdeb9c211a775ca7f9760b180de289e27f3 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Fri, 24 Mar 2023 13:43:51 +0200 Subject: [PATCH 013/421] Fix headers --- .../metadata/TbAbstractFetchToNodeConfiguration.java | 8 ++++---- .../rule/engine/metadata/TbAbstractGetAttributesNode.java | 8 ++++---- .../rule/engine/metadata/TbAbstractGetEntityAttrNode.java | 8 ++++---- .../engine/metadata/TbAbstractGetEntityDetailsNode.java | 8 ++++---- .../TbAbstractGetEntityDetailsNodeConfiguration.java | 8 ++++---- .../engine/metadata/TbFetchDeviceCredentialsNode.java | 8 ++++---- .../TbFetchDeviceCredentialsNodeConfiguration.java | 8 ++++---- .../rule/engine/metadata/TbGetAttributesNode.java | 8 ++++---- .../engine/metadata/TbGetAttributesNodeConfiguration.java | 8 ++++---- .../rule/engine/metadata/TbGetCustomerAttributeNode.java | 8 ++++---- .../rule/engine/metadata/TbGetCustomerDetailsNode.java | 8 ++++---- .../metadata/TbGetCustomerDetailsNodeConfiguration.java | 8 ++++---- .../rule/engine/metadata/TbGetDeviceAttrNode.java | 8 ++++---- .../engine/metadata/TbGetDeviceAttrNodeConfiguration.java | 8 ++++---- .../engine/metadata/TbGetEntityAttrNodeConfiguration.java | 8 ++++---- .../metadata/TbGetOriginatorFieldsConfiguration.java | 8 ++++---- .../rule/engine/metadata/TbGetOriginatorFieldsNode.java | 8 ++++---- .../metadata/TbGetRelatedAttrNodeConfiguration.java | 8 ++++---- .../rule/engine/metadata/TbGetRelatedAttributeNode.java | 8 ++++---- .../rule/engine/metadata/TbGetTenantAttributeNode.java | 8 ++++---- .../rule/engine/metadata/TbGetTenantDetailsNode.java | 8 ++++---- .../rule/engine/transform/TbAbstractTransformNode.java | 8 ++++---- .../rule/engine/metadata/TbAbstractAttributeNodeTest.java | 8 ++++---- 23 files changed, 92 insertions(+), 92 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java index ff335d824b..63ddf9be5f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java index 0a9c3c8703..0c40ace712 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java index 3a02bfa4d5..874cee2e75 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java index df46e35226..4644db2ff7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java index 0d2840d35c..1da798ae82 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java index 99bba12229..0a8ca6b255 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java index 79ac0eb4cd..62fb3eb797 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java index a280442052..0cd8b9cade 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java index 4dbb5f98a4..89c4eb8086 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index 9796289ba5..d00de4dd0e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java index 18e5c76c10..300be8cdff 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java index b54fa02702..06131c4197 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java index 20eae3ec99..96230ae28f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java index 0dffad1884..108a1f5017 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java index c6f6b36f72..fccbdfb39f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java index 5d1dd87237..3c0498f6ba 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java index 5012ccacc5..7dee45aae0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java index 7207fadb80..9387858811 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index dc9175eab7..d722d1c62b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index c31d6b6f12..dcc96e82c1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index f8716d4cb2..c89259d9ad 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java index b90a03a432..bc693d9b97 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java index fee6ad38c9..7dab0a675d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbAbstractAttributeNodeTest.java @@ -1,12 +1,12 @@ /** * Copyright © 2016-2023 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 - *

+ * + * 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. From f16188ae5883551b2d720698905eb1e144da83d0 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 30 Mar 2023 16:27:17 +0300 Subject: [PATCH 014/421] refactoring rule nodes after review --- .../update/DefaultDataUpdateService.java | 44 ++-- .../rule/engine/api/NodeConfiguration.java | 2 + .../thingsboard/rule/engine/api/TbNode.java | 2 + .../TbAbstractFetchToNodeConfiguration.java | 2 + .../metadata/TbAbstractGetAttributesNode.java | 136 +++++------ .../metadata/TbAbstractGetEntityAttrNode.java | 42 ++-- .../TbAbstractGetEntityDetailsNode.java | 214 ++++++++---------- ...ractGetEntityDetailsNodeConfiguration.java | 2 + .../metadata/TbAbstractNodeWithFetchTo.java | 44 +++- .../TbFetchDeviceCredentialsNode.java | 17 +- .../engine/metadata/TbGetAttributesNode.java | 1 - .../TbGetAttributesNodeConfiguration.java | 2 + .../metadata/TbGetCustomerAttributeNode.java | 23 +- .../metadata/TbGetCustomerDetailsNode.java | 27 ++- ...TbGetCustomerDetailsNodeConfiguration.java | 4 +- .../engine/metadata/TbGetDeviceAttrNode.java | 11 +- .../TbGetDeviceAttrNodeConfiguration.java | 2 + .../TbGetEntityAttrNodeConfiguration.java | 6 +- .../TbGetOriginatorFieldsConfiguration.java | 2 + .../metadata/TbGetOriginatorFieldsNode.java | 61 +++-- .../TbGetRelatedAttrNodeConfiguration.java | 5 +- .../metadata/TbGetRelatedAttributeNode.java | 15 +- .../metadata/TbGetTenantAttributeNode.java | 13 +- .../metadata/TbGetTenantDetailsNode.java | 23 +- .../TbGetTenantDetailsNodeConfiguration.java | 4 +- .../transform/TbAbstractTransformNode.java | 22 +- .../transform/TbChangeOriginatorNode.java | 39 ++-- .../TbChangeOriginatorNodeConfiguration.java | 6 +- .../engine/transform/TbTransformMsgNode.java | 15 +- .../TbTransformMsgNodeConfiguration.java | 2 +- .../TbTransformNodeConfiguration.java | 23 -- .../util/EntitiesCustomerIdAsyncLoader.java | 2 - .../util/EntitiesFieldsAsyncLoader.java | 27 +-- .../transform/TbChangeOriginatorNodeTest.java | 4 +- 34 files changed, 421 insertions(+), 423 deletions(-) delete mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNodeConfiguration.java diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index a07bddc676..acade3afba 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -217,9 +217,9 @@ public class DefaultDataUpdateService implements DataUpdateService { break; case "3.4.4": log.info("Updating data from version 3.4.4 to 3.5.0 ..."); - log.info("Started enrichment rule nodes update ..."); + log.info("Starting enrichment rule nodes update ..."); updateEnrichmentRuleNodes(); - log.info("Finished enrichment rule nodes update ..."); + log.info("Finished enrichment rule nodes update!"); break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); @@ -247,12 +247,12 @@ public class DefaultDataUpdateService implements DataUpdateService { for (var ruleNode : ruleNodes) { var configuration = ruleNode.getConfiguration(); if (configuration == null) { - log.error("Unable to update [{}] rule node with ID [{}]! Node configuration is null! Skipping this node!", + log.error("Failed to update rule node: [{}] with id: [{}] Node configuration is null! Skipping this node!", ruleNodeType, ruleNode.getId()); continue; } if (!configuration.isObject()) { - log.error("Unable to update [{}] rule node with ID [{}]! Node configuration is not an object! Skipping this node!", + log.error("Failed to update rule node: [{}] with id: [{}] Node configuration is not an object! Skipping this node!", ruleNodeType, ruleNode.getId()); continue; } @@ -265,8 +265,10 @@ public class DefaultDataUpdateService implements DataUpdateService { } else if ("false".equals(fetchToMetadata)) { fetchTo = FetchTo.DATA; } else { - log.error("[fetchToMetadata] property has unexpected value: {}! Expected true or false! Skipping this node ID[{}]!", - fetchToMetadata, ruleNode.getId()); + log.error("Failed to updated rule node: [{}] with id: [{}] " + + "Reason: fetchToMetadata property has unexpected value: {} Allowed values: true or false!", + ruleNodeType, ruleNode.getId(), fetchToMetadata); + continue; } configObjectNode.remove("fetchToMetadata"); } @@ -277,8 +279,10 @@ public class DefaultDataUpdateService implements DataUpdateService { } else if ("false".equals(fetchToData)) { fetchTo = FetchTo.METADATA; } else { - log.error("[fetchToData] property has unexpected value: {}! Expected true or false! Skipping this node ID[{}]!", - fetchToData, ruleNode.getId()); + log.error("Failed to updated rule node: [{}] with id: [{}] " + + "Reason: fetchToData property has unexpected value: {} Allowed values: true or false!", + ruleNodeType, ruleNode.getId(), fetchToData); + continue; } configObjectNode.remove("fetchToData"); } @@ -289,16 +293,28 @@ public class DefaultDataUpdateService implements DataUpdateService { } else if ("false".equals(addToMetadata)) { fetchTo = FetchTo.DATA; } else { - log.error("[addToMetadata] property has unexpected value: {}! Skipping Expected true or false! Skipping this node ID[{}]!", - addToMetadata, ruleNode.getId()); + log.error("Failed to updated rule node: [{}] with id: [{}] " + + "Reason: addToMetadata property has unexpected value: {} Allowed values: true or false!", + ruleNodeType, ruleNode.getId(), addToMetadata); + continue; } configObjectNode.remove("addToMetadata"); } - configObjectNode.put("fetchTo", fetchTo.toString()); + configObjectNode.put("fetchTo", fetchTo.name()); ruleNode.setConfiguration(configObjectNode); - ruleChainIdToTenantId.computeIfAbsent(ruleNode.getRuleChainId(), - ruleChainId -> ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, ruleNode.getRuleChainId()).getTenantId()); - ruleChainService.saveRuleNode(ruleChainIdToTenantId.get(ruleNode.getRuleChainId()), ruleNode); + RuleChainId ruleChainId = ruleNode.getRuleChainId(); + TenantId tenantId = ruleChainIdToTenantId.computeIfAbsent(ruleChainId, + id -> { + RuleChain ruleChain = ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, id); + if (ruleChain == null) { + log.error("Failed to find rule chain by id: [{}], ruleNodeId: [{}]", ruleChainId, ruleNode.getId()); + return null; + } + return ruleChain.getTenantId(); + }); + if (tenantId != null) { + ruleChainService.saveRuleNode(tenantId, ruleNode); + } } }); } catch (Exception e) { diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java index 8c11ddc110..12a25b517c 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeConfiguration.java @@ -16,5 +16,7 @@ package org.thingsboard.rule.engine.api; public interface NodeConfiguration { + T defaultConfiguration(); + } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java index a0fbdaf8e1..b857307247 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNode.java @@ -24,6 +24,7 @@ import java.util.concurrent.ExecutionException; * Created by ashvayka on 19.01.18. */ public interface TbNode { + void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException; void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException; @@ -33,4 +34,5 @@ public interface TbNode { default void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) { } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java index 63ddf9be5f..14c27a7ac7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractFetchToNodeConfiguration.java @@ -19,5 +19,7 @@ import lombok.Data; @Data public abstract class TbAbstractFetchToNodeConfiguration { + private FetchTo fetchTo; + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java index 0c40ace712..5cc2da4d7a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java @@ -19,7 +19,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; @@ -31,14 +33,13 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; import java.util.Objects; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @@ -48,6 +49,7 @@ import static org.thingsboard.server.common.data.DataConstants.LATEST_TS; import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; import static org.thingsboard.server.common.data.DataConstants.SHARED_SCOPE; +@Slf4j public abstract class TbAbstractGetAttributesNode extends TbAbstractNodeWithFetchTo { private static final String VALUE = "value"; private static final String TS = "ts"; @@ -58,98 +60,81 @@ public abstract class TbAbstractGetAttributesNode safePutAttributes(ctx, msg, entityId), - t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); - } catch (Throwable th) { - ctx.tellFailure(msg, th); - } + ctx.checkTenantEntity(msg.getOriginator()); + var msgDataAsObjectNode = FetchTo.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null; + withCallback( + findEntityIdAsync(ctx, msg), + entityId -> safePutAttributes(ctx, msg, msgDataAsObjectNode, entityId), + t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } protected abstract ListenableFuture findEntityIdAsync(TbContext ctx, TbMsg msg); - private void safePutAttributes(TbContext ctx, TbMsg msg, T entityId) { - if (entityId == null || entityId.isNullUid()) { - ctx.tellFailure(msg, new NoSuchElementException("Did not find entity! Msg ID: " + msg.getId())); - return; - } - ObjectNode msgDataNode; - if (FetchTo.DATA.equals(fetchTo)) { - msgDataNode = getMsgDataAsObjectNode(msg); - } else { - msgDataNode = null; - } - var failuresMap = new ConcurrentHashMap>(); - ListenableFuture>>> allFutures = Futures.allAsList( - getLatestTelemetry(ctx, entityId, TbNodeUtils.processPatterns(config.getLatestTsKeyNames(), msg), failuresMap), - getAttrAsync(ctx, entityId, CLIENT_SCOPE, TbNodeUtils.processPatterns(config.getClientAttributeNames(), msg), failuresMap), - getAttrAsync(ctx, entityId, SHARED_SCOPE, TbNodeUtils.processPatterns(config.getSharedAttributeNames(), msg), failuresMap), - getAttrAsync(ctx, entityId, SERVER_SCOPE, TbNodeUtils.processPatterns(config.getServerAttributeNames(), msg), failuresMap) + private void safePutAttributes(TbContext ctx, TbMsg msg, ObjectNode msgDataNode, T entityId) { + Set>> failuresPairSet = ConcurrentHashMap.newKeySet(); + var getKvEntryPairFutures = Futures.allAsList( + getLatestTelemetry(ctx, entityId, TbNodeUtils.processPatterns(config.getLatestTsKeyNames(), msg), failuresPairSet), + getAttrAsync(ctx, entityId, CLIENT_SCOPE, TbNodeUtils.processPatterns(config.getClientAttributeNames(), msg), failuresPairSet), + getAttrAsync(ctx, entityId, SHARED_SCOPE, TbNodeUtils.processPatterns(config.getSharedAttributeNames(), msg), failuresPairSet), + getAttrAsync(ctx, entityId, SERVER_SCOPE, TbNodeUtils.processPatterns(config.getServerAttributeNames(), msg), failuresPairSet) ); - withCallback(allFutures, futuresList -> { + withCallback(getKvEntryPairFutures, futuresList -> { var msgMetaData = msg.getMetaData().copy(); - futuresList.stream().filter(Objects::nonNull).forEach(kvEntriesMap -> { - kvEntriesMap.forEach((keyScope, kvEntryList) -> { - var prefix = getPrefix(keyScope); - kvEntryList.forEach(kvEntry -> { - var key = prefix + kvEntry.getKey(); - if (FetchTo.DATA.equals(fetchTo)) { - JacksonUtil.addKvEntry(msgDataNode, kvEntry, key); - } else if (FetchTo.METADATA.equals(fetchTo)) { - msgMetaData.putValue(key, kvEntry.getValueAsString()); - } - }); + futuresList.stream().filter(Objects::nonNull).forEach(kvEntriesPair -> { + var keyScope = kvEntriesPair.getFirst(); + var kvEntryList = kvEntriesPair.getSecond(); + var prefix = getPrefix(keyScope); + kvEntryList.forEach(kvEntry -> { + String targetKey = prefix + kvEntry.getKey(); + enrichMessage(msgDataNode, msgMetaData, kvEntry, targetKey); }); }); - - TbMsg outMsg = null; - if (FetchTo.DATA.equals(fetchTo)) { - outMsg = TbMsg.transformMsgData(msg, JacksonUtil.toString(msgDataNode)); - } else if (FetchTo.METADATA.equals(fetchTo)) { - outMsg = TbMsg.transformMsg(msg, msgMetaData); - } - - if (failuresMap.isEmpty()) { + TbMsg outMsg = transformMessage(msg, msgDataNode, msgMetaData); + if (failuresPairSet.isEmpty()) { ctx.tellSuccess(outMsg); } else { - ctx.tellFailure(outMsg, reportFailures(failuresMap)); + ctx.tellFailure(outMsg, reportFailures(failuresPairSet)); } }, t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } - private ListenableFuture>> getAttrAsync(TbContext ctx, EntityId entityId, String scope, List keys, ConcurrentHashMap> failuresMap) { + private ListenableFuture>> getAttrAsync( + TbContext ctx, + EntityId entityId, + String scope, + List keys, + Set>> failuresPairSet + ) { if (CollectionUtils.isEmpty(keys)) { return Futures.immediateFuture(null); } var attributeKvEntryListFuture = ctx.getAttributesService().find(ctx.getTenantId(), entityId, scope, keys); return Futures.transform(attributeKvEntryListFuture, attributeKvEntryList -> { if (isTellFailureIfAbsent && attributeKvEntryList.size() != keys.size()) { - getNotExistingKeys(attributeKvEntryList, keys).forEach(key -> computeFailuresMap(scope, failuresMap, key)); + List nonExistentKeys = getNonExistentKeys(attributeKvEntryList, keys); + failuresPairSet.add(new TbPair<>(scope, nonExistentKeys)); } - var mapAttributeKvEntry = new HashMap>(); - mapAttributeKvEntry.put(scope, attributeKvEntryList); - return mapAttributeKvEntry; + return new TbPair<>(scope, attributeKvEntryList); }, MoreExecutors.directExecutor()); } - private ListenableFuture>> getLatestTelemetry(TbContext ctx, EntityId entityId, List keys, ConcurrentHashMap> failuresMap) { + private ListenableFuture>> getLatestTelemetry(TbContext ctx, EntityId entityId, List keys, Set>> failuresPairSet) { if (CollectionUtils.isEmpty(keys)) { return Futures.immediateFuture(null); } ListenableFuture> latestTelemetryFutures = ctx.getTimeseriesService().findLatest(ctx.getTenantId(), entityId, keys); return Futures.transform(latestTelemetryFutures, tsKvEntries -> { var listTsKvEntry = new ArrayList(); + var nonExistentKeys = new ArrayList(); tsKvEntries.forEach(tsKvEntry -> { if (tsKvEntry.getValue() == null) { if (isTellFailureIfAbsent) { - computeFailuresMap(LATEST_TS, failuresMap, tsKvEntry.getKey()); + nonExistentKeys.add(tsKvEntry.getKey()); } } else if (getLatestValueWithTs) { listTsKvEntry.add(getValueWithTs(tsKvEntry)); @@ -157,9 +142,10 @@ public abstract class TbAbstractGetAttributesNode>(); - mapTsKvEntry.put(LATEST_TS, listTsKvEntry); - return mapTsKvEntry; + if (isTellFailureIfAbsent && !nonExistentKeys.isEmpty()) { + failuresPairSet.add(new TbPair<>(LATEST_TS, nonExistentKeys)); + } + return new TbPair<>(LATEST_TS, listTsKvEntry); }, MoreExecutors.directExecutor()); } @@ -187,31 +173,19 @@ public abstract class TbAbstractGetAttributesNode getNotExistingKeys(List existingAttributesKvEntry, List allKeys) { + private List getNonExistentKeys(List existingAttributesKvEntry, List allKeys) { List existingKeys = existingAttributesKvEntry.stream().map(KvEntry::getKey).collect(Collectors.toList()); return allKeys.stream().filter(key -> !existingKeys.contains(key)).collect(Collectors.toList()); } - private void computeFailuresMap(String scope, ConcurrentHashMap> failuresMap, String key) { - List failures = failuresMap.computeIfAbsent(scope, k -> new ArrayList<>()); - failures.add(key); - } - - private RuntimeException reportFailures(ConcurrentHashMap> failuresMap) { + private RuntimeException reportFailures(Set>> failuresPairSet) { var errorMessage = new StringBuilder("The following attribute/telemetry keys is not present in the DB: ").append("\n"); - if (failuresMap.containsKey(CLIENT_SCOPE)) { - errorMessage.append("\t").append("[" + CLIENT_SCOPE + "]:").append(failuresMap.get(CLIENT_SCOPE).toString()).append("\n"); - } - if (failuresMap.containsKey(SERVER_SCOPE)) { - errorMessage.append("\t").append("[" + SERVER_SCOPE + "]:").append(failuresMap.get(SERVER_SCOPE).toString()).append("\n"); - } - if (failuresMap.containsKey(SHARED_SCOPE)) { - errorMessage.append("\t").append("[" + SHARED_SCOPE + "]:").append(failuresMap.get(SHARED_SCOPE).toString()).append("\n"); - } - if (failuresMap.containsKey(LATEST_TS)) { - errorMessage.append("\t").append("[" + LATEST_TS + "]:").append(failuresMap.get(LATEST_TS).toString()).append("\n"); - } - failuresMap.clear(); + failuresPairSet.forEach(failurePair -> { + String scope = failurePair.getFirst(); + List nonExistentKeys = failurePair.getSecond(); + errorMessage.append("\t").append("[").append(scope).append("]:").append(nonExistentKeys.toString()).append("\n"); + }); + failuresPairSet.clear(); return new RuntimeException(errorMessage.toString()); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java index 874cee2e75..0a650bf3d9 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityAttrNode.java @@ -20,8 +20,8 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.kv.KvEntry; @@ -30,7 +30,6 @@ import org.thingsboard.server.common.msg.TbMsg; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.stream.Collectors; import static org.thingsboard.common.util.DonAsynchron.withCallback; @@ -38,35 +37,31 @@ import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; @Slf4j public abstract class TbAbstractGetEntityAttrNode extends TbAbstractNodeWithFetchTo { + @Override public void onMsg(TbContext ctx, TbMsg msg) { - ObjectNode msgDataAsJsonNode; - if (FetchTo.DATA.equals(fetchTo)) { - msgDataAsJsonNode = getMsgDataAsObjectNode(msg); - } else { - msgDataAsJsonNode = null; - } ctx.checkTenantEntity(msg.getOriginator()); + var msgDataAsObjectNode = FetchTo.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null; withCallback(findEntityAsync(ctx, msg.getOriginator()), - entityId -> safeGetAttributes(ctx, msg, entityId, msgDataAsJsonNode), + entityId -> safeGetAttributes(ctx, msg, entityId, msgDataAsObjectNode), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } protected abstract ListenableFuture findEntityAsync(TbContext ctx, EntityId originator); - private void safeGetAttributes(TbContext ctx, TbMsg msg, T entityId, ObjectNode msgDataAsJsonNode) { - if (entityId == null || entityId.isNullUid()) { - ctx.tellFailure(msg, new NoSuchElementException("Did not find entity! Msg ID: " + msg.getId())); - return; + protected void checkIfMappingIsNotEmptyOrThrow(TbGetEntityAttrNodeConfiguration config) throws TbNodeException { + if (config.getAttrMapping().isEmpty()) { + throw new TbNodeException("At least one attribute mapping should be specified!"); } + } - Map mappingsMap = new HashMap<>(); + private void safeGetAttributes(TbContext ctx, TbMsg msg, T entityId, ObjectNode msgDataAsJsonNode) { + var mappingsMap = new HashMap(); config.getAttrMapping().forEach((key, value) -> { String patternProcessedSourceKey = TbNodeUtils.processPattern(key, msg); String patternProcessedTargetKey = TbNodeUtils.processPattern(value, msg); mappingsMap.put(patternProcessedSourceKey, patternProcessedTargetKey); }); - var sourceKeys = List.copyOf(mappingsMap.keySet()); withCallback(config.isTelemetry() ? getLatestTelemetryAsync(ctx, entityId, sourceKeys) : getAttributesAsync(ctx, entityId, sourceKeys), data -> putDataAndTell(ctx, msg, data, mappingsMap, msgDataAsJsonNode), @@ -91,20 +86,13 @@ public abstract class TbAbstractGetEntityAttrNode extends Tb MoreExecutors.directExecutor()); } - private void putDataAndTell(TbContext ctx, TbMsg msg, List data, Map map, ObjectNode msgDataAsJsonNode) { + private void putDataAndTell(TbContext ctx, TbMsg msg, List data, Map map, ObjectNode msgData) { + var msgMetaData = msg.getMetaData().copy(); for (KvEntry entry : data) { String targetKey = map.get(entry.getKey()); - String value = entry.getValueAsString(); - if (FetchTo.DATA.equals(fetchTo)) { - msgDataAsJsonNode.put(targetKey, value); - } else if (FetchTo.METADATA.equals(fetchTo)) { - msg.getMetaData().putValue(targetKey, value); - } - } - if (FetchTo.DATA.equals(fetchTo)) { - ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(msgDataAsJsonNode))); - } else if (FetchTo.METADATA.equals(fetchTo)) { - ctx.tellSuccess(msg); + enrichMessage(msgData, msgMetaData, entry, targetKey); } + ctx.tellSuccess(transformMessage(msg, msgData, msgMetaData)); } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java index 4644db2ff7..0016234a91 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java @@ -15,159 +15,131 @@ */ package org.thingsboard.rule.engine.metadata; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.reflect.TypeToken; -import lombok.AllArgsConstructor; -import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.util.EntityDetails; +import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.ContactBased; +import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; -import java.lang.reflect.Type; -import java.util.Map; - import static org.thingsboard.common.util.DonAsynchron.withCallback; @Slf4j -public abstract class TbAbstractGetEntityDetailsNode extends TbAbstractNodeWithFetchTo { - private static final Gson gson = new Gson(); - private static final Type TYPE = new TypeToken>() { - }.getType(); +public abstract class TbAbstractGetEntityDetailsNode extends TbAbstractNodeWithFetchTo { @Override public void onMsg(TbContext ctx, TbMsg msg) { - withCallback(getDetails(ctx, msg), + ctx.checkTenantEntity(msg.getOriginator()); + var msgDataAsObjectNode = FetchTo.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null; + withCallback(getDetails(ctx, msg, msgDataAsObjectNode), ctx::tellSuccess, t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } - protected abstract ListenableFuture getDetails(TbContext ctx, TbMsg msg); + protected abstract String getPrefix(); - protected abstract ListenableFuture getContactBasedListenableFuture(TbContext ctx, TbMsg msg); + protected abstract ListenableFuture> getContactBasedFuture(TbContext ctx, TbMsg msg); - protected MessageData getDataAsJson(TbMsg msg) { - if (fetchTo == FetchTo.METADATA) { - return new MessageData(gson.toJsonTree(msg.getMetaData().getData(), TYPE), DataSource.METADATA); - } else if (fetchTo == FetchTo.DATA) { - var msgDataJsonElement = JsonParser.parseString(msg.getData()); - if (!msgDataJsonElement.isJsonObject()) { - throw new IllegalArgumentException("Message body is not an object!"); - } - return new MessageData(msgDataJsonElement, DataSource.DATA); - } else { - throw new IllegalArgumentException("Unsupported fetchTo value!"); + protected void checkIfDetailsListIsNotEmptyOrThrow(C configuration) throws TbNodeException { + if (configuration.getDetailsList().isEmpty()) { + throw new TbNodeException("No entity details selected!"); } } - protected ListenableFuture getTbMsgListenableFuture(TbContext ctx, TbMsg msg, MessageData messageData, String prefix) { - if (config.getDetailsList().isEmpty()) { - return Futures.immediateFuture(msg); - } else { - ListenableFuture contactBasedListenableFuture = getContactBasedListenableFuture(ctx, msg); - ListenableFuture resultObject = addContactProperties(messageData.getData(), contactBasedListenableFuture, prefix); - return transformMsg(ctx, msg, resultObject, messageData); - } - } - - private ListenableFuture transformMsg(TbContext ctx, TbMsg msg, ListenableFuture propertiesFuture, MessageData messageData) { - return Futures.transformAsync(propertiesFuture, jsonElement -> { - if (jsonElement == null) { - return Futures.immediateFuture(null); - } else if (messageData.getDataSource().equals(DataSource.METADATA)) { - Map metadataMap = gson.fromJson(jsonElement.toString(), TYPE); - return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), new TbMsgMetaData(metadataMap), msg.getData())); - } else { - return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), gson.toJson(jsonElement))); - } - }, MoreExecutors.directExecutor()); - } - - private ListenableFuture addContactProperties(JsonElement data, ListenableFuture entityFuture, String prefix) { - return Futures.transformAsync(entityFuture, contactBased -> { + private ListenableFuture getDetails(TbContext ctx, TbMsg msg, ObjectNode messageData) { + ListenableFuture> contactBasedFuture = getContactBasedFuture(ctx, msg); + return Futures.transformAsync(contactBasedFuture, contactBased -> { if (contactBased == null) { - return Futures.immediateFuture(null); - } else { - JsonElement jsonElement = null; - for (EntityDetails entityDetails : this.config.getDetailsList()) { - jsonElement = setProperties(contactBased, data, entityDetails, prefix); - } - return Futures.immediateFuture(jsonElement); + return Futures.immediateFuture(msg); } + var msgMetaData = msg.getMetaData().copy(); + setProperties(contactBased, messageData, msgMetaData); + return Futures.immediateFuture(transformMessage(msg, messageData, msgMetaData)); }, MoreExecutors.directExecutor()); } - private JsonElement setProperties(ContactBased entity, JsonElement data, EntityDetails entityDetails, String prefix) { - JsonObject dataAsObject = data.getAsJsonObject(); - switch (entityDetails) { - case ID: - dataAsObject.addProperty(prefix + "id", entity.getId().toString()); - break; - case TITLE: - dataAsObject.addProperty(prefix + "title", entity.getName()); - break; - case ADDRESS: - if (entity.getAddress() != null) { - dataAsObject.addProperty(prefix + "address", entity.getAddress()); - } - break; - case ADDRESS2: - if (entity.getAddress2() != null) { - dataAsObject.addProperty(prefix + "address2", entity.getAddress2()); - } - break; - case CITY: - if (entity.getCity() != null) dataAsObject.addProperty(prefix + "city", entity.getCity()); - break; - case COUNTRY: - if (entity.getCountry() != null) - dataAsObject.addProperty(prefix + "country", entity.getCountry()); - break; - case STATE: - if (entity.getState() != null) { - dataAsObject.addProperty(prefix + "state", entity.getState()); - } - break; - case EMAIL: - if (entity.getEmail() != null) { - dataAsObject.addProperty(prefix + "email", entity.getEmail()); - } - break; - case PHONE: - if (entity.getPhone() != null) { - dataAsObject.addProperty(prefix + "phone", entity.getPhone()); - } - break; - case ZIP: - if (entity.getZip() != null) { - dataAsObject.addProperty(prefix + "zip", entity.getZip()); - } - break; - case ADDITIONAL_INFO: - if (entity.getAdditionalInfo().hasNonNull("description")) { - dataAsObject.addProperty(prefix + "additionalInfo", entity.getAdditionalInfo().get("description").asText()); - } - break; + private void setProperties(ContactBased contactBased, ObjectNode messageData, TbMsgMetaData msgMetaData) { + String prefix = getPrefix(); + String property; + String value; + for (var entityDetails : config.getDetailsList()) { + switch (entityDetails) { + case ID: + property = prefix + "id"; + value = contactBased.getId().getId().toString(); + setDetail(property, value, messageData, msgMetaData); + break; + case TITLE: + property = prefix + "title"; + value = contactBased.getName(); + setDetail(property, value, messageData, msgMetaData); + break; + case ADDRESS: + property = prefix + "address"; + value = contactBased.getAddress(); + setDetail(property, value, messageData, msgMetaData); + break; + case ADDRESS2: + property = prefix + "address2"; + value = contactBased.getAddress2(); + setDetail(property, value, messageData, msgMetaData); + break; + case CITY: + property = prefix + "city"; + value = contactBased.getCity(); + setDetail(property, value, messageData, msgMetaData); + break; + case COUNTRY: + property = prefix + "country"; + value = contactBased.getCountry(); + setDetail(property, value, messageData, msgMetaData); + break; + case STATE: + property = prefix + "state"; + value = contactBased.getState(); + setDetail(property, value, messageData, msgMetaData); + break; + case EMAIL: + property = prefix + "email"; + value = contactBased.getEmail(); + setDetail(property, value, messageData, msgMetaData); + break; + case PHONE: + property = prefix + "phone"; + value = contactBased.getPhone(); + setDetail(property, value, messageData, msgMetaData); + break; + case ZIP: + property = prefix + "zip"; + value = contactBased.getZip(); + setDetail(property, value, messageData, msgMetaData); + break; + case ADDITIONAL_INFO: + if (contactBased.getAdditionalInfo().hasNonNull("description")) { + property = prefix + "additionalInfo"; + value = contactBased.getAdditionalInfo().get("description").asText(); + setDetail(property, value, messageData, msgMetaData); + } + break; + } } - return dataAsObject; } - @Data - @AllArgsConstructor - private static class MessageData { - private JsonElement data; - private DataSource dataSource; + private void setDetail(String property, String value, ObjectNode messageData, TbMsgMetaData msgMetaData) { + if (value == null) { + return; + } + if (FetchTo.METADATA.equals(fetchTo)) { + msgMetaData.putValue(property, value); + } + if (FetchTo.DATA.equals(fetchTo)) { + messageData.put(property, value); + } } - private enum DataSource { - DATA, METADATA - } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java index 1da798ae82..4bf150ebff 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNodeConfiguration.java @@ -24,5 +24,7 @@ import java.util.List; @Data @EqualsAndHashCode(callSuper = true) public abstract class TbAbstractGetEntityDetailsNodeConfiguration extends TbAbstractFetchToNodeConfiguration { + private List detailsList; + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java index 3cf6300b77..a9c204215c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java @@ -17,14 +17,24 @@ package org.thingsboard.rule.engine.metadata; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.AsyncFunction; +import com.google.common.util.concurrent.Futures; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import java.util.NoSuchElementException; + +@Slf4j public abstract class TbAbstractNodeWithFetchTo implements TbNode { + protected C config; protected FetchTo fetchTo; @@ -32,7 +42,7 @@ public abstract class TbAbstractNodeWithFetchTo AsyncFunction checkIfEntityIsPresentOrThrow(String message) { + return id -> { + if (id == null || id.isNullUid()) { + return Futures.immediateFailedFuture(new NoSuchElementException(message)); + } + return Futures.immediateFuture(id); + }; + } + protected ObjectNode getMsgDataAsObjectNode(TbMsg msg) { JsonNode msgDataNode = JacksonUtil.toJsonNode(msg.getData()); - if (!msgDataNode.isObject()) { + if (msgDataNode == null || !msgDataNode.isObject()) { throw new IllegalArgumentException("Message body is not an object!"); } return (ObjectNode) msgDataNode; } + + protected void enrichMessage(ObjectNode msgData, TbMsgMetaData metaData, KvEntry kvEntry, String targetKey) { + if (FetchTo.DATA.equals(fetchTo)) { + JacksonUtil.addKvEntry(msgData, kvEntry, targetKey); + } else if (FetchTo.METADATA.equals(fetchTo)) { + metaData.putValue(targetKey, kvEntry.getValueAsString()); + } + } + + protected TbMsg transformMessage(TbMsg msg, ObjectNode msgDataNode, TbMsgMetaData msgMetaData) { + switch (fetchTo) { + case DATA: + return TbMsg.transformMsgData(msg, JacksonUtil.toString(msgDataNode)); + case METADATA: + return TbMsg.transformMsg(msg, msgMetaData); + default: + log.debug("Unexpected FetchTo value: {}. Allowed values: {}", fetchTo, FetchTo.values()); + return msg; + } + } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java index 0a8ca6b255..f1dba47a90 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.metadata; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleNode; @@ -43,6 +44,7 @@ import java.util.concurrent.ExecutionException; uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeFetchDeviceCredentialsConfig") public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo { + private static final String CREDENTIALS = "credentials"; private static final String CREDENTIALS_TYPE = "credentialsType"; @@ -55,6 +57,7 @@ public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo findEntityIdAsync(TbContext ctx, TbMsg msg) { - ctx.checkTenantEntity(msg.getOriginator()); return Futures.immediateFuture(msg.getOriginator()); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java index 89c4eb8086..2450796b59 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeConfiguration.java @@ -28,6 +28,7 @@ import java.util.List; @Data @EqualsAndHashCode(callSuper = true) public class TbGetAttributesNodeConfiguration extends TbAbstractFetchToNodeConfiguration implements NodeConfiguration { + private List clientAttributeNames; private List sharedAttributeNames; private List serverAttributeNames; @@ -49,4 +50,5 @@ public class TbGetAttributesNodeConfiguration extends TbAbstractFetchToNodeConfi configuration.setFetchTo(FetchTo.METADATA); return configuration; } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index d00de4dd0e..5f5f73c01c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.metadata; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; @@ -30,22 +31,30 @@ import org.thingsboard.server.common.data.plugin.ComponentType; type = ComponentType.ENRICHMENT, name = "customer attributes", configClazz = TbGetEntityAttrNodeConfiguration.class, - nodeDescription = "Add Originators Customer Attributes or Latest Telemetry into Message Metadata/Data", - nodeDetails = "Enrich the Message Metadata/Data with the corresponding customer's latest attributes or telemetry value. " + + nodeDescription = "Add Originators Customer Attributes or Latest Telemetry into Message or Metadata", + nodeDetails = "Enrich the Message or Metadata with the corresponding customer's latest attributes or telemetry value. " + "The customer is selected based on the originator of the message: device, asset, etc. " + "
" + "Useful when you store some parameters on the customer level and would like to use them for message processing.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeCustomerAttributesConfig") public class TbGetCustomerAttributeNode extends TbAbstractGetEntityAttrNode { + + private static final String CUSTOMER_NOT_FOUND_MESSAGE = "Failed to find customer for entity with id %s and type %s"; + @Override - protected ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { - ctx.checkTenantEntity(originator); - return EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctx, originator); + protected TbGetEntityAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { + var config = TbNodeUtils.convert(configuration, TbGetEntityAttrNodeConfiguration.class); + checkIfMappingIsNotEmptyOrThrow(config); + return config; } @Override - protected TbGetEntityAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { - return TbNodeUtils.convert(configuration, TbGetEntityAttrNodeConfiguration.class); + protected ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { + return Futures.transformAsync(EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctx, originator), + checkIfEntityIsPresentOrThrow(String.format(CUSTOMER_NOT_FOUND_MESSAGE, originator.getId(), originator.getEntityType().getNormalName())), + ctx.getDbCallbackExecutor() + ); } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java index 1d7c53e002..810a6c2cd3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; @@ -37,6 +38,8 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; +import java.util.NoSuchElementException; + @Slf4j @RuleNode(type = ComponentType.ENRICHMENT, name = "customer details", @@ -47,28 +50,24 @@ import org.thingsboard.server.common.msg.TbMsg; "If the originator of the message is not assigned to Customer, or originator type is not supported - Message will be forwarded to Failure chain, otherwise, Success chain will be used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") -public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode { +public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode { + private static final String CUSTOMER_PREFIX = "customer_"; @Override protected TbGetCustomerDetailsNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { - return TbNodeUtils.convert(configuration, TbGetCustomerDetailsNodeConfiguration.class); + var config = TbNodeUtils.convert(configuration, TbGetCustomerDetailsNodeConfiguration.class); + checkIfDetailsListIsNotEmptyOrThrow(config); + return config; } @Override - protected ListenableFuture getDetails(TbContext ctx, TbMsg msg) { - ctx.checkTenantEntity(msg.getOriginator()); - return getTbMsgListenableFuture(ctx, msg, getDataAsJson(msg), CUSTOMER_PREFIX); + protected String getPrefix() { + return CUSTOMER_PREFIX; } @Override - protected ListenableFuture getContactBasedListenableFuture(TbContext ctx, TbMsg msg) { - return Futures.transformAsync(getCustomer(ctx, msg), customer -> - customer == null ? Futures.immediateFuture(null) : Futures.immediateFuture(customer), - MoreExecutors.directExecutor()); - } - - private ListenableFuture getCustomer(TbContext ctx, TbMsg msg) { + protected ListenableFuture> getContactBasedFuture(TbContext ctx, TbMsg msg) { switch (msg.getOriginator().getEntityType()) { case DEVICE: return Futures.transformAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), new DeviceId(msg.getOriginator().getId())), @@ -86,7 +85,7 @@ public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode getCustomerFuture(ctx, edge, msg.getOriginator()), MoreExecutors.directExecutor()); default: - throw new RuntimeException("Entity with entityType '" + msg.getOriginator().getEntityType() + "' is not supported."); + return Futures.immediateFailedFuture(new NoSuchElementException("Entity with entityType '" + msg.getOriginator().getEntityType() + "' is not supported.")); } } @@ -96,7 +95,7 @@ public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode { + @Override public TbGetCustomerDetailsNodeConfiguration defaultConfiguration() { var configuration = new TbGetCustomerDetailsNodeConfiguration(); configuration.setDetailsList(Collections.emptyList()); - configuration.setFetchTo(FetchTo.METADATA); + configuration.setFetchTo(FetchTo.DATA); return configuration; } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java index 96230ae28f..fdbb412e6b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.metadata; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; @@ -39,6 +40,9 @@ import org.thingsboard.server.common.msg.TbMsg; uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeDeviceAttributesConfig") public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode { + + private static final String RELATED_DEVICE_NOT_FOUND_MESSAGE = "Failed to find related device to message originator using relation query specified in the configuration!"; + @Override protected TbGetDeviceAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { return TbNodeUtils.convert(configuration, TbGetDeviceAttrNodeConfiguration.class); @@ -46,7 +50,10 @@ public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode findEntityIdAsync(TbContext ctx, TbMsg msg) { - ctx.checkTenantEntity(msg.getOriginator()); - return EntitiesRelatedDeviceIdAsyncLoader.findDeviceAsync(ctx, msg.getOriginator(), config.getDeviceRelationsQuery()); + return Futures.transformAsync( + EntitiesRelatedDeviceIdAsyncLoader.findDeviceAsync(ctx, msg.getOriginator(), config.getDeviceRelationsQuery()), + checkIfEntityIsPresentOrThrow(RELATED_DEVICE_NOT_FOUND_MESSAGE), + ctx.getDbCallbackExecutor()); } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java index 108a1f5017..60a2c9cdf7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeConfiguration.java @@ -26,6 +26,7 @@ import java.util.Collections; @Data @EqualsAndHashCode(callSuper = true) public class TbGetDeviceAttrNodeConfiguration extends TbGetAttributesNodeConfiguration { + private DeviceRelationsQuery deviceRelationsQuery; @Override @@ -49,4 +50,5 @@ public class TbGetDeviceAttrNodeConfiguration extends TbGetAttributesNodeConfigu return configuration; } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java index fccbdfb39f..18134a5040 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetEntityAttrNodeConfiguration.java @@ -25,17 +25,19 @@ import java.util.Map; @Data @EqualsAndHashCode(callSuper = true) public class TbGetEntityAttrNodeConfiguration extends TbAbstractFetchToNodeConfiguration implements NodeConfiguration { + private Map attrMapping; - private boolean isTelemetry = false; + private boolean isTelemetry; @Override public TbGetEntityAttrNodeConfiguration defaultConfiguration() { var configuration = new TbGetEntityAttrNodeConfiguration(); var attrMapping = new HashMap(); - attrMapping.putIfAbsent("serialNumber", "sn"); + attrMapping.putIfAbsent("alarmThreshold", "threshold"); configuration.setAttrMapping(attrMapping); configuration.setTelemetry(false); configuration.setFetchTo(FetchTo.METADATA); return configuration; } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java index 3c0498f6ba..e5d428100b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsConfiguration.java @@ -25,6 +25,7 @@ import java.util.Map; @Data @EqualsAndHashCode(callSuper = true) public class TbGetOriginatorFieldsConfiguration extends TbAbstractFetchToNodeConfiguration implements NodeConfiguration { + private Map fieldsMapping; private boolean ignoreNullStrings; @@ -39,4 +40,5 @@ public class TbGetOriginatorFieldsConfiguration extends TbAbstractFetchToNodeCon configuration.setFetchTo(FetchTo.METADATA); return configuration; } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java index 7dee45aae0..f520425cbc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java @@ -15,11 +15,9 @@ */ package org.thingsboard.rule.engine.metadata; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; @@ -29,8 +27,8 @@ import org.thingsboard.rule.engine.util.EntitiesFieldsAsyncLoader; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; -import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -48,60 +46,53 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeOriginatorFieldsConfig") public class TbGetOriginatorFieldsNode extends TbAbstractNodeWithFetchTo { + @Override protected TbGetOriginatorFieldsConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { - return TbNodeUtils.convert(configuration, TbGetOriginatorFieldsConfiguration.class); + var getOriginatorFieldsConfiguration = TbNodeUtils.convert(configuration, TbGetOriginatorFieldsConfiguration.class); + if (config.getFieldsMapping().isEmpty()) { + throw new TbNodeException("At least one field mapping should be specified!"); + } + return getOriginatorFieldsConfiguration; } @Override public void onMsg(TbContext ctx, TbMsg msg) { - ObjectNode msgDataAsJsonNode; - if (FetchTo.DATA.equals(fetchTo)) { - msgDataAsJsonNode = getMsgDataAsObjectNode(msg); - } else { - msgDataAsJsonNode = null; - } ctx.checkTenantEntity(msg.getOriginator()); + var msgDataAsObjectNode = FetchTo.DATA.equals(fetchTo) ? getMsgDataAsObjectNode(msg) : null; withCallback(collectMappedEntityFieldsAsync(ctx, msg.getOriginator()), targetKeysToSourceValuesMap -> { + TbMsgMetaData msgMetaData = msg.getMetaData().copy(); for (var entry : targetKeysToSourceValuesMap.entrySet()) { var targetKeyName = entry.getKey(); var sourceFieldValue = entry.getValue(); if (FetchTo.DATA.equals(fetchTo)) { - msgDataAsJsonNode.put(targetKeyName, sourceFieldValue); + msgDataAsObjectNode.put(targetKeyName, sourceFieldValue); } else if (FetchTo.METADATA.equals(fetchTo)) { - msg.getMetaData().putValue(targetKeyName, sourceFieldValue); + msgMetaData.putValue(targetKeyName, sourceFieldValue); } } - - if (FetchTo.DATA.equals(fetchTo)) { - ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(msgDataAsJsonNode))); - } else if (FetchTo.METADATA.equals(fetchTo)) { - ctx.tellSuccess(msg); - } + TbMsg outMsg = transformMessage(msg, msgDataAsObjectNode, msgMetaData); + ctx.tellSuccess(outMsg); }, t -> ctx.tellFailure(msg, t), MoreExecutors.directExecutor()); } private ListenableFuture> collectMappedEntityFieldsAsync(TbContext ctx, EntityId entityId) { - if (config.getFieldsMapping().isEmpty()) { - return Futures.immediateFuture(Collections.emptyMap()); - } else { - return Futures.transform(EntitiesFieldsAsyncLoader.findAsync(ctx, entityId), - fieldsData -> { - var targetKeysToSourceValuesMap = new HashMap(); - for (var mappingEntry : config.getFieldsMapping().entrySet()) { - var sourceFieldName = mappingEntry.getKey(); - var targetKeyName = mappingEntry.getValue(); - var sourceFieldValue = fieldsData.getFieldValue(sourceFieldName, config.isIgnoreNullStrings()); - if (sourceFieldValue != null) { - targetKeysToSourceValuesMap.put(targetKeyName, sourceFieldValue); - } + return Futures.transform(EntitiesFieldsAsyncLoader.findAsync(ctx, entityId), + fieldsData -> { + var targetKeysToSourceValuesMap = new HashMap(); + for (var mappingEntry : config.getFieldsMapping().entrySet()) { + var sourceFieldName = mappingEntry.getKey(); + var targetKeyName = mappingEntry.getValue(); + var sourceFieldValue = fieldsData.getFieldValue(sourceFieldName, config.isIgnoreNullStrings()); + if (sourceFieldValue != null) { + targetKeysToSourceValuesMap.put(targetKeyName, sourceFieldValue); } - return targetKeysToSourceValuesMap; - }, ctx.getDbCallbackExecutor() - ); - } + } + return targetKeysToSourceValuesMap; + }, ctx.getDbCallbackExecutor() + ); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java index 9387858811..26491509b8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttrNodeConfiguration.java @@ -28,6 +28,7 @@ import java.util.HashMap; @Data @EqualsAndHashCode(callSuper = true) public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfiguration { + private RelationsQuery relationsQuery; @Override @@ -37,14 +38,16 @@ public class TbGetRelatedAttrNodeConfiguration extends TbGetEntityAttrNodeConfig attrMapping.putIfAbsent("serialNumber", "sn"); configuration.setAttrMapping(attrMapping); configuration.setTelemetry(false); + configuration.setFetchTo(FetchTo.METADATA); var relationsQuery = new RelationsQuery(); + var relationEntityTypeFilter = new RelationEntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.emptyList()); relationsQuery.setDirection(EntitySearchDirection.FROM); relationsQuery.setMaxLevel(1); - var relationEntityTypeFilter = new RelationEntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.emptyList()); relationsQuery.setFilters(Collections.singletonList(relationEntityTypeFilter)); configuration.setRelationsQuery(relationsQuery); return configuration; } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index d722d1c62b..b535d050f4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.metadata; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; @@ -39,15 +40,23 @@ import org.thingsboard.server.common.data.plugin.ComponentType; uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeRelatedAttributesConfig") public class TbGetRelatedAttributeNode extends TbAbstractGetEntityAttrNode { + + private static final String RELATED_ENTITY_NOT_FOUND_MESSAGE = "Failed to find related entity to message originator using relation query specified in the configuration!"; + @Override public TbGetRelatedAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { - return TbNodeUtils.convert(configuration, TbGetRelatedAttrNodeConfiguration.class); + var config = TbNodeUtils.convert(configuration, TbGetRelatedAttrNodeConfiguration.class); + checkIfMappingIsNotEmptyOrThrow(config); + return config; } @Override public ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { - ctx.checkTenantEntity(originator); var relatedAttrConfig = (TbGetRelatedAttrNodeConfiguration) config; - return EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, originator, relatedAttrConfig.getRelationsQuery()); + return Futures.transformAsync( + EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctx, originator, relatedAttrConfig.getRelationsQuery()), + checkIfEntityIsPresentOrThrow(RELATED_ENTITY_NOT_FOUND_MESSAGE), + ctx.getDbCallbackExecutor()); } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index dcc96e82c1..d729c6159f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -40,14 +40,17 @@ import org.thingsboard.server.common.data.plugin.ComponentType; uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeTenantAttributesConfig") public class TbGetTenantAttributeNode extends TbAbstractGetEntityAttrNode { + @Override - public ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { - ctx.checkTenantEntity(originator); - return Futures.immediateFuture(ctx.getTenantId()); + public TbGetEntityAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { + var config = TbNodeUtils.convert(configuration, TbGetEntityAttrNodeConfiguration.class); + checkIfMappingIsNotEmptyOrThrow(config); + return config; } @Override - public TbGetEntityAttrNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { - return TbNodeUtils.convert(configuration, TbGetEntityAttrNodeConfiguration.class); + public ListenableFuture findEntityAsync(TbContext ctx, EntityId originator) { + return Futures.immediateFuture(ctx.getTenantId()); } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index c89259d9ad..645106ab10 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -15,9 +15,7 @@ */ package org.thingsboard.rule.engine.metadata; -import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; @@ -25,6 +23,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.ContactBased; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -38,25 +37,25 @@ import org.thingsboard.server.common.msg.TbMsg; "If the originator of the message is not assigned to Tenant, or originator type is not supported - Message will be forwarded to Failure chain, otherwise, Success chain will be used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") -public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode { +public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode { + private static final String TENANT_PREFIX = "tenant_"; @Override protected TbGetTenantDetailsNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { - return TbNodeUtils.convert(configuration, TbGetTenantDetailsNodeConfiguration.class); + var config = TbNodeUtils.convert(configuration, TbGetTenantDetailsNodeConfiguration.class); + checkIfDetailsListIsNotEmptyOrThrow(config); + return config; } @Override - protected ListenableFuture getDetails(TbContext ctx, TbMsg msg) { - ctx.checkTenantEntity(msg.getOriginator()); - return getTbMsgListenableFuture(ctx, msg, getDataAsJson(msg), TENANT_PREFIX); + protected String getPrefix() { + return TENANT_PREFIX; } @Override - protected ListenableFuture getContactBasedListenableFuture(TbContext ctx, TbMsg msg) { - ctx.checkTenantEntity(msg.getOriginator()); - return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), ctx.getTenantId()), tenant -> - tenant == null ? Futures.immediateFuture(null) : Futures.immediateFuture(tenant), - MoreExecutors.directExecutor()); + protected ListenableFuture> getContactBasedFuture(TbContext ctx, TbMsg msg) { + return ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), ctx.getTenantId()); } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeConfiguration.java index e3608abbbd..c8d74c6170 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeConfiguration.java @@ -24,11 +24,13 @@ import java.util.Collections; @Data @EqualsAndHashCode(callSuper = true) public class TbGetTenantDetailsNodeConfiguration extends TbAbstractGetEntityDetailsNodeConfiguration implements NodeConfiguration { + @Override public TbGetTenantDetailsNodeConfiguration defaultConfiguration() { TbGetTenantDetailsNodeConfiguration configuration = new TbGetTenantDetailsNodeConfiguration(); configuration.setDetailsList(Collections.emptyList()); - configuration.setFetchTo(FetchTo.METADATA); + configuration.setFetchTo(FetchTo.DATA); return configuration; } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java index bc693d9b97..b2a1599e8c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java @@ -36,12 +36,13 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; * Created by ashvayka on 19.01.18. */ @Slf4j -public abstract class TbAbstractTransformNode implements TbNode { - private TbTransformNodeConfiguration config; +public abstract class TbAbstractTransformNode implements TbNode { + + protected C config; @Override - public void init(TbContext context, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, TbTransformNodeConfiguration.class); + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + config = loadNodeConfiguration(ctx, configuration); } @Override @@ -52,18 +53,12 @@ public abstract class TbAbstractTransformNode implements TbNode { MoreExecutors.directExecutor()); } + protected abstract C loadNodeConfiguration(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException; + protected void transformFailure(TbContext ctx, TbMsg msg, Throwable t) { ctx.tellFailure(msg, t); } - protected void transformSuccess(TbContext ctx, TbMsg msg, TbMsg m) { - if (m != null) { - ctx.tellSuccess(m); - } else { - ctx.tellFailure(msg, new RuntimeException("Message is null!")); - } - } - protected void transformSuccess(TbContext ctx, TbMsg msg, List msgs) { if (msgs != null && !msgs.isEmpty()) { if (msgs.size() == 1) { @@ -89,7 +84,4 @@ public abstract class TbAbstractTransformNode implements TbNode { protected abstract ListenableFuture> transform(TbContext ctx, TbMsg msg); - public void setConfig(TbTransformNodeConfiguration config) { - this.config = config; - } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java index 911b811032..5cc5dfe23f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java @@ -37,6 +37,7 @@ import org.thingsboard.server.common.msg.TbMsg; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.NoSuchElementException; @Slf4j @RuleNode( @@ -51,31 +52,36 @@ import java.util.List; configDirective = "tbTransformationNodeChangeOriginatorConfig", icon = "find_replace" ) -public class TbChangeOriginatorNode extends TbAbstractTransformNode { +public class TbChangeOriginatorNode extends TbAbstractTransformNode { - protected static final String CUSTOMER_SOURCE = "CUSTOMER"; - protected static final String TENANT_SOURCE = "TENANT"; - protected static final String RELATED_SOURCE = "RELATED"; - protected static final String ALARM_ORIGINATOR_SOURCE = "ALARM_ORIGINATOR"; - protected static final String ENTITY_SOURCE = "ENTITY"; - - private TbChangeOriginatorNodeConfiguration config; + private static final String CUSTOMER_SOURCE = "CUSTOMER"; + private static final String TENANT_SOURCE = "TENANT"; + private static final String RELATED_SOURCE = "RELATED"; + private static final String ALARM_ORIGINATOR_SOURCE = "ALARM_ORIGINATOR"; + private static final String ENTITY_SOURCE = "ENTITY"; @Override - public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, TbChangeOriginatorNodeConfiguration.class); + protected TbChangeOriginatorNodeConfiguration loadNodeConfiguration(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + var config = TbNodeUtils.convert(configuration, TbChangeOriginatorNodeConfiguration.class); validateConfig(config); - setConfig(config); + return config; } @Override protected ListenableFuture> transform(TbContext ctx, TbMsg msg) { - ListenableFuture newOriginator = getNewOriginator(ctx, msg); - return Futures.transform(newOriginator, n -> { - if (n == null || n.isNullUid()) { - return null; + ListenableFuture newOriginatorFuture = getNewOriginator(ctx, msg); + return Futures.transformAsync(newOriginatorFuture, newOriginator -> { + if (newOriginator == null || newOriginator.isNullUid()) { + return Futures.immediateFailedFuture(new NoSuchElementException("Failed to find new originator!")); } - return Collections.singletonList((ctx.transformMsg(msg, msg.getType(), n, msg.getMetaData(), msg.getData()))); + return Futures.immediateFuture( + Collections.singletonList( + ctx.transformMsg( + msg, + msg.getType(), + newOriginator, + msg.getMetaData(), + msg.getData()))); }, ctx.getDbCallbackExecutor()); } @@ -129,7 +135,6 @@ public class TbChangeOriginatorNode extends TbAbstractTransformNode { } EntitiesByNameAndTypeLoader.checkEntityType(EntityType.valueOf(conf.getEntityType())); } - } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeConfiguration.java index cc85933a48..473e83b91c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeConfiguration.java @@ -25,7 +25,9 @@ import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; import java.util.Collections; @Data -public class TbChangeOriginatorNodeConfiguration extends TbTransformNodeConfiguration implements NodeConfiguration { +public class TbChangeOriginatorNodeConfiguration implements NodeConfiguration { + + private static final String CUSTOMER_SOURCE = "CUSTOMER"; private String originatorSource; @@ -36,7 +38,7 @@ public class TbChangeOriginatorNodeConfiguration extends TbTransformNodeConfigur @Override public TbChangeOriginatorNodeConfiguration defaultConfiguration() { TbChangeOriginatorNodeConfiguration configuration = new TbChangeOriginatorNodeConfiguration(); - configuration.setOriginatorSource(TbChangeOriginatorNode.CUSTOMER_SOURCE); + configuration.setOriginatorSource(CUSTOMER_SOURCE); RelationsQuery relationsQuery = new RelationsQuery(); relationsQuery.setDirection(EntitySearchDirection.FROM); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java index 5c55cfb46d..ba78970c54 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java @@ -43,17 +43,16 @@ import java.util.List; uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbTransformationNodeScriptConfig" ) -public class TbTransformMsgNode extends TbAbstractTransformNode { +public class TbTransformMsgNode extends TbAbstractTransformNode { - private TbTransformMsgNodeConfiguration config; private ScriptEngine scriptEngine; @Override - public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, TbTransformMsgNodeConfiguration.class); + protected TbTransformMsgNodeConfiguration loadNodeConfiguration(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + var config = TbNodeUtils.convert(configuration, TbTransformMsgNodeConfiguration.class); scriptEngine = ctx.createScriptEngine(config.getScriptLang(), ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getTbelScript() : config.getJsScript()); - setConfig(config); + return config; } @Override @@ -62,12 +61,6 @@ public class TbTransformMsgNode extends TbAbstractTransformNode { return scriptEngine.executeUpdateAsync(msg); } - @Override - protected void transformSuccess(TbContext ctx, TbMsg msg, TbMsg m) { - ctx.logJsEvalResponse(); - super.transformSuccess(ctx, msg, m); - } - @Override protected void transformFailure(TbContext ctx, TbMsg msg, Throwable t) { ctx.logJsEvalFailure(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeConfiguration.java index 2d4aeac161..34d465f49c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeConfiguration.java @@ -20,7 +20,7 @@ import org.thingsboard.rule.engine.api.NodeConfiguration; import org.thingsboard.server.common.data.script.ScriptLanguage; @Data -public class TbTransformMsgNodeConfiguration extends TbTransformNodeConfiguration implements NodeConfiguration { +public class TbTransformMsgNodeConfiguration implements NodeConfiguration { private ScriptLanguage scriptLang; private String jsScript; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNodeConfiguration.java deleted file mode 100644 index 160bd6d8d1..0000000000 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformNodeConfiguration.java +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright © 2016-2023 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.rule.engine.transform; - -import lombok.Data; - -@Data -public class TbTransformNodeConfiguration { - -} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesCustomerIdAsyncLoader.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesCustomerIdAsyncLoader.java index d36162196e..52fb011614 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesCustomerIdAsyncLoader.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesCustomerIdAsyncLoader.java @@ -29,9 +29,7 @@ import org.thingsboard.server.common.data.id.UserId; public class EntitiesCustomerIdAsyncLoader { - public static ListenableFuture findEntityIdAsync(TbContext ctx, EntityId original) { - switch (original.getEntityType()) { case CUSTOMER: return Futures.immediateFuture((CustomerId) original); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java index 0d54e5ddc1..15dd7f85b1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntitiesFieldsAsyncLoader.java @@ -17,8 +17,6 @@ package org.thingsboard.rule.engine.util; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.MoreExecutors; -import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.BaseData; @@ -34,36 +32,37 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.id.UserId; +import java.util.NoSuchElementException; import java.util.function.Function; -@Slf4j public class EntitiesFieldsAsyncLoader { + public static ListenableFuture findAsync(TbContext ctx, EntityId originatorId) { switch (originatorId.getEntityType()) { case TENANT: return toEntityFieldsDataAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), (TenantId) originatorId), - EntityFieldsData::new); + EntityFieldsData::new, ctx); case CUSTOMER: return toEntityFieldsDataAsync(ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), (CustomerId) originatorId), - EntityFieldsData::new); + EntityFieldsData::new, ctx); case USER: return toEntityFieldsDataAsync(ctx.getUserService().findUserByIdAsync(ctx.getTenantId(), (UserId) originatorId), - EntityFieldsData::new); + EntityFieldsData::new, ctx); case ASSET: return toEntityFieldsDataAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), (AssetId) originatorId), - EntityFieldsData::new); + EntityFieldsData::new, ctx); case DEVICE: return toEntityFieldsDataAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), (DeviceId) originatorId), - EntityFieldsData::new); + EntityFieldsData::new, ctx); case ALARM: return toEntityFieldsDataAsync(ctx.getAlarmService().findAlarmByIdAsync(ctx.getTenantId(), (AlarmId) originatorId), - EntityFieldsData::new); + EntityFieldsData::new, ctx); case RULE_CHAIN: return toEntityFieldsDataAsync(ctx.getRuleChainService().findRuleChainByIdAsync(ctx.getTenantId(), (RuleChainId) originatorId), - EntityFieldsData::new); + EntityFieldsData::new, ctx); case ENTITY_VIEW: return toEntityFieldsDataAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), (EntityViewId) originatorId), - EntityFieldsData::new); + EntityFieldsData::new, ctx); default: return Futures.immediateFailedFuture(new TbNodeException("Unexpected originator EntityType: " + originatorId.getEntityType())); } @@ -71,10 +70,12 @@ public class EntitiesFieldsAsyncLoader { private static > ListenableFuture toEntityFieldsDataAsync( ListenableFuture future, - Function converter + Function converter, + TbContext ctx ) { return Futures.transformAsync(future, in -> in != null ? Futures.immediateFuture(converter.apply(in)) - : Futures.immediateFailedFuture(new TbNodeException("Entity not found!")), MoreExecutors.directExecutor()); + : Futures.immediateFailedFuture(new NoSuchElementException("Entity not found!")), ctx.getDbCallbackExecutor()); } + } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java index 1f7057050e..6af846d36d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java @@ -53,6 +53,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; @RunWith(MockitoJUnitRunner.class) public class TbChangeOriginatorNodeTest { + private static final String CUSTOMER_SOURCE = "CUSTOMER"; + private TbChangeOriginatorNode node; @Mock @@ -158,7 +160,7 @@ public class TbChangeOriginatorNodeTest { public void init() throws TbNodeException { TbChangeOriginatorNodeConfiguration config = new TbChangeOriginatorNodeConfiguration(); - config.setOriginatorSource(TbChangeOriginatorNode.CUSTOMER_SOURCE); + config.setOriginatorSource(CUSTOMER_SOURCE); ObjectMapper mapper = new ObjectMapper(); TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); From b43c28800102c85851f671d976f3e20f352c90b4 Mon Sep 17 00:00:00 2001 From: kalytka Date: Tue, 11 Apr 2023 17:04:39 +0300 Subject: [PATCH 015/421] Changes for the enrichment rule nodes --- .../relation/relation-filters.component.html | 35 +++++++---------- .../relation/relation-filters.component.scss | 38 +++++++++++++------ .../entity/entity-subtype-list.component.html | 11 +++++- .../entity/entity-subtype-list.component.ts | 13 +++++-- .../entity/entity-type-list.component.html | 3 +- .../relation-type-autocomplete.component.html | 8 ++-- .../relation-type-autocomplete.component.ts | 3 ++ .../rulenode/customer_attributes_node_fn.md | 24 ++++++++++++ .../assets/locale/locale.constant-en_US.json | 2 + 9 files changed, 95 insertions(+), 42 deletions(-) create mode 100644 ui-ngx/src/assets/help/en_US/rulenode/customer_attributes_node_fn.md diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html index 16222675db..d5dfca3e71 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html @@ -17,28 +17,21 @@ -->

-
-
- relation.type - entity.entity-types -   -
-
-
- - - - +
+ + + + +
-
@@ -56,14 +48,13 @@ class="tb-prompt" translate>relation.any-relation
-
diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss index b18f226f4f..d2bb8191c1 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss @@ -22,26 +22,40 @@ width: 100%; } - .header { - padding: 0 5px 5px; - - .cell { - padding-right: 5px; - padding-left: 5px; - font-size: 12px; - font-weight: 700; - color: rgba(0, 0, 0, .54); - white-space: nowrap; - } + .map-label { + font-weight: 400; + font-size: 12px; } + + //.header { + // padding: 0 5px 5px; + // + // .cell { + // padding-right: 5px; + // padding-left: 5px; + // font-size: 12px; + // font-weight: 700; + // color: rgba(0, 0, 0, .54); + // white-space: nowrap; + // } + //} + .body { - padding: 0 5px 20px; + //padding: 0 5px 20px; max-height: 300px; overflow: auto; .row { padding-top: 5px; + + .input-block { + border: 1px solid #E0E0E0; + border-radius: 6px; + padding: 24px 24px 2px 24px; + align-items: center; + margin: 0px 8px 15px 0px; + } } .cell { diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html index 7d45b5a071..909d780e45 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html @@ -15,7 +15,8 @@ limitations under the License. --> - + + {{ label | translate }} + = 0) { @@ -249,9 +258,7 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, this.searchText = searchText; return this.getEntitySubtypes().pipe( map(subTypes => { - let result = subTypes.filter( subType => { - return searchText ? subType.toUpperCase().startsWith(searchText.toUpperCase()) : true; - }); + let result = subTypes.filter( subType => searchText ? subType.toUpperCase().startsWith(searchText.toUpperCase()) : true); if (!result.length) { result = [searchText]; } diff --git a/ui-ngx/src/app/shared/components/entity/entity-type-list.component.html b/ui-ngx/src/app/shared/components/entity/entity-type-list.component.html index 7a20291a0a..6852f7f62d 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-type-list.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-type-list.component.html @@ -15,7 +15,8 @@ limitations under the License. --> - + + {{ 'entity.entity-types' | translate }} - - {{ 'relation.relation-type' | translate }} + + {{ label | translate }}
-
+
diff --git a/ui-ngx/src/app/modules/home/components/details-panel.component.scss b/ui-ngx/src/app/modules/home/components/details-panel.component.scss index 9002246841..b73eb5d58d 100644 --- a/ui-ngx/src/app/modules/home/components/details-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/details-panel.component.scss @@ -20,12 +20,22 @@ height: 100%; display: flex; flex-direction: column; + .mat-toolbar.details-toolbar { padding: 0; } } :host ::ng-deep { + + .reset-style { + color: rgba(0, 0, 0, 0.6);; + //font-family: "Arial"; + line-height: 24px; + //font-weight: 500; + letter-spacing: 0.5px; + } + .mat-toolbar-tools { height: 100%; min-height: 60px; diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html index bfc639e6b4..71965c4ba1 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html @@ -22,13 +22,13 @@ fxLayoutAlign="start center" formArrayName="relationFilters" *ngFor="let relationFilterControl of relationFiltersFormArray.controls; let $index = index">
-
- + - @@ -49,7 +49,7 @@ relation.any-relation
-
+
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.scss index 4995d5c06d..a576472592 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.scss +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.scss @@ -27,12 +27,16 @@ display: flex; flex-direction: column; gap: 8px; - margin-bottom: 5px; + + @media #{$mat-gt-sm} { + margin-bottom: 24px; + } } @media #{$mat-gt-sm} { flex-direction: row; gap: 8px; + align-items: center; .node-setting { margin-top: 5px; From e39e1d61ff537d165ace2ec7c8f3ff0a7201089c Mon Sep 17 00:00:00 2001 From: kalytka Date: Fri, 19 May 2023 15:11:15 +0300 Subject: [PATCH 062/421] Refactoring --- .../modules/home/components/details-panel.component.html | 2 +- .../modules/home/components/details-panel.component.scss | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/details-panel.component.html b/ui-ngx/src/app/modules/home/components/details-panel.component.html index e82ee068d5..720cdffd83 100644 --- a/ui-ngx/src/app/modules/home/components/details-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/details-panel.component.html @@ -65,6 +65,6 @@ -
+
diff --git a/ui-ngx/src/app/modules/home/components/details-panel.component.scss b/ui-ngx/src/app/modules/home/components/details-panel.component.scss index b73eb5d58d..2a820b9f54 100644 --- a/ui-ngx/src/app/modules/home/components/details-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/details-panel.component.scss @@ -20,7 +20,6 @@ height: 100%; display: flex; flex-direction: column; - .mat-toolbar.details-toolbar { padding: 0; } @@ -28,11 +27,9 @@ :host ::ng-deep { - .reset-style { - color: rgba(0, 0, 0, 0.6);; - //font-family: "Arial"; + .details-panel-style { + color: rgba(0, 0, 0, 0.6); line-height: 24px; - //font-weight: 500; letter-spacing: 0.5px; } From dfbd8801887e3b37fa239393ace974010170e83c Mon Sep 17 00:00:00 2001 From: kalytka Date: Fri, 19 May 2023 16:10:29 +0300 Subject: [PATCH 063/421] Refactoring --- .../modules/home/components/details-panel.component.html | 2 +- .../modules/home/components/details-panel.component.scss | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/details-panel.component.html b/ui-ngx/src/app/modules/home/components/details-panel.component.html index 720cdffd83..15df7e99e5 100644 --- a/ui-ngx/src/app/modules/home/components/details-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/details-panel.component.html @@ -65,6 +65,6 @@ -
+
diff --git a/ui-ngx/src/app/modules/home/components/details-panel.component.scss b/ui-ngx/src/app/modules/home/components/details-panel.component.scss index 2a820b9f54..9002246841 100644 --- a/ui-ngx/src/app/modules/home/components/details-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/details-panel.component.scss @@ -26,13 +26,6 @@ } :host ::ng-deep { - - .details-panel-style { - color: rgba(0, 0, 0, 0.6); - line-height: 24px; - letter-spacing: 0.5px; - } - .mat-toolbar-tools { height: 100%; min-height: 60px; From 490ad63ab69eff1c7abc2e5424c8bab9abd308d8 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 19 May 2023 17:27:52 +0300 Subject: [PATCH 064/421] updated rule node upgrade logic --- .../update/DefaultDataUpdateService.java | 64 +++++++------------ .../server/dao/rule/BaseRuleChainService.java | 31 ++------- 2 files changed, 29 insertions(+), 66 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 59f4b9cc82..2c63b9987d 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -27,7 +27,6 @@ import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbVersionedNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; @@ -86,10 +85,11 @@ import org.thingsboard.server.service.bean.BeanDiscoveryService; import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.install.SystemDataLoaderService; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; @@ -221,35 +221,26 @@ public class DefaultDataUpdateService implements DataUpdateService { private void upgradeRuleNodes() { try { log.info("Lookup rule nodes to upgrade ..."); - ArrayList tbVersionedNodes = getTbVersionedNodes(); - log.info("Found {} versioned nodes to check for upgrade!", tbVersionedNodes.size()); - for (TbVersionedNode tbVersionedNode : tbVersionedNodes) { - String ruleNodeType = tbVersionedNode.getClass().getName(); - String ruleNodeTypeForLogs = tbVersionedNode.getClass().getSimpleName(); - int toVersion = tbVersionedNode.getCurrentVersion(); + var nodeClassToVersionMap = getNodeClassToVersionMap(); + log.info("Found {} versioned nodes to check for upgrade!", nodeClassToVersionMap.size()); + nodeClassToVersionMap.forEach((clazz, toVersion) -> { + var ruleNodeType = clazz.getName(); + var ruleNodeTypeForLogs = clazz.getSimpleName(); log.info("Going to check for nodes with type: {} to upgrade to version: {}.", ruleNodeTypeForLogs, toVersion); var ruleNodesToUpdate = new PageDataIterable<>( - pageLink -> - ruleChainService.findAllRuleNodesByTypeAndVersionLessThan( - ruleNodeType, - toVersion, - pageLink - ), - 1024 + pageLink -> ruleChainService.findAllRuleNodesByTypeAndVersionLessThan(ruleNodeType, toVersion, pageLink), 1024 ); if (Iterables.isEmpty(ruleNodesToUpdate)) { log.info("There are no active nodes with type: {}, or all nodes with this type already set to latest version!", ruleNodeTypeForLogs); } else { - for (RuleNode ruleNode : ruleNodesToUpdate) { - RuleNodeId ruleNodeId = ruleNode.getId(); + for (var ruleNode : ruleNodesToUpdate) { + var ruleNodeId = ruleNode.getId(); var oldConfiguration = ruleNode.getConfiguration(); int fromVersion = ruleNode.getConfigurationVersion(); log.info("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", - ruleNodeId, - ruleNodeTypeForLogs, - fromVersion, - toVersion); + ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion); try { + var tbVersionedNode = (TbVersionedNode) clazz.getDeclaredConstructor().newInstance(); TbPair upgradeRuleNodeConfigurationResult = tbVersionedNode.upgrade(fromVersion, oldConfiguration); if (upgradeRuleNodeConfigurationResult.getFirst()) { ruleNode.setConfiguration(upgradeRuleNodeConfigurationResult.getSecond()); @@ -257,45 +248,34 @@ public class DefaultDataUpdateService implements DataUpdateService { ruleNode.setConfigurationVersion(toVersion); ruleChainService.saveRuleNode(TenantId.SYS_TENANT_ID, ruleNode); log.info("Successfully upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", - ruleNodeId, - ruleNodeTypeForLogs, - fromVersion, - toVersion); - } catch (TbNodeException e) { + ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion); + } catch (Exception e) { log.warn("Failed to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {} due to: ", - ruleNodeId, - ruleNodeTypeForLogs, - fromVersion, - toVersion, - e); + ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion, e); } } } - } + }); log.info("Finished rule nodes upgrade!"); } catch (Exception e) { log.error("Unexpected error during rule nodes upgrade: ", e); } } - private ArrayList getTbVersionedNodes() { + private Map, Integer> getNodeClassToVersionMap() { var ruleNodeDefinitions = beanDiscoveryService.discoverBeansByAnnotationType( org.thingsboard.rule.engine.api.RuleNode.class ); - var tbVersionedNodes = new ArrayList(); + var tbVersionedNodes = new HashMap, Integer>(); for (var def : ruleNodeDefinitions) { String clazzName = def.getBeanClassName(); try { var clazz = Class.forName(clazzName); if (TbVersionedNode.class.isAssignableFrom(clazz)) { - tbVersionedNodes.add((TbVersionedNode) clazz.getDeclaredConstructor().newInstance()); - } - } catch (NoSuchMethodException | - InstantiationException | - IllegalAccessException | - InvocationTargetException | - ClassNotFoundException e - ) { + TbVersionedNode tbVersionedNode = (TbVersionedNode) clazz.getDeclaredConstructor().newInstance(); + tbVersionedNodes.put(clazz, tbVersionedNode.getCurrentVersion()); + } + } catch (Exception e) { log.warn("Failed to create instance of rule node type: {} due to: ", clazzName, e); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 92146aa427..7d85087703 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -199,10 +199,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC int toVersion = tbVersionedNode.getCurrentVersion(); if (fromVersion < toVersion) { log.debug("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", - ruleNodeId, - ruleNodeType, - fromVersion, - toVersion); + ruleNodeId, ruleNodeType, fromVersion, toVersion); try { TbPair upgradeResult = tbVersionedNode.upgrade(fromVersion, node.getConfiguration()); if (upgradeResult.getFirst()) { @@ -210,33 +207,19 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } node.setConfigurationVersion(toVersion); log.debug("Successfully upgrade rule node with id: {} type: {}, rule chain id: {} fromVersion: {} toVersion: {}", - ruleNodeId, - ruleNodeType, - ruleChainId, - fromVersion, - toVersion); + ruleNodeId, ruleNodeType, ruleChainId, fromVersion, toVersion); } catch (TbNodeException e) { log.warn("Failed to upgrade rule node with id: {} type: {} rule chain id: {} fromVersion: {} toVersion: {} due to: ", - ruleNodeId, - ruleNodeType, - ruleChainId, - fromVersion, - toVersion, - e); + ruleNodeId, ruleNodeType, ruleChainId, fromVersion, toVersion, e); } } else { log.debug("Rule node with id: {} type: {} ruleChainId: {} already set to latest version!", - ruleNodeId, - ruleChainId, - ruleNodeType); + ruleNodeId, ruleChainId, ruleNodeType); } } - } catch (ClassNotFoundException | - InvocationTargetException | - InstantiationException | - IllegalAccessException | - NoSuchMethodException e) { - log.error("Failed to create instance of rule node with id: {} type: {}, rule chain id: {}", ruleNodeId, ruleNodeType, ruleChainId); + } catch (Exception e) { + log.error("Failed to create instance of rule node with id: {} type: {}, rule chain id: {}", + ruleNodeId, ruleNodeType, ruleChainId); } RuleNode savedNode = ruleNodeDao.save(tenantId, node); relations.add(new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(), From d67313cf8c6413d9ab26c413515a611fe71ebabb Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 22 May 2023 15:57:26 +0300 Subject: [PATCH 065/421] fix rule node descriptions & fix validation messages & updated tests --- .../engine/metadata/CalculateDeltaNode.java | 8 ++++---- .../metadata/TbAbstractGetEntityDataNode.java | 17 ++++++++++++----- .../TbFetchDeviceCredentialsNode.java | 9 ++++----- .../engine/metadata/TbGetAttributesNode.java | 12 +++++++----- .../metadata/TbGetCustomerAttributeNode.java | 19 ++++++------------- .../metadata/TbGetCustomerDetailsNode.java | 15 +++++++++------ .../engine/metadata/TbGetDeviceAttrNode.java | 14 +++++++++----- .../metadata/TbGetOriginatorFieldsNode.java | 9 ++++++--- .../metadata/TbGetRelatedAttributeNode.java | 19 +++++++++++-------- .../engine/metadata/TbGetTelemetryNode.java | 18 +++++++++++------- .../metadata/TbGetTenantAttributeNode.java | 16 +++------------- .../metadata/TbGetTenantDetailsNode.java | 7 +++---- .../TbGetCustomerAttributeNodeTest.java | 2 +- .../TbGetCustomerDetailsNodeTest.java | 2 +- 14 files changed, 87 insertions(+), 80 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java index 291c2cf316..71038e934f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java @@ -48,10 +48,10 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; name = "calculate delta", relationTypes = {"Success", "Failure", "Other"}, configClazz = CalculateDeltaNodeConfiguration.class, nodeDescription = "Calculates and adds 'delta' value into message based on the incoming and previous value", - nodeDetails = "Calculates delta and period based on the previous time-series reading and current data. " + - "Delta calculation is done in scope of the message originator, e.g. device, asset or customer. " + - "If there is input key, the output relation will be 'Success' unless delta is negative and corresponding configuration parameter is set. " + - "If there is no input value key in the incoming message, the output relation will be 'Other'.", + nodeDetails = "Calculates delta and period based on the previous timeseries reading and current data. " + + "Delta calculation is done in scope of the message originator, e.g. device, asset or customer.

" + + "If there is input key, the output relation will be Success unless delta is negative and corresponding configuration parameter is set.
" + + "If there is no input value key in the incoming message, the output relation will be Other.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeCalculateDeltaConfig") public class CalculateDeltaNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java index 5615147fd0..4550a4f3f8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDataNode.java @@ -30,10 +30,13 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; @Slf4j public abstract class TbAbstractGetEntityDataNode extends TbAbstractGetMappedDataNode { - protected final static String DATA_TO_FETCH_PROPERTY_NAME = "dataToFetch"; - protected static final String OLD_DATA_TO_FETCH_PROPERTY_NAME = "telemetry"; - protected final static String DATA_MAPPING_PROPERTY_NAME = "dataMapping"; - protected static final String OLD_DATA_MAPPING_PROPERTY_NAME = "attrMapping"; + private final static String DATA_TO_FETCH_PROPERTY_NAME = "dataToFetch"; + private static final String OLD_DATA_TO_FETCH_PROPERTY_NAME = "telemetry"; + private final static String DATA_MAPPING_PROPERTY_NAME = "dataMapping"; + private static final String OLD_DATA_MAPPING_PROPERTY_NAME = "attrMapping"; + + private static final String DATA_TO_FETCH_VALIDATION_MSG = "DataToFetch property has invalid value: %s." + + " Only ATTRIBUTES and LATEST_TELEMETRY values supported!"; @Override public void onMsg(TbContext ctx, TbMsg msg) { @@ -45,7 +48,11 @@ public abstract class TbAbstractGetEntityDataNode extends Tb protected abstract ListenableFuture findEntityAsync(TbContext ctx, EntityId originator); - protected abstract void checkDataToFetchSupportedOrElseThrow(DataToFetch dataToFetch) throws TbNodeException; + protected void checkDataToFetchSupportedOrElseThrow(DataToFetch dataToFetch) throws TbNodeException { + if (dataToFetch == null || dataToFetch.equals(DataToFetch.FIELDS)) { + throw new TbNodeException(String.format(DATA_TO_FETCH_VALIDATION_MSG, dataToFetch)); + } + } protected void processDataAndTell(TbContext ctx, TbMsg msg, T entityId, ObjectNode msgDataAsJsonNode) { DataToFetch dataToFetch = config.getDataToFetch(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java index ec21706ff1..e044dcbae6 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java @@ -37,11 +37,10 @@ import java.util.concurrent.ExecutionException; type = ComponentType.ENRICHMENT, name = "fetch device credentials", configClazz = TbFetchDeviceCredentialsNodeConfiguration.class, - nodeDescription = "Enrich the message body or metadata with the device credentials", - nodeDetails = "Adds credentialsType and credentials properties to the message metadata if the " + - "configuration parameter fetchToMetadata is set to true, otherwise, adds properties " + - "to the message data. If originator type is not DEVICE or rule node failed to get device credentials " + - "- send Message via Failure chain, otherwise Success chain is used.", + nodeDescription = "Adds device credentials to the message or message metadata", + nodeDetails = "if message originator type is Device and device credentials was successfully fetched, " + + "rule node enriches message or message metadata with credentialsType and credentials properties " + + "and send message via Success chain. Otherwise message will be forwarded via Failure chain.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeFetchDeviceCredentialsConfig") public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java index 2d1f02acf8..42b0633cb2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java @@ -36,11 +36,13 @@ import org.thingsboard.server.common.msg.TbMsg; @RuleNode(type = ComponentType.ENRICHMENT, name = "originator attributes", configClazz = TbGetAttributesNodeConfiguration.class, - nodeDescription = "Enrich the message body or metadata with the originator attributes and/or timeseries data", - nodeDetails = "If Attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into Message data/metadata " + - "with specific prefix: cs/shared/ss. Latest telemetry value added into Message data/metadata without prefix. " + - "To access those attributes in other nodes this template can be used " + - "metadata.cs_temperature or metadata.shared_limit ", + nodeDescription = "Adds originator attributes and/or latest timeseries data for the message originator to the message or message metadata", + nodeDetails = "If attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into message or message metadata " + + "with specific prefix: cs/shared/ss. Latest telemetry value adds without prefix.

" + + "See the following examples of accessing those attributes in other nodes:
" + + "metadata.cs_serialNumber - to access client side attribute 'serialNumber' that was fetched to message metadata.
" + + "metadata.shared_limit - to access shared side attribute 'limit' that was fetched to message metadata.
" + + "msg.temperature - to access latest telemetry 'temperature' that was fetched to message.
", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeOriginatorAttributesConfig") public class TbGetAttributesNode extends TbAbstractGetAttributesNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index e693dab684..1deae1f5fb 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -35,16 +35,17 @@ import org.thingsboard.server.common.data.util.TbPair; type = ComponentType.ENRICHMENT, name = "customer attributes", configClazz = TbGetEntityDataNodeConfiguration.class, - nodeDescription = "Add Originators Customer Attributes or Latest Telemetry into Message or Metadata", - nodeDetails = "Enrich the Message or Metadata with the corresponding customer's latest attributes or telemetry value. " + - "The customer is selected based on the originator of the message: device, asset, etc. " + - "
" + + nodeDescription = "Adds message originator customer attributes or latest telemetry into message or message metadata", + nodeDetails = "Enriches incoming message or message metadata with the customer's attributes or latest telemetry values.

" + + "The customer is selected based on the originator of the message. " + + "Supported originator types:

" + + "Customer, User, Asset, Device.

" + "Useful when you store some parameters on the customer level and would like to use them for message processing.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeCustomerAttributesConfig") public class TbGetCustomerAttributeNode extends TbAbstractGetEntityDataNode { - private static final String CUSTOMER_NOT_FOUND_MESSAGE = "Failed to find customer for entity with id %s and type %s"; + private static final String CUSTOMER_NOT_FOUND_MESSAGE = "Failed to find customer for entity with id: %s and type: %s"; @Override protected TbGetEntityDataNodeConfiguration loadNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { @@ -54,14 +55,6 @@ public class TbGetCustomerAttributeNode extends TbAbstractGetEntityDataNode findEntityAsync(TbContext ctx, EntityId originator) { return Futures.transformAsync(EntitiesCustomerIdAsyncLoader.findEntityIdAsync(ctx, originator), diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java index c31f9cbcef..a86aed66d5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java @@ -44,10 +44,13 @@ import java.util.NoSuchElementException; @RuleNode(type = ComponentType.ENRICHMENT, name = "customer details", configClazz = TbGetCustomerDetailsNodeConfiguration.class, - nodeDescription = "Enrich the message body or metadata with the corresponding customer details: title, address, email, phone, etc.", - nodeDetails = "If checkbox: Add selected details to the message metadata is selected, existing fields will be added to the message metadata instead of message data.

" + - "Note: only Device, Asset, and Entity View type are allowed.

" + - "If the originator of the message is not assigned to Customer, or originator type is not supported - Message will be forwarded to Failure chain, otherwise, Success chain will be used.", + nodeDescription = "Adds originator customer details into message or message metadata", + nodeDetails = "Enriches incoming message or message metadata with the corresponding customer details. " + + "Selected details adds to the message with predefined prefix: customer_. Examples: customer_title, customer_address, etc.

" + + "The customer is selected based on the originator of the message. Supported originator types:

" + + "Device, Asset, Entity view, User, Edge.

" + + "If message originator is not assigned to customer, or originator is not supported - " + + "message will be forwarded via Failure chain, otherwise, Success chain will be used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode { @@ -96,9 +99,9 @@ public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNodecs/shared/ss
. Latest telemetry value added into Message data/metadata without prefix. " + - "To access those attributes in other nodes this template can be used " + - "metadata.cs_temperature or metadata.shared_limit ", + nodeDescription = "Add originators related device attributes and latest telemetry values into message or message metadata", + nodeDetails = "Related device lookup based on the configured relation query. " + + "If multiple related devices are found, only first device is used for message enrichment, other entities are discarded.

" + + "If Attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into message or message metadata " + + "with specific prefix: cs/shared/ss. Latest telemetry value adds into message or message metadata without prefix.

" + + "See the following examples of accessing those attributes in other nodes:
" + + "metadata.cs_serialNumber - to access client side attribute 'serialNumber' that was fetched to message metadata.
" + + "metadata.shared_limit - to access shared side attribute 'limit' that was fetched to message metadata.
" + + "msg.temperature - to access latest telemetry 'temperature' that was fetched to message.
", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeDeviceAttributesConfig") public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java index f777d98bcb..b0a282af1f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java @@ -37,9 +37,12 @@ import java.util.concurrent.ExecutionException; @RuleNode(type = ComponentType.ENRICHMENT, name = "originator fields", configClazz = TbGetOriginatorFieldsConfiguration.class, - nodeDescription = "Add Message Originator fields values into Message Metadata or Message Data", - nodeDetails = "Will fetch fields values specified in mapping. If specified field is not part of originator fields it will be ignored. " + - "This node supports only following originator types: TENANT, CUSTOMER, USER, ASSET, DEVICE, ALARM, RULE_CHAIN, ENTITY_VIEW.", + nodeDescription = "Adds message originator fields values into message or message metadata", + nodeDetails = "Fetches fields values specified in the mapping. If specified field is not part of originator fields it will be ignored. " + + "Supported originator types:

" + + "Tenant, Customer, User, Asset, Device, Alarm, Rule chain, Entity view.

" + + "If message originator is not supported - message will be forwarded via Failure chain, " + + "otherwise, Success chain will be used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeOriginatorFieldsConfig") public class TbGetOriginatorFieldsNode extends TbAbstractGetMappedDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index 3c508bda14..109c47dcac 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -34,15 +34,18 @@ import java.util.Arrays; @Slf4j @RuleNode( type = ComponentType.ENRICHMENT, - name = "related attributes", + name = "related entity data", configClazz = TbGetRelatedDataNodeConfiguration.class, - nodeDescription = "Add Originators Related Entity Attributes or Latest Telemetry into Message Metadata/Data", - nodeDetails = "Related Entity found using configured relation direction and Relation Type. " + - "If multiple Related Entities are found, only first Entity is used for attributes enrichment, other entities are discarded. " + - "If Attributes enrichment configured, server scope attributes are added into Message Metadata/Data. " + - "If Latest Telemetry enrichment configured, latest telemetry added into Metadata/Data. " + - "To access those attributes in other nodes this template can be used " + - "metadata.temperature.", + nodeDescription = "Adds originators related entity data into message or message metadata", + nodeDetails = "Related entity lookup based on the configured relation query. " + + "If multiple related entities are found, only first entity is used for message enrichment, other entities are discarded.

" + + "Data to fetch configuration:

" + + "Attributes - rule node fetches server scope attributes configured in mapping and adds them into message or message metadata. " + + "Access example in other nodes: metadata.serialNumber, msg.serialNumber.
" + + "Latest telemetry - rule node fetches latest telemetry configured in mapping and adds them into message or message metadata. " + + "Access example in other nodes: metadata.temperature, msg.temperature.
" + + "Fields - rule node fetches fields configured in mapping and adds them into message or message metadata. " + + "Access example in other nodes: metadata.entityName, msg.entityName.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeRelatedAttributesConfig") public class TbGetRelatedAttributeNode extends TbAbstractGetEntityDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java index b43aeb4e4b..97f08ce8fd 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java @@ -54,13 +54,17 @@ import static org.thingsboard.rule.engine.metadata.TbGetTelemetryNodeConfigurati @RuleNode(type = ComponentType.ENRICHMENT, name = "originator telemetry", configClazz = TbGetTelemetryNodeConfiguration.class, - nodeDescription = "Add Message Originator Telemetry for selected time range into Message Metadata\n", - nodeDetails = "The node allows you to select fetch mode: FIRST/LAST/ALL to fetch telemetry of certain time range that are added into Message metadata without any prefix. " + - "If selected fetch mode ALL Telemetry will be added like array into Message Metadata where key is Timestamp and value is value of Telemetry.
" + - "If selected fetch mode FIRST or LAST Telemetry will be added like string without Timestamp.
" + - "Also, the rule node allows you to select telemetry sampling order: ASC or DESC.
" + - "Aggregation feature allows you to fetch aggregated telemetry as a single value by AVG, COUNT, SUM, MIN, MAX, NONE.
" + - "Note: The maximum size of the fetched array is 1000 records.\n ", + nodeDescription = "Adds message originator telemetry for selected time range into message metadata", + nodeDetails = "The node allows you to configure fetch interval and fetch strategy. Fetch strategy section allows you to select fetch mode: First/Last/All

" + + "If selected fetch mode First rule node will retrieve the closest telemetry to the fetch interval's start.
" + + "If selected fetch mode Last rule node will retrieve the closest telemetry to the fetch interval's end.
" + + "If selected fetch mode All rule node will retrieve telemetry from the fetch interval with configurable query parameters.

" + + "Query parameters:

" + + "Data aggregation function: Min/Max/Average/Sum/Count/None. " + + "If selected aggregation function None rule node allows you to configure additional query parameters:

" + + "Order by timestamp: Ascending/Descending

" + + "Limit: Min value - 2, max value - 1000.

" + + "Other data aggregation functions useful when you need to get the aggregated telemetry data as a single value for the configured fetch interval.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase") public class TbGetTelemetryNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index aac8d8d3bf..df1ae1b371 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -34,11 +34,9 @@ import org.thingsboard.server.common.data.util.TbPair; type = ComponentType.ENRICHMENT, name = "tenant attributes", configClazz = TbGetEntityDataNodeConfiguration.class, - nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata/Data", - nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message Metadata/Data. " + - "If Latest Telemetry enrichment configured, latest telemetry added into Metadata/Data. " + - "To access those attributes in other nodes this template can be used " + - "metadata.temperature.", + nodeDescription = "Adds message originator tenant attributes or latest telemetry into message or message metadata", + nodeDetails = "Enriches incoming message or message metadata with the tenant's attributes or latest telemetry values. " + + "Useful when you store some parameters on the tenant level and would like to use them for message processing.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeTenantAttributesConfig") public class TbGetTenantAttributeNode extends TbAbstractGetEntityDataNode { @@ -56,14 +54,6 @@ public class TbGetTenantAttributeNode extends TbAbstractGetEntityDataNode upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException { return fromVersion == 0 ? upgradeToUseFetchToAndDataToFetch(oldConfiguration) : new TbPair<>(false, oldConfiguration); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index 759a91785c..e6433b541e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -33,10 +33,9 @@ import org.thingsboard.server.common.msg.TbMsg; @RuleNode(type = ComponentType.ENRICHMENT, name = "tenant details", configClazz = TbGetTenantDetailsNodeConfiguration.class, - nodeDescription = "Adds fields from Tenant details to the message body or metadata", - nodeDetails = "If checkbox: Add selected details to the message metadata is selected, existing fields will be added to the message metadata instead of message data.

" + - "Note: only Device, Asset, and Entity View type are allowed.

" + - "If the originator of the message is not assigned to Tenant, or originator type is not supported - Message will be forwarded to Failure chain, otherwise, Success chain will be used.", + nodeDescription = "Adds originator tenant details into message or message metadata", + nodeDetails = "Enriches incoming message or message metadata with the corresponding tenant details. " + + "Selected details adds to the message with predefined prefix: tenant_, Examples: tenant_title or tenant_address, etc.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 54e2f3bd4b..e1b799552c 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -262,7 +262,7 @@ public class TbGetCustomerAttributeNodeTest { var actualException = actualExceptionCaptor.getValue(); var expectedExceptionMessage = String.format( - "Failed to find customer for entity with id %s and type %s", + "Failed to find customer for entity with id: %s and type: %s", userId.getId(), userId.getEntityType().getNormalName()); assertEquals(msg, actualMessage); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java index 901172d344..bfbfd83051 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java @@ -385,7 +385,7 @@ public class TbGetCustomerDetailsNodeTest { assertThat(actualMsg.getMetaData()).isEqualTo(msg.getMetaData()); assertThat(actualException).isInstanceOf(RuntimeException.class); - assertThat(actualException.getMessage()).isEqualTo("Device with name 'Thermostat' is not assigned to Customer."); + assertThat(actualException.getMessage()).isEqualTo("Device with name 'Thermostat' is not assigned to Customer!"); } @Test From 1ebd385c8cae5c61e523cd1e876b6300ecac2371 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 23 May 2023 15:06:13 +0300 Subject: [PATCH 066/421] updated rule node details & descriptions --- .../rule/engine/metadata/CalculateDeltaNode.java | 8 +++----- .../metadata/TbFetchDeviceCredentialsNode.java | 4 ++-- .../rule/engine/metadata/TbGetAttributesNode.java | 11 ++++------- .../engine/metadata/TbGetCustomerAttributeNode.java | 8 +++----- .../engine/metadata/TbGetCustomerDetailsNode.java | 10 +++------- .../rule/engine/metadata/TbGetDeviceAttrNode.java | 11 +++-------- .../engine/metadata/TbGetOriginatorFieldsNode.java | 5 +---- .../engine/metadata/TbGetRelatedAttributeNode.java | 12 +++--------- .../rule/engine/metadata/TbGetTelemetryNode.java | 13 +++---------- .../engine/metadata/TbGetTenantAttributeNode.java | 4 ++-- .../engine/metadata/TbGetTenantDetailsNode.java | 6 +++--- 11 files changed, 30 insertions(+), 62 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java index 71038e934f..1a2ba6d646 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java @@ -47,11 +47,9 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; @RuleNode(type = ComponentType.ENRICHMENT, name = "calculate delta", relationTypes = {"Success", "Failure", "Other"}, configClazz = CalculateDeltaNodeConfiguration.class, - nodeDescription = "Calculates and adds 'delta' value into message based on the incoming and previous value", - nodeDetails = "Calculates delta and period based on the previous timeseries reading and current data. " + - "Delta calculation is done in scope of the message originator, e.g. device, asset or customer.

" + - "If there is input key, the output relation will be Success unless delta is negative and corresponding configuration parameter is set.
" + - "If there is no input value key in the incoming message, the output relation will be Other.", + nodeDescription = "Calculates delta and amount of time passed between previous timeseries key reading " + + "and current value for this key from the incoming message", + nodeDetails = "Useful for metering use cases, when you need to calculate consumption based on pulse counter reading.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeCalculateDeltaConfig") public class CalculateDeltaNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java index e044dcbae6..130b50872f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java @@ -39,8 +39,8 @@ import java.util.concurrent.ExecutionException; configClazz = TbFetchDeviceCredentialsNodeConfiguration.class, nodeDescription = "Adds device credentials to the message or message metadata", nodeDetails = "if message originator type is Device and device credentials was successfully fetched, " + - "rule node enriches message or message metadata with credentialsType and credentials properties " + - "and send message via Success chain. Otherwise message will be forwarded via Failure chain.", + "rule node enriches message or message metadata with credentialsType and credentials properties. " + + "Useful when you need to fetch device credentials and use them for further message processing. For example, use device credentials to interact with external systems.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeFetchDeviceCredentialsConfig") public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java index 42b0633cb2..2c0eed086c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java @@ -36,13 +36,10 @@ import org.thingsboard.server.common.msg.TbMsg; @RuleNode(type = ComponentType.ENRICHMENT, name = "originator attributes", configClazz = TbGetAttributesNodeConfiguration.class, - nodeDescription = "Adds originator attributes and/or latest timeseries data for the message originator to the message or message metadata", - nodeDetails = "If attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into message or message metadata " + - "with specific prefix: cs/shared/ss. Latest telemetry value adds without prefix.

" + - "See the following examples of accessing those attributes in other nodes:
" + - "metadata.cs_serialNumber - to access client side attribute 'serialNumber' that was fetched to message metadata.
" + - "metadata.shared_limit - to access shared side attribute 'limit' that was fetched to message metadata.
" + - "msg.temperature - to access latest telemetry 'temperature' that was fetched to message.
", + nodeDescription = "Adds attributes and/or latest timeseries data for the message originator to the message or message metadata", + nodeDetails = "Useful when you need to retrieve some attributes or the latest telemetry readings from the message originator " + + "that are not included in the incoming message to use them for further message processing. " + + "For example to filter messages based on the threshold value stored in the attributes.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeOriginatorAttributesConfig") public class TbGetAttributesNode extends TbAbstractGetAttributesNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index 1deae1f5fb..74865da5b9 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -36,11 +36,9 @@ import org.thingsboard.server.common.data.util.TbPair; name = "customer attributes", configClazz = TbGetEntityDataNodeConfiguration.class, nodeDescription = "Adds message originator customer attributes or latest telemetry into message or message metadata", - nodeDetails = "Enriches incoming message or message metadata with the customer's attributes or latest telemetry values.

" + - "The customer is selected based on the originator of the message. " + - "Supported originator types:

" + - "Customer, User, Asset, Device.

" + - "Useful when you store some parameters on the customer level and would like to use them for message processing.", + nodeDetails = "Useful in multi-customer solutions where each customer has a different configuration or threshold set " + + "that is stored as customer attributes or telemetry data and used for dynamic message filtering, transformation, " + + "or actions such as alarm creation if the threshold is exceeded.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeCustomerAttributesConfig") public class TbGetCustomerAttributeNode extends TbAbstractGetEntityDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java index a86aed66d5..723b98a98d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java @@ -44,13 +44,9 @@ import java.util.NoSuchElementException; @RuleNode(type = ComponentType.ENRICHMENT, name = "customer details", configClazz = TbGetCustomerDetailsNodeConfiguration.class, - nodeDescription = "Adds originator customer details into message or message metadata", - nodeDetails = "Enriches incoming message or message metadata with the corresponding customer details. " + - "Selected details adds to the message with predefined prefix: customer_. Examples: customer_title, customer_address, etc.

" + - "The customer is selected based on the originator of the message. Supported originator types:

" + - "Device, Asset, Entity view, User, Edge.

" + - "If message originator is not assigned to customer, or originator is not supported - " + - "message will be forwarded via Failure chain, otherwise, Success chain will be used.", + nodeDescription = "Adds message originator customer details into message or message metadata", + nodeDetails = "Useful in multi-customer solutions where we need dynamically use customer contact information " + + "such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java index 3a55c5d7ca..f776aeaa8c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java @@ -34,15 +34,10 @@ import org.thingsboard.server.common.msg.TbMsg; @RuleNode(type = ComponentType.ENRICHMENT, name = "related device attributes", configClazz = TbGetDeviceAttrNodeConfiguration.class, - nodeDescription = "Add originators related device attributes and latest telemetry values into message or message metadata", + nodeDescription = "Add originators related device attributes and/or latest telemetry values into message or message metadata", nodeDetails = "Related device lookup based on the configured relation query. " + - "If multiple related devices are found, only first device is used for message enrichment, other entities are discarded.

" + - "If Attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into message or message metadata " + - "with specific prefix: cs/shared/ss. Latest telemetry value adds into message or message metadata without prefix.

" + - "See the following examples of accessing those attributes in other nodes:
" + - "metadata.cs_serialNumber - to access client side attribute 'serialNumber' that was fetched to message metadata.
" + - "metadata.shared_limit - to access shared side attribute 'limit' that was fetched to message metadata.
" + - "msg.temperature - to access latest telemetry 'temperature' that was fetched to message.
", + "If multiple related devices are found, only first device is used for message enrichment, other entities are discarded. " + + "Useful when you need to retrieve attributes and/or latest telemetry values from device that has a relation to the message originator and use them for further message processing.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeDeviceAttributesConfig") public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java index b0a282af1f..bd775ed4dc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java @@ -39,10 +39,7 @@ import java.util.concurrent.ExecutionException; configClazz = TbGetOriginatorFieldsConfiguration.class, nodeDescription = "Adds message originator fields values into message or message metadata", nodeDetails = "Fetches fields values specified in the mapping. If specified field is not part of originator fields it will be ignored. " + - "Supported originator types:

" + - "Tenant, Customer, User, Asset, Device, Alarm, Rule chain, Entity view.

" + - "If message originator is not supported - message will be forwarded via Failure chain, " + - "otherwise, Success chain will be used.", + "Useful when you need to retrieve originator fields and use them for further message processing.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeOriginatorFieldsConfig") public class TbGetOriginatorFieldsNode extends TbAbstractGetMappedDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index 109c47dcac..60d684098f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -36,16 +36,10 @@ import java.util.Arrays; type = ComponentType.ENRICHMENT, name = "related entity data", configClazz = TbGetRelatedDataNodeConfiguration.class, - nodeDescription = "Adds originators related entity data into message or message metadata", + nodeDescription = "Adds originators related entity attributes or latest telemetry or fields into message or message metadata", nodeDetails = "Related entity lookup based on the configured relation query. " + - "If multiple related entities are found, only first entity is used for message enrichment, other entities are discarded.

" + - "Data to fetch configuration:

" + - "Attributes - rule node fetches server scope attributes configured in mapping and adds them into message or message metadata. " + - "Access example in other nodes: metadata.serialNumber, msg.serialNumber.
" + - "Latest telemetry - rule node fetches latest telemetry configured in mapping and adds them into message or message metadata. " + - "Access example in other nodes: metadata.temperature, msg.temperature.
" + - "Fields - rule node fetches fields configured in mapping and adds them into message or message metadata. " + - "Access example in other nodes: metadata.entityName, msg.entityName.", + "If multiple related entities are found, only first entity is used for message enrichment, other entities are discarded. " + + "Useful when you need to retrieve data from an entity that has a relation to the message originator and use them for further message processing.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeRelatedAttributesConfig") public class TbGetRelatedAttributeNode extends TbAbstractGetEntityDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java index 97f08ce8fd..569c76c2a2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java @@ -55,16 +55,9 @@ import static org.thingsboard.rule.engine.metadata.TbGetTelemetryNodeConfigurati name = "originator telemetry", configClazz = TbGetTelemetryNodeConfiguration.class, nodeDescription = "Adds message originator telemetry for selected time range into message metadata", - nodeDetails = "The node allows you to configure fetch interval and fetch strategy. Fetch strategy section allows you to select fetch mode: First/Last/All

" + - "If selected fetch mode First rule node will retrieve the closest telemetry to the fetch interval's start.
" + - "If selected fetch mode Last rule node will retrieve the closest telemetry to the fetch interval's end.
" + - "If selected fetch mode All rule node will retrieve telemetry from the fetch interval with configurable query parameters.

" + - "Query parameters:

" + - "Data aggregation function: Min/Max/Average/Sum/Count/None. " + - "If selected aggregation function None rule node allows you to configure additional query parameters:

" + - "Order by timestamp: Ascending/Descending

" + - "Limit: Min value - 2, max value - 1000.

" + - "Other data aggregation functions useful when you need to get the aggregated telemetry data as a single value for the configured fetch interval.", + nodeDetails = "Useful when you need to get telemetry data set from the message originator for a specific time range " + + "instead of fetching just the latest telemetry or if you need to get the closest telemetry to the fetch interval start or end. " + + "Also, this node can be used for telemetry aggregation within configured fetch interval.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase") public class TbGetTelemetryNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index df1ae1b371..9fc8efe777 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -35,8 +35,8 @@ import org.thingsboard.server.common.data.util.TbPair; name = "tenant attributes", configClazz = TbGetEntityDataNodeConfiguration.class, nodeDescription = "Adds message originator tenant attributes or latest telemetry into message or message metadata", - nodeDetails = "Enriches incoming message or message metadata with the tenant's attributes or latest telemetry values. " + - "Useful when you store some parameters on the tenant level and would like to use them for message processing.", + nodeDetails = "Useful when you need to retrieve some common configuration or threshold set " + + "that is stored as tenant attributes or telemetry data and use it for further message processing.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeTenantAttributesConfig") public class TbGetTenantAttributeNode extends TbAbstractGetEntityDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index e6433b541e..fafa7bf38d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -33,9 +33,9 @@ import org.thingsboard.server.common.msg.TbMsg; @RuleNode(type = ComponentType.ENRICHMENT, name = "tenant details", configClazz = TbGetTenantDetailsNodeConfiguration.class, - nodeDescription = "Adds originator tenant details into message or message metadata", - nodeDetails = "Enriches incoming message or message metadata with the corresponding tenant details. " + - "Selected details adds to the message with predefined prefix: tenant_, Examples: tenant_title or tenant_address, etc.", + nodeDescription = "Adds message originator tenant details into message or message metadata", + nodeDetails = "Useful when we need to retrieve contact information from your tenant " + + "such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode { From cca276dcbfdfbb26e5de084aa309e2f4fd18ddfd Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 23 May 2023 16:02:25 +0300 Subject: [PATCH 067/421] added configuration version to component descriptor --- .../AnnotationComponentDiscoveryService.java | 6 ++++++ .../install/SqlDatabaseUpgradeService.java | 4 ++++ .../common/data/plugin/ComponentDescriptor.java | 17 ++++++++++++----- .../server/dao/model/ModelConstants.java | 1 + .../model/sql/ComponentDescriptorEntity.java | 5 +++++ ...ractComponentDescriptorInsertRepository.java | 1 + .../SqlComponentDescriptorInsertRepository.java | 4 ++-- dao/src/main/resources/sql/schema-entities.sql | 1 + 8 files changed, 32 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java index d4077cb9a4..ac24141dcf 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java @@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.api.NodeConfiguration; import org.thingsboard.rule.engine.api.NodeDefinition; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbVersionedNode; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -148,6 +149,11 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe scannedComponent.setType(type); Class clazz = Class.forName(clazzName); RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); + if (TbVersionedNode.class.isAssignableFrom(clazz)) { + TbVersionedNode tbVersionNode = (TbVersionedNode) clazz.getDeclaredConstructor().newInstance(); + int currentVersion = tbVersionNode.getCurrentVersion(); + scannedComponent.setConfigurationVersion(currentVersion); + } scannedComponent.setName(ruleNodeAnnotation.name()); scannedComponent.setScope(ruleNodeAnnotation.scope()); scannedComponent.setClusteringMode(ruleNodeAnnotation.clusteringMode()); diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index f2372c4f13..d94fa75f57 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -720,6 +720,10 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService if (isOldSchema(conn, 3005000)) { schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.5.0", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); + try { + conn.createStatement().execute("ALTER TABLE component_descriptor ADD COLUMN IF NOT EXISTS configuration_version int DEFAULT 0;"); + } catch (Exception e) { + } try { conn.createStatement().execute("ALTER TABLE rule_node ADD COLUMN IF NOT EXISTS configuration_version int DEFAULT 0;"); } catch (Exception e) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentDescriptor.java b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentDescriptor.java index 034311c379..a745c8e70a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentDescriptor.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentDescriptor.java @@ -25,6 +25,8 @@ import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.ComponentDescriptorId; import org.thingsboard.server.common.data.validation.Length; +import java.util.Objects; + /** * @author Andrew Shvayka */ @@ -47,8 +49,10 @@ public class ComponentDescriptor extends SearchTextBased @Getter @Setter private String clazz; @ApiModelProperty(position = 8, value = "Complex JSON object that represents the Rule Node configuration.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) @Getter @Setter private transient JsonNode configurationDescriptor; + @ApiModelProperty(position = 9, value = "Rule node configuration version. By default, this value is 0. If the rule node is a versioned node, this value might be greater than 0.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Getter @Setter private int configurationVersion; @Length(fieldName = "actions") - @ApiModelProperty(position = 9, value = "Rule Node Actions. Deprecated. Always null.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @ApiModelProperty(position = 10, value = "Rule Node Actions. Deprecated. Always null.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) @Getter @Setter private String actions; public ComponentDescriptor() { @@ -63,9 +67,11 @@ public class ComponentDescriptor extends SearchTextBased super(plugin); this.type = plugin.getType(); this.scope = plugin.getScope(); + this.clusteringMode = plugin.getClusteringMode(); this.name = plugin.getName(); this.clazz = plugin.getClazz(); this.configurationDescriptor = plugin.getConfigurationDescriptor(); + this.configurationVersion = plugin.getConfigurationVersion(); this.actions = plugin.getActions(); } @@ -98,10 +104,11 @@ public class ComponentDescriptor extends SearchTextBased if (type != that.type) return false; if (scope != that.scope) return false; - if (name != null ? !name.equals(that.name) : that.name != null) return false; - if (actions != null ? !actions.equals(that.actions) : that.actions != null) return false; - if (configurationDescriptor != null ? !configurationDescriptor.equals(that.configurationDescriptor) : that.configurationDescriptor != null) return false; - return clazz != null ? clazz.equals(that.clazz) : that.clazz == null; + if (!Objects.equals(name, that.name)) return false; + if (!Objects.equals(actions, that.actions)) return false; + if (!Objects.equals(configurationDescriptor, that.configurationDescriptor)) return false; + if (configurationVersion != that.configurationVersion) return false; + return Objects.equals(clazz, that.clazz); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index da429c5ed5..00dcbb2545 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -337,6 +337,7 @@ public class ModelConstants { public static final String COMPONENT_DESCRIPTOR_NAME_PROPERTY = "name"; public static final String COMPONENT_DESCRIPTOR_CLASS_PROPERTY = "clazz"; public static final String COMPONENT_DESCRIPTOR_CONFIGURATION_DESCRIPTOR_PROPERTY = "configuration_descriptor"; + public static final String COMPONENT_DESCRIPTOR_CONFIGURATION_VERSION_PROPERTY = "configuration_version"; public static final String COMPONENT_DESCRIPTOR_ACTIONS_PROPERTY = "actions"; /** diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/ComponentDescriptorEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/ComponentDescriptorEntity.java index 09cabb72f1..968a49507e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/ComponentDescriptorEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/ComponentDescriptorEntity.java @@ -65,6 +65,9 @@ public class ComponentDescriptorEntity extends BaseSqlEntity Date: Tue, 23 May 2023 19:25:00 +0300 Subject: [PATCH 068/421] fix test name + moved tests from PE --- ...titiesRelatedEntityIdAsyncLoaderTest.java} | 138 +++++++++++++----- 1 file changed, 100 insertions(+), 38 deletions(-) rename rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/{EntitiesRelatedEntitiesIdAsyncLoaderTest.java => EntitiesRelatedEntityIdAsyncLoaderTest.java} (57%) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesRelatedEntitiesIdAsyncLoaderTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesRelatedEntityIdAsyncLoaderTest.java similarity index 57% rename from rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesRelatedEntitiesIdAsyncLoaderTest.java rename to rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesRelatedEntityIdAsyncLoaderTest.java index fc93206c18..b29e451eaf 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesRelatedEntitiesIdAsyncLoaderTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/util/EntitiesRelatedEntityIdAsyncLoaderTest.java @@ -18,16 +18,13 @@ package org.thingsboard.rule.engine.util; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.ArgumentMatchers; import org.thingsboard.common.util.ListeningExecutor; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.data.RelationsQuery; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; @@ -36,25 +33,29 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.dao.relation.RelationService; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.Callable; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.thingsboard.common.util.DonAsynchron.withCallback; -@ExtendWith(MockitoExtension.class) -public class EntitiesRelatedEntitiesIdAsyncLoaderTest { +public class EntitiesRelatedEntityIdAsyncLoaderTest { - private static final EntityId DUMMY_ORIGINATOR = new DeviceId(UUID.randomUUID()); + private static final EntityId ASSET_ORIGINATOR_ID = new AssetId(UUID.randomUUID()); private static final TenantId TENANT_ID = new TenantId(UUID.randomUUID()); private static final ListeningExecutor DB_EXECUTOR = new ListeningExecutor() { @Override @@ -71,23 +72,34 @@ public class EntitiesRelatedEntitiesIdAsyncLoaderTest { command.run(); } }; - @Mock + private TbContext ctxMock; - @Mock private RelationService relationServiceMock; - @Test - public void givenRelationsQuery_whenFindEntityAsync_ShouldBuildCorrectEntityRelationsQuery() { - // GIVEN - var relationsQuery = new RelationsQuery(); - var relationEntityTypeFilter = new RelationEntityTypeFilter(EntityRelation.CONTAINS_TYPE, Collections.emptyList()); + private RelationsQuery relationsQuery; + + @BeforeEach + void setUp() { + ctxMock = mock(TbContext.class); + relationServiceMock = mock(RelationService.class); + when(ctxMock.getRelationService()).thenReturn(relationServiceMock); + when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + + relationsQuery = new RelationsQuery(); relationsQuery.setDirection(EntitySearchDirection.FROM); relationsQuery.setMaxLevel(1); - relationsQuery.setFilters(Collections.singletonList(relationEntityTypeFilter)); + RelationEntityTypeFilter entityTypeFilter = new RelationEntityTypeFilter( + EntityRelation.CONTAINS_TYPE, Collections.emptyList() + ); + relationsQuery.setFilters(Collections.singletonList(entityTypeFilter)); + } + @Test + public void givenRelationsQuery_whenFindEntityAsync_ShouldBuildCorrectEntityRelationsQuery() { + // GIVEN var expectedEntityRelationsQuery = new EntityRelationsQuery(); var parameters = new RelationsSearchParameters( - DUMMY_ORIGINATOR, + ASSET_ORIGINATOR_ID, relationsQuery.getDirection(), relationsQuery.getMaxLevel(), relationsQuery.isFetchLastLevelOnly() @@ -102,27 +114,19 @@ public class EntitiesRelatedEntitiesIdAsyncLoaderTest { when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); // WHEN - EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctxMock, DUMMY_ORIGINATOR, relationsQuery); + EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctxMock, ASSET_ORIGINATOR_ID, relationsQuery); // THEN verify(relationServiceMock, times(1)).findByQuery(eq(TENANT_ID), eq(expectedEntityRelationsQuery)); } + @Test public void givenSeveralEntitiesFound_whenFindEntityAsync_ShouldKeepOneAndDiscardOthers() throws Exception { // GIVEN - var relationsQuery = new RelationsQuery(); - var relationEntityTypeFilter = new RelationEntityTypeFilter( - EntityRelation.CONTAINS_TYPE, - List.of(EntityType.DEVICE, EntityType.ASSET) - ); - relationsQuery.setDirection(EntitySearchDirection.FROM); - relationsQuery.setMaxLevel(2); - relationsQuery.setFilters(Collections.singletonList(relationEntityTypeFilter)); - var expectedEntityRelationsQuery = new EntityRelationsQuery(); var parameters = new RelationsSearchParameters( - DUMMY_ORIGINATOR, + ASSET_ORIGINATOR_ID, relationsQuery.getDirection(), relationsQuery.getMaxLevel(), relationsQuery.isFetchLastLevelOnly() @@ -134,25 +138,25 @@ public class EntitiesRelatedEntitiesIdAsyncLoaderTest { device1.setName("Device 1"); var device2 = new Device(new DeviceId(UUID.randomUUID())); device1.setName("Device 2"); - var asset = new Asset(new AssetId(UUID.randomUUID())); - asset.setName("Asset"); + var device3 = new Device(new DeviceId(UUID.randomUUID())); + device3.setName("Device 3"); var entityRelationDevice1 = new EntityRelation(); - entityRelationDevice1.setFrom(DUMMY_ORIGINATOR); + entityRelationDevice1.setFrom(ASSET_ORIGINATOR_ID); entityRelationDevice1.setTo(device1.getId()); entityRelationDevice1.setType(EntityRelation.CONTAINS_TYPE); var entityRelationDevice2 = new EntityRelation(); - entityRelationDevice2.setFrom(DUMMY_ORIGINATOR); + entityRelationDevice2.setFrom(ASSET_ORIGINATOR_ID); entityRelationDevice2.setTo(device2.getId()); entityRelationDevice2.setType(EntityRelation.CONTAINS_TYPE); - var entityRelationAsset = new EntityRelation(); - entityRelationAsset.setFrom(DUMMY_ORIGINATOR); - entityRelationAsset.setTo(asset.getId()); - entityRelationAsset.setType(EntityRelation.CONTAINS_TYPE); + var entityRelationDevice3 = new EntityRelation(); + entityRelationDevice3.setFrom(ASSET_ORIGINATOR_ID); + entityRelationDevice3.setTo(device3.getId()); + entityRelationDevice3.setType(EntityRelation.CONTAINS_TYPE); - var expectedEntityRelationsList = List.of(entityRelationDevice1, entityRelationDevice2, entityRelationAsset); + var expectedEntityRelationsList = List.of(entityRelationDevice1, entityRelationDevice2, entityRelationDevice3); when(ctxMock.getTenantId()).thenReturn(TENANT_ID); when(ctxMock.getRelationService()).thenReturn(relationServiceMock); @@ -161,7 +165,7 @@ public class EntitiesRelatedEntitiesIdAsyncLoaderTest { when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); // WHEN - var deviceIdFuture = EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctxMock, DUMMY_ORIGINATOR, relationsQuery); + var deviceIdFuture = EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctxMock, ASSET_ORIGINATOR_ID, relationsQuery); // THEN assertNotNull(deviceIdFuture); @@ -171,4 +175,62 @@ public class EntitiesRelatedEntitiesIdAsyncLoaderTest { assertEquals(device1.getId(), actualDeviceId); } + + @Test + public void givenRelationQuery_whenFindEntityAsync_thenOK() { + // GIVEN + List entityRelations = new ArrayList<>(); + entityRelations.add(createEntityRelation(TENANT_ID, ASSET_ORIGINATOR_ID)); + when(relationServiceMock.findByQuery(ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(Futures.immediateFuture(entityRelations)); + + // WHEN + ListenableFuture entityIdFuture = EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctxMock, TENANT_ID, relationsQuery); + + // THEN + verifyEntityIdFuture(entityIdFuture, ASSET_ORIGINATOR_ID); + } + + @Test + public void givenRelationQuery_whenFindEntityAsync_thenReturnNull() { + // GIVEN + List entityRelations = new ArrayList<>(); + when(relationServiceMock.findByQuery(ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(Futures.immediateFuture(entityRelations)); + + // WHEN + ListenableFuture entityIdFuture = EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctxMock, TENANT_ID, relationsQuery); + + // THEN + verifyEntityIdFuture(entityIdFuture, null); + } + + @Test + public void givenRelationQuery_whenFindEntityAsync_thenFailure() { + // GIVEN + relationsQuery.setDirection(null); + List entityRelations = new ArrayList<>(); + entityRelations.add(createEntityRelation(TENANT_ID, ASSET_ORIGINATOR_ID)); + + when(relationServiceMock.findByQuery(ArgumentMatchers.any(), ArgumentMatchers.any())).thenReturn(Futures.immediateFuture(entityRelations)); + + // WHEN + ListenableFuture entityIdFuture = EntitiesRelatedEntityIdAsyncLoader.findEntityAsync(ctxMock, TENANT_ID, relationsQuery); + + // THEN + verifyEntityIdFuture(entityIdFuture, ASSET_ORIGINATOR_ID); + } + + private void verifyEntityIdFuture(ListenableFuture entityIdFuture, EntityId assetId) { + withCallback(entityIdFuture, + entityId -> assertThat(entityId).isEqualTo(assetId), + throwable -> assertThat(throwable).isInstanceOf(IllegalStateException.class), ctxMock.getDbCallbackExecutor()); + } + + private static EntityRelation createEntityRelation(EntityId from, EntityId to) { + EntityRelation relation = new EntityRelation(); + relation.setFrom(from); + relation.setTo(to); + relation.setType(EntityRelation.CONTAINS_TYPE); + relation.setTypeGroup(RelationTypeGroup.COMMON); + return relation; + } } From 5f32f9c51b4425d0dcc65fccdd58c0b23687bea0 Mon Sep 17 00:00:00 2001 From: kalytka Date: Wed, 24 May 2023 12:13:01 +0300 Subject: [PATCH 069/421] Added configurationVersion to ruleNodes --- .../modules/home/pages/rulechain/rulechain-page.component.ts | 4 ++-- ui-ngx/src/app/shared/models/rule-chain.models.ts | 2 ++ ui-ngx/src/app/shared/models/rule-node.models.ts | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index a06c06ba36..e604f3ea9e 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -78,7 +78,7 @@ import { RuleChainService } from '@core/http/rule-chain.service'; import { fromEvent, NEVER, Observable, of, ReplaySubject, Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged, mergeMap, tap } from 'rxjs/operators'; import { ISearchableComponent } from '../../models/searchable-component.models'; -import { deepClone } from '@core/utils'; +import { deepClone, isDefinedAndNotNull } from '@core/utils'; import { RuleNodeDetailsComponent } from '@home/pages/rulechain/rule-node-details.component'; import { RuleNodeLinkComponent } from './rule-node-link.component'; import { DialogComponent } from '@shared/components/dialog.component'; @@ -1425,7 +1425,7 @@ export class RuleChainPageComponent extends PageComponent id: node.ruleNodeId, type: node.component.clazz, name: node.name, - configurationVersion: node.configurationVersion, + configurationVersion: isDefinedAndNotNull(node.configurationVersion) ? node.configurationVersion : node.component.configurationVersion, configuration: node.configuration, additionalInfo: node.additionalInfo ? node.additionalInfo : {}, debugMode: node.debugMode, diff --git a/ui-ngx/src/app/shared/models/rule-chain.models.ts b/ui-ngx/src/app/shared/models/rule-chain.models.ts index fbf6f57268..85dcbf3a6e 100644 --- a/ui-ngx/src/app/shared/models/rule-chain.models.ts +++ b/ui-ngx/src/app/shared/models/rule-chain.models.ts @@ -65,6 +65,7 @@ export const unknownNodeComponent: RuleNodeComponentDescriptor = { type: RuleNodeType.UNKNOWN, name: 'unknown', clusteringMode: ComponentClusteringMode.ENABLED, + configurationVersion: 0, clazz: 'tb.internal.Unknown', configurationDescriptor: { nodeDefinition: { @@ -81,6 +82,7 @@ export const unknownNodeComponent: RuleNodeComponentDescriptor = { export const inputNodeComponent: RuleNodeComponentDescriptor = { type: RuleNodeType.INPUT, + configurationVersion: 0, clusteringMode: ComponentClusteringMode.ENABLED, name: 'Input', clazz: 'tb.internal.Input' diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index 19d4a24a9d..d4688546d7 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -305,6 +305,7 @@ export const ruleNodeTypeDescriptors = new Map Date: Wed, 24 May 2023 15:07:56 +0300 Subject: [PATCH 070/421] Refactoring --- .../modules/home/pages/rulechain/rulechain-page.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index e604f3ea9e..c57b99d855 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -555,7 +555,7 @@ export class RuleChainPageComponent extends PageComponent ruleNodeId: ruleNode.id, additionalInfo: ruleNode.additionalInfo, configuration: ruleNode.configuration, - configurationVersion: ruleNode.configurationVersion, + configurationVersion: isDefinedAndNotNull(ruleNode.configurationVersion) ? ruleNode.configurationVersion : 0, debugMode: ruleNode.debugMode, singletonMode: ruleNode.singletonMode, x: Math.round(ruleNode.additionalInfo.layoutX), From d9e4102ee382534ec5ad216aab3244583a6fe185 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 24 May 2023 16:03:06 +0300 Subject: [PATCH 071/421] updated upgrade tests for versioned nodes --- .../engine/metadata/TbFetchDeviceCredentialsNodeTest.java | 4 ++-- .../rule/engine/metadata/TbGetAttributesNodeTest.java | 4 ++-- .../rule/engine/metadata/TbGetCustomerAttributeNodeTest.java | 4 ++-- .../rule/engine/metadata/TbGetCustomerDetailsNodeTest.java | 4 ++-- .../rule/engine/metadata/TbGetDeviceAttrNodeTest.java | 4 ++-- .../rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java | 4 ++-- .../rule/engine/metadata/TbGetRelatedAttributeNodeTest.java | 4 ++-- .../rule/engine/metadata/TbGetTenantAttributeNodeTest.java | 4 ++-- .../rule/engine/metadata/TbGetTenantDetailsNodeTest.java | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java index 353317a1a3..4c9d138236 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java @@ -154,12 +154,12 @@ public class TbFetchDeviceCredentialsNodeTest { } @Test - void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception { + void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { String oldConfig = "{\"fetchToMetadata\":true}"; JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); TbPair upgrade = node.upgrade(0, configJson); assertTrue(upgrade.getFirst()); - assertEquals(JacksonUtil.valueToTree(config), upgrade.getSecond()); + assertEquals(config, JacksonUtil.treeToValue(upgrade.getSecond(), config.getClass())); } private TbMsg getTbMsg(EntityId entityId) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java index 52f11cd4a8..5146f2f1e9 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java @@ -251,7 +251,7 @@ public class TbGetAttributesNodeTest { } @Test - public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception { + public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { var defaultConfig = new TbGetAttributesNodeConfiguration().defaultConfiguration(); var node = new TbGetAttributesNode(); String oldConfig = "{\"fetchToData\":false," + @@ -264,7 +264,7 @@ public class TbGetAttributesNodeTest { JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); TbPair upgrade = node.upgrade(0, configJson); Assertions.assertTrue(upgrade.getFirst()); - Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond()); + Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass())); } private TbMsg checkMsg(boolean checkSuccess) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index e1b799552c..156c3f03d7 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -455,14 +455,14 @@ public class TbGetCustomerAttributeNodeTest { } @Test - public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception { + public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { var defaultConfig = new TbGetEntityDataNodeConfiguration().defaultConfiguration(); var node = new TbGetCustomerAttributeNode(); String oldConfig = "{\"attrMapping\":{\"alarmThreshold\":\"threshold\"},\"telemetry\":false}"; JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); TbPair upgrade = node.upgrade(0, configJson); Assertions.assertTrue(upgrade.getFirst()); - Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond()); + Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass())); } private void prepareMsgAndConfig(FetchTo fetchTo, DataToFetch dataToFetch, EntityId originator) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java index bfbfd83051..2830dddaeb 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java @@ -448,14 +448,14 @@ public class TbGetCustomerDetailsNodeTest { } @Test - public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception { + public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { var defaultConfig = new TbGetCustomerDetailsNodeConfiguration().defaultConfiguration(); var node = new TbGetCustomerDetailsNode(); String oldConfig = "{\"detailsList\":[],\"addToMetadata\":false}"; JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); TbPair upgrade = node.upgrade(0, configJson); Assertions.assertTrue(upgrade.getFirst()); - Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond()); + Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass())); } private void prepareMsgAndConfig(FetchTo fetchTo, List detailsList, EntityId originator) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeTest.java index c7d5e1c0c3..82e24226f5 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNodeTest.java @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.util.TbPair; public class TbGetDeviceAttrNodeTest { @Test - public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception { + public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { var defaultConfig = new TbGetDeviceAttrNodeConfiguration().defaultConfiguration(); var node = new TbGetDeviceAttrNode(); String oldConfig = "{\"fetchToData\":false," + @@ -39,7 +39,7 @@ public class TbGetDeviceAttrNodeTest { JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); TbPair upgrade = node.upgrade(0, configJson); Assertions.assertTrue(upgrade.getFirst()); - Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond()); + Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass())); } } \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java index 45f42a95a7..4f03fe54c0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java @@ -344,14 +344,14 @@ public class TbGetOriginatorFieldsNodeTest { } @Test - public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception { + public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { var defaultConfig = new TbGetOriginatorFieldsConfiguration().defaultConfiguration(); var node = new TbGetOriginatorFieldsNode(); String oldConfig = "{\"fieldsMapping\":{\"name\":\"originatorName\",\"type\":\"originatorType\"},\"ignoreNullStrings\":false}"; JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); TbPair upgrade = node.upgrade(0, configJson); Assertions.assertTrue(upgrade.getFirst()); - Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond()); + Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass())); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index b222e11d20..23ceb082bc 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -569,7 +569,7 @@ public class TbGetRelatedAttributeNodeTest { } @Test - public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception { + public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { var defaultConfig = new TbGetRelatedDataNodeConfiguration().defaultConfiguration(); var node = new TbGetRelatedAttributeNode(); String oldConfig = "{\"attrMapping\":{\"serialNumber\":\"sn\"}," + @@ -580,7 +580,7 @@ public class TbGetRelatedAttributeNodeTest { JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); TbPair upgrade = node.upgrade(0, configJson); Assertions.assertTrue(upgrade.getFirst()); - Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond()); + Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass())); } private void prepareMsgAndConfig(FetchTo fetchTo, DataToFetch dataToFetch, EntityId originator) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index 855adea614..d8532247ae 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -385,14 +385,14 @@ public class TbGetTenantAttributeNodeTest { } @Test - public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception { + public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { var defaultConfig = new TbGetEntityDataNodeConfiguration().defaultConfiguration(); var node = new TbGetTenantAttributeNode(); String oldConfig = "{\"attrMapping\":{\"alarmThreshold\":\"threshold\"},\"telemetry\":false}"; JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); TbPair upgrade = node.upgrade(0, configJson); Assertions.assertTrue(upgrade.getFirst()); - Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond()); + Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass())); } private void prepareMsgAndConfig(FetchTo fetchTo, DataToFetch dataToFetch, EntityId originator) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java index 87e933f5bd..6e1e619eab 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java @@ -263,14 +263,14 @@ public class TbGetTenantDetailsNodeTest { } @Test - public void givenOldConfig_whenUpgrade_thenShouldReturnSuccessResult() throws Exception { + public void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { var defaultConfig = new TbGetTenantDetailsNodeConfiguration().defaultConfiguration(); var node = new TbGetTenantDetailsNode(); String oldConfig = "{\"detailsList\":[],\"addToMetadata\":false}"; JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); TbPair upgrade = node.upgrade(0, configJson); Assertions.assertTrue(upgrade.getFirst()); - Assertions.assertEquals(JacksonUtil.valueToTree(defaultConfig), upgrade.getSecond()); + Assertions.assertEquals(defaultConfig, JacksonUtil.treeToValue(upgrade.getSecond(), defaultConfig.getClass())); } private void prepareMsgAndConfig(FetchTo fetchTo, List detailsList) { From 64a3c6402dcfb671336de9ee4b9923a50f5d11e0 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 25 May 2023 12:39:39 +0300 Subject: [PATCH 072/421] Execute update of the rule nodes on each upgrade of the system --- .../server/install/ThingsboardInstallService.java | 1 + .../server/service/install/update/DataUpdateService.java | 1 + .../service/install/update/DefaultDataUpdateService.java | 8 ++++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 1821d35d36..9ce5356d02 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -268,6 +268,7 @@ public class ThingsboardInstallService { entityDatabaseSchemaService.createOrUpdateViewsAndFunctions(); entityDatabaseSchemaService.createOrUpdateDeviceInfoView(persistToTelemetry); log.info("Updating system data..."); + dataUpdateService.upgradeRuleNodes(); systemDataLoaderService.updateSystemWidgets(); installScripts.loadSystemLwm2mResources(); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DataUpdateService.java index ae573b829a..289e3b1c94 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DataUpdateService.java @@ -19,4 +19,5 @@ public interface DataUpdateService { void updateData(String fromVersion) throws Exception; + void upgradeRuleNodes(); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 2c63b9987d..d0f3bbdeb3 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -209,16 +209,16 @@ public class DefaultDataUpdateService implements DataUpdateService { log.info("Skipping edge events migration"); } break; - case "3.5.0": - log.info("Updating data from version 3.5.0 to 3.5.1 ..."); - upgradeRuleNodes(); + case "3.5.1": + log.info("Updating data from version 3.5.1 to 3.5.2 ..."); break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } } - private void upgradeRuleNodes() { + @Override + public void upgradeRuleNodes() { try { log.info("Lookup rule nodes to upgrade ..."); var nodeClassToVersionMap = getNodeClassToVersionMap(); From dc483ee0a2f66d0be76ed2274c69d2ac902b89fa Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 25 May 2023 13:16:43 +0300 Subject: [PATCH 073/421] Changed method for removing relations from all to removing only COMMON relations --- .../controller/EntityRelationController.java | 2 +- .../DefaultTbEntityRelationService.java | 4 ++-- .../relation/TbEntityRelationService.java | 2 +- .../server/dao/relation/RelationService.java | 2 ++ .../dao/relation/BaseRelationService.java | 22 +++++++++++++++++-- .../dao/service/BaseRelationServiceTest.java | 18 +++++++++++++++ 6 files changed, 44 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index 08448f1d28..788b48360d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -129,7 +129,7 @@ public class EntityRelationController extends BaseController { checkParameter("entityType", strType); EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId); checkEntityId(entityId, Operation.WRITE); - tbEntityRelationService.deleteRelations(getTenantId(), getCurrentUser().getCustomerId(), entityId, getCurrentUser()); + tbEntityRelationService.deleteCommonRelations(getTenantId(), getCurrentUser().getCustomerId(), entityId, getCurrentUser()); } @ApiOperation(value = "Get Relation (getRelation)", diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java index b978b730fd..cf1733490d 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java @@ -72,9 +72,9 @@ public class DefaultTbEntityRelationService extends AbstractTbEntityService impl } @Override - public void deleteRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException { + public void deleteCommonRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException { try { - relationService.deleteEntityRelations(tenantId, entityId); + relationService.deleteEntityCommonRelations(tenantId, entityId); notificationEntityService.logEntityAction(tenantId, entityId, null, customerId, ActionType.RELATIONS_DELETED, user); } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, entityId, null, customerId, diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java index 2caee86d0c..8bf5018c95 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/TbEntityRelationService.java @@ -28,6 +28,6 @@ public interface TbEntityRelationService { void delete(TenantId tenantId, CustomerId customerId, EntityRelation entity, User user) throws ThingsboardException; - void deleteRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException; + void deleteCommonRelations(TenantId tenantId, CustomerId customerId, EntityId entityId, User user) throws ThingsboardException; } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java index 3ddb6187ea..39e94b3a6b 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java @@ -53,6 +53,8 @@ public interface RelationService { void deleteEntityRelations(TenantId tenantId, EntityId entity); + void deleteEntityCommonRelations(TenantId tenantId, EntityId entity); + List findByFrom(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup); ListenableFuture> findByFromAsync(TenantId tenantId, EntityId from, RelationTypeGroup typeGroup); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index fb86e09ab3..b0d5fb3c2c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -220,13 +220,31 @@ public class BaseRelationService implements RelationService { return future; } + @Transactional + @Override + public void deleteEntityCommonRelations(TenantId tenantId, EntityId entityId) { + deleteEntityRelations(tenantId, entityId, RelationTypeGroup.COMMON); + } + @Transactional @Override public void deleteEntityRelations(TenantId tenantId, EntityId entityId) { + deleteEntityRelations(tenantId, entityId, null); + } + + @Transactional + public void deleteEntityRelations(TenantId tenantId, EntityId entityId, RelationTypeGroup relationTypeGroup) { log.trace("Executing deleteEntityRelations [{}]", entityId); validate(entityId); - List inboundRelations = new ArrayList<>(relationDao.findAllByTo(tenantId, entityId)); - List outboundRelations = new ArrayList<>(relationDao.findAllByFrom(tenantId, entityId)); + List inboundRelations; + List outboundRelations; + if (relationTypeGroup == null) { + inboundRelations = relationDao.findAllByTo(tenantId, entityId); + outboundRelations = relationDao.findAllByFrom(tenantId, entityId); + } else { + inboundRelations = relationDao.findAllByFrom(tenantId, entityId, relationTypeGroup); + outboundRelations = relationDao.findAllByTo(tenantId, entityId, relationTypeGroup); + } if (!inboundRelations.isEmpty()) { try { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java index d60a896aec..ae07930156 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java @@ -130,6 +130,24 @@ public abstract class BaseRelationServiceTest extends AbstractServiceTest { Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); } + @Test + public void testDeleteEntityCommonRelations() { + AssetId parentId = new AssetId(Uuids.timeBased()); + AssetId childId = new AssetId(Uuids.timeBased()); + AssetId subChildId = new AssetId(Uuids.timeBased()); + + EntityRelation relationA = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE); + EntityRelation relationB = new EntityRelation(childId, subChildId, EntityRelation.CONTAINS_TYPE); + + saveRelation(relationA); + saveRelation(relationB); + + relationService.deleteEntityCommonRelations(SYSTEM_TENANT_ID, childId); + + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); + } + @Test public void testFindFrom() throws ExecutionException, InterruptedException { AssetId parentA = new AssetId(Uuids.timeBased()); From c9f5654e082b0f22ffa34387892428903eadde5d Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 25 May 2023 16:05:25 +0300 Subject: [PATCH 074/421] Added additional methods to dao to remove only required relations --- .../dao/relation/BaseRelationService.java | 27 +++++++++++-------- .../server/dao/relation/RelationDao.java | 4 +++ .../dao/sql/relation/JpaRelationDao.java | 23 +++++++++++++--- .../dao/sql/relation/RelationRepository.java | 5 ++++ .../dao/service/BaseRelationServiceTest.java | 7 +++++ 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index b0d5fb3c2c..f7ae4a1596 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -236,19 +236,20 @@ public class BaseRelationService implements RelationService { public void deleteEntityRelations(TenantId tenantId, EntityId entityId, RelationTypeGroup relationTypeGroup) { log.trace("Executing deleteEntityRelations [{}]", entityId); validate(entityId); - List inboundRelations; - List outboundRelations; - if (relationTypeGroup == null) { - inboundRelations = relationDao.findAllByTo(tenantId, entityId); - outboundRelations = relationDao.findAllByFrom(tenantId, entityId); - } else { - inboundRelations = relationDao.findAllByFrom(tenantId, entityId, relationTypeGroup); - outboundRelations = relationDao.findAllByTo(tenantId, entityId, relationTypeGroup); - } + List inboundRelations = relationTypeGroup == null + ? relationDao.findAllByTo(tenantId, entityId) + : relationDao.findAllByTo(tenantId, entityId, relationTypeGroup); + List outboundRelations = relationTypeGroup == null + ? relationDao.findAllByFrom(tenantId, entityId) + : relationDao.findAllByFrom(tenantId, entityId, relationTypeGroup); if (!inboundRelations.isEmpty()) { try { - relationDao.deleteInboundRelations(tenantId, entityId); + if (relationTypeGroup == null) { + relationDao.deleteInboundRelations(tenantId, entityId); + } else { + relationDao.deleteInboundRelations(tenantId, entityId, relationTypeGroup); + } } catch (ConcurrencyFailureException e) { log.debug("Concurrency exception while deleting relations [{}]", inboundRelations, e); } @@ -259,7 +260,11 @@ public class BaseRelationService implements RelationService { } if (!outboundRelations.isEmpty()) { - relationDao.deleteOutboundRelations(tenantId, entityId); + if (relationTypeGroup == null) { + relationDao.deleteOutboundRelations(tenantId, entityId); + } else { + relationDao.deleteOutboundRelations(tenantId, entityId, relationTypeGroup); + } for (EntityRelation relation : outboundRelations) { eventPublisher.publishEvent(EntityRelationEvent.from(relation)); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java index 7fee4a31ff..250a0c6105 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java @@ -64,8 +64,12 @@ public interface RelationDao { void deleteOutboundRelations(TenantId tenantId, EntityId entity); + void deleteOutboundRelations(TenantId tenantId, EntityId entity, RelationTypeGroup relationTypeGroup); + void deleteInboundRelations(TenantId tenantId, EntityId entity); + void deleteInboundRelations(TenantId tenantId, EntityId entity, RelationTypeGroup relationTypeGroup); + ListenableFuture deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity); List findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index c1b17f160e..7e4b41702e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -34,10 +34,7 @@ import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService; import org.thingsboard.server.dao.util.SqlDao; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; /** @@ -205,6 +202,15 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple } } + @Override + public void deleteOutboundRelations(TenantId tenantId, EntityId entity, RelationTypeGroup relationTypeGroup) { + try { + relationRepository.deleteByFromIdAndFromTypeAndRelationTypeGroupIn(entity.getId(), entity.getEntityType().name(), Collections.singletonList(relationTypeGroup.name())); + } catch (ConcurrencyFailureException e) { + log.debug("Concurrency exception while deleting relations [{}]", entity, e); + } + } + @Override public void deleteInboundRelations(TenantId tenantId, EntityId entity) { try { @@ -214,6 +220,15 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple } } + @Override + public void deleteInboundRelations(TenantId tenantId, EntityId entity, RelationTypeGroup relationTypeGroup) { + try { + relationRepository.deleteByToIdAndToTypeAndRelationTypeGroupIn(entity.getId(), entity.getEntityType().name(), Collections.singletonList(relationTypeGroup.name())); + } catch (ConcurrencyFailureException e) { + log.debug("Concurrency exception while deleting relations [{}]", entity, e); + } + } + @Override public ListenableFuture deleteOutboundRelationsAsync(TenantId tenantId, EntityId entity) { return service.submit( diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java index a3d6d8570d..10c8c826eb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java @@ -82,4 +82,9 @@ public interface RelationRepository @Query("DELETE FROM RelationEntity r where r.toId = :toId and r.toType = :toType and r.relationTypeGroup in :relationTypeGroups") void deleteByToIdAndToTypeAndRelationTypeGroupIn(@Param("toId") UUID toId, @Param("toType") String toType, @Param("relationTypeGroups") List relationTypeGroups); + @Transactional + @Modifying + @Query("DELETE FROM RelationEntity r where r.fromId = :fromId and r.fromType = :fromType and r.relationTypeGroup in :relationTypeGroups") + void deleteByFromIdAndFromTypeAndRelationTypeGroupIn(@Param("fromId") UUID fromId, @Param("fromType") String fromType, @Param("relationTypeGroups") List relationTypeGroups); + } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java index ae07930156..afd42c5ab8 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java @@ -138,14 +138,21 @@ public abstract class BaseRelationServiceTest extends AbstractServiceTest { EntityRelation relationA = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE); EntityRelation relationB = new EntityRelation(childId, subChildId, EntityRelation.CONTAINS_TYPE); + EntityRelation relationC = new EntityRelation(parentId, childId, EntityRelation.MANAGES_TYPE, RelationTypeGroup.EDGE); + EntityRelation relationD = new EntityRelation(childId, subChildId, EntityRelation.MANAGES_TYPE, RelationTypeGroup.EDGE); saveRelation(relationA); saveRelation(relationB); + saveRelation(relationC); + saveRelation(relationD); relationService.deleteEntityCommonRelations(SYSTEM_TENANT_ID, childId); Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); + + Assert.assertTrue(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.MANAGES_TYPE, RelationTypeGroup.EDGE)); + Assert.assertTrue(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.MANAGES_TYPE, RelationTypeGroup.EDGE)); } @Test From 91aca058554615f58de5a72447b921ef565a6c91 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 25 May 2023 17:00:24 +0300 Subject: [PATCH 075/421] Imports --- .../thingsboard/server/dao/sql/relation/JpaRelationDao.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 7e4b41702e..31125a0791 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -34,7 +34,11 @@ import org.thingsboard.server.dao.relation.RelationDao; import org.thingsboard.server.dao.sql.JpaAbstractDaoListeningExecutorService; import org.thingsboard.server.dao.util.SqlDao; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.stream.Collectors; /** From adcf23cabbff4f98e53953ff3cab2aed1e5e4e04 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 25 May 2023 17:13:59 +0300 Subject: [PATCH 076/421] Improved the procedure of rule node update --- .../server/ThingsboardInstallApplication.java | 1 - .../controller/RuleChainController.java | 2 +- .../bean/AnnotationBeanDiscoveryService.java | 45 ---------- .../AnnotationComponentDiscoveryService.java | 87 +++++++++++++------ .../component/ComponentDiscoveryService.java | 6 ++ .../RuleNodeClassInfo.java} | 25 ++++-- .../service/install/InstallScripts.java | 3 +- .../update/DefaultDataUpdateService.java | 36 ++------ .../rule/DefaultTbRuleChainService.java | 50 ++++++++++- .../service/rule/TbRuleChainService.java | 3 + .../impl/RuleChainImportService.java | 4 +- .../controller/RuleChainControllerTest.java | 12 +-- ...AbstractRuleEngineFlowIntegrationTest.java | 5 ++ ...actRuleEngineLifecycleIntegrationTest.java | 2 + .../sync/ie/BaseExportImportServiceTest.java | 9 +- .../server/dao/rule/RuleChainService.java | 5 +- .../server/dao/rule/BaseRuleChainService.java | 40 ++------- .../server/dao/service/EdgeServiceTest.java | 3 +- .../dao/service/RuleChainServiceTest.java | 9 +- .../thingsboard/rule/engine/api/RuleNode.java | 2 + .../rule/engine/api/TbVersionedNode.java | 2 - .../metadata/TbAbstractNodeWithFetchTo.java | 5 -- .../TbFetchDeviceCredentialsNode.java | 1 + .../engine/metadata/TbGetAttributesNode.java | 1 + .../metadata/TbGetCustomerAttributeNode.java | 1 + .../metadata/TbGetCustomerDetailsNode.java | 1 + .../engine/metadata/TbGetDeviceAttrNode.java | 1 + .../metadata/TbGetOriginatorFieldsNode.java | 1 + .../metadata/TbGetRelatedAttributeNode.java | 1 + .../metadata/TbGetTenantAttributeNode.java | 1 + .../metadata/TbGetTenantDetailsNode.java | 1 + 31 files changed, 198 insertions(+), 167 deletions(-) delete mode 100644 application/src/main/java/org/thingsboard/server/service/bean/AnnotationBeanDiscoveryService.java rename application/src/main/java/org/thingsboard/server/service/{bean/BeanDiscoveryService.java => component/RuleNodeClassInfo.java} (55%) diff --git a/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java b/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java index b99674f416..b780f0e8cd 100644 --- a/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java +++ b/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java @@ -27,7 +27,6 @@ import java.util.Arrays; @Slf4j @SpringBootConfiguration @ComponentScan({"org.thingsboard.server.install", - "org.thingsboard.server.service.bean", "org.thingsboard.server.service.component", "org.thingsboard.server.service.install", "org.thingsboard.server.service.security.auth.jwt.settings", diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java index 50abb3de1d..e43a365cf8 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -460,7 +460,7 @@ public class RuleChainController extends BaseController { @ApiParam(value = "Enables overwrite for existing rule chains with the same name.") @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { TenantId tenantId = getCurrentUser().getTenantId(); - List importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, overwrite); + List importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, overwrite, tbRuleChainService::updateRuleNodeConfiguration); for (RuleChainImportResult importResult : importResults) { if (importResult.getError() == null) { tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(), diff --git a/application/src/main/java/org/thingsboard/server/service/bean/AnnotationBeanDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/bean/AnnotationBeanDiscoveryService.java deleted file mode 100644 index 3ee1c14540..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/bean/AnnotationBeanDiscoveryService.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright © 2016-2023 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.service.bean; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.stereotype.Service; - -import java.lang.annotation.Annotation; -import java.util.HashSet; -import java.util.Set; - -@Service -public class AnnotationBeanDiscoveryService implements BeanDiscoveryService { - - @Value("${plugins.scan_packages}") - private String[] scanPackages; - - @Override - public Set discoverBeansByAnnotationType(Class annotationType) { - ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); - scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType)); - Set defs = new HashSet<>(); - for (String scanPackage : scanPackages) { - defs.addAll(scanner.findCandidateComponents(scanPackage)); - } - return defs; - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java index ac24141dcf..ad65ee805b 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java @@ -19,9 +19,12 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.env.Environment; import org.springframework.core.env.Profiles; +import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.NodeConfiguration; @@ -34,17 +37,19 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.dao.component.ComponentDescriptorService; -import org.thingsboard.server.service.bean.BeanDiscoveryService; import javax.annotation.PostConstruct; +import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; @Service @Slf4j @@ -52,20 +57,22 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe public static final int MAX_OPTIMISITC_RETRIES = 3; + @Value("${plugins.scan_packages}") + private String[] scanPackages; + @Autowired private Environment environment; - @Autowired(required = false) - private BeanDiscoveryService beanDiscoveryService; - @Autowired private ComponentDescriptorService componentDescriptorService; - private Map components = new HashMap<>(); + private final Map ruleNodeClasses = new HashMap<>(); + + private final Map components = new HashMap<>(); - private Map> coreComponentsMap = new HashMap<>(); + private final Map> coreComponentsMap = new HashMap<>(); - private Map> edgeComponentsMap = new HashMap<>(); + private final Map> edgeComponentsMap = new HashMap<>(); private boolean isInstall() { return environment.acceptsProfiles(Profiles.of("install")); @@ -73,28 +80,62 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe @PostConstruct public void init() { + for (var def : discoverBeansByAnnotationType(RuleNode.class)) { + String clazzName = def.getBeanClassName(); + try { + var clazz = Class.forName(clazzName); + RuleNode annotation = clazz.getAnnotation(RuleNode.class); + boolean versioned = false; + if (annotation.version() > 0) { // No need to process nodes that has version = 0; + if (TbVersionedNode.class.isAssignableFrom(clazz)) { + versioned = true; + } else { + log.error("RuleNode [{}] has version {} but does not implement TbVersionedNode interface! Any update procedures for this rule node will be skipped!", clazzName, annotation.version()); + } + } + ruleNodeClasses.put(clazzName, new RuleNodeClassInfo(clazz, annotation, versioned)); + } catch (Exception e) { + log.warn("Failed to create instance of rule node type: {} due to: ", clazzName, e); + } + } if (!isInstall()) { discoverComponents(); } } + private Set discoverBeansByAnnotationType(Class annotationType) { + ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType)); + Set defs = new HashSet<>(); + for (String scanPackage : scanPackages) { + defs.addAll(scanner.findCandidateComponents(scanPackage)); + } + return defs; + } + + @Override + public Optional getRuleNodeInfo(String clazz) { + return Optional.ofNullable(ruleNodeClasses.get(clazz)); + } + + @Override + public List getVersionedNodes() { + return ruleNodeClasses.values().stream().filter(RuleNodeClassInfo::isVersioned).collect(Collectors.toList()); + } + private void registerRuleNodeComponents() { - Set ruleNodeBeanDefinitions = beanDiscoveryService.discoverBeansByAnnotationType(RuleNode.class); - for (BeanDefinition def : ruleNodeBeanDefinitions) { + for (RuleNodeClassInfo def : ruleNodeClasses.values()) { int retryCount = 0; Exception cause = null; while (retryCount < MAX_OPTIMISITC_RETRIES) { try { - String clazzName = def.getBeanClassName(); - Class clazz = Class.forName(clazzName); - RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); - ComponentType type = ruleNodeAnnotation.type(); + ComponentType type = def.getAnnotation().type(); ComponentDescriptor component = scanAndPersistComponent(def, type); components.put(component.getClazz(), component); - putComponentIntoMaps(type, ruleNodeAnnotation, component); + putComponentIntoMaps(type, def.getAnnotation(), component); break; } catch (Exception e) { - log.trace("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e); + log.trace("Can't initialize component {}, due to {}", def.getClassName(), e.getMessage(), e); cause = e; retryCount++; try { @@ -105,7 +146,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe } } if (cause != null && retryCount == MAX_OPTIMISITC_RETRIES) { - log.error("Can't initialize component {}, due to {}", def.getBeanClassName(), cause.getMessage(), cause); + log.error("Can't initialize component {}, due to {}", def.getClassName(), cause.getMessage(), cause); throw new RuntimeException(cause); } } @@ -142,18 +183,14 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe return false; } - private ComponentDescriptor scanAndPersistComponent(BeanDefinition def, ComponentType type) { + private ComponentDescriptor scanAndPersistComponent(RuleNodeClassInfo def, ComponentType type) { ComponentDescriptor scannedComponent = new ComponentDescriptor(); - String clazzName = def.getBeanClassName(); + String clazzName = def.getClassName(); try { scannedComponent.setType(type); - Class clazz = Class.forName(clazzName); + Class clazz = def.getClazz(); RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); - if (TbVersionedNode.class.isAssignableFrom(clazz)) { - TbVersionedNode tbVersionNode = (TbVersionedNode) clazz.getDeclaredConstructor().newInstance(); - int currentVersion = tbVersionNode.getCurrentVersion(); - scannedComponent.setConfigurationVersion(currentVersion); - } + scannedComponent.setConfigurationVersion(def.isVersioned() ? def.getCurrentVersion() : 0); scannedComponent.setName(ruleNodeAnnotation.name()); scannedComponent.setScope(ruleNodeAnnotation.scope()); scannedComponent.setClusteringMode(ruleNodeAnnotation.clusteringMode()); @@ -165,7 +202,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe scannedComponent.setClazz(clazzName); log.debug("Processing scanned component: {}", scannedComponent); } catch (Exception e) { - log.error("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e); + log.error("Can't initialize component {}, due to {}", clazzName, e.getMessage(), e); throw new RuntimeException(e); } ComponentDescriptor persistedComponent = componentDescriptorService.findByClazz(TenantId.SYS_TENANT_ID, clazzName); diff --git a/application/src/main/java/org/thingsboard/server/service/component/ComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/ComponentDiscoveryService.java index 731009575d..d0b0804f9b 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/ComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/ComponentDiscoveryService.java @@ -19,7 +19,9 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.rule.RuleChainType; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -30,6 +32,10 @@ public interface ComponentDiscoveryService { void discoverComponents(); + Optional getRuleNodeInfo(String clazz); + + List getVersionedNodes(); + List getComponents(ComponentType type, RuleChainType ruleChainType); List getComponents(Set types, RuleChainType ruleChainType); diff --git a/application/src/main/java/org/thingsboard/server/service/bean/BeanDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/RuleNodeClassInfo.java similarity index 55% rename from application/src/main/java/org/thingsboard/server/service/bean/BeanDiscoveryService.java rename to application/src/main/java/org/thingsboard/server/service/component/RuleNodeClassInfo.java index 5ca615a94d..56fd367820 100644 --- a/application/src/main/java/org/thingsboard/server/service/bean/BeanDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/RuleNodeClassInfo.java @@ -13,15 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.service.bean; +package org.thingsboard.server.service.component; -import org.springframework.beans.factory.config.BeanDefinition; +import lombok.Data; +import org.thingsboard.rule.engine.api.RuleNode; -import java.lang.annotation.Annotation; -import java.util.Set; +@Data +public class RuleNodeClassInfo { -public interface BeanDiscoveryService { + private final Class clazz; + private final RuleNode annotation; + private final boolean versioned; - Set discoverBeansByAnnotationType(Class annotationType); + public String getClassName(){ + return clazz.getName(); + } + + public String getSimpleName() { + return clazz.getSimpleName(); + } + + public int getCurrentVersion() { + return annotation.version(); + } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java index 9a810aa446..36ec2b9b78 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java +++ b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java @@ -48,6 +48,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Base64; import java.util.Optional; +import java.util.function.Function; import static org.thingsboard.server.utils.LwM2mObjectModelUtils.toLwm2mResource; @@ -173,7 +174,7 @@ public class InstallScripts { ruleChain = ruleChainService.saveRuleChain(ruleChain); ruleChainMetaData.setRuleChainId(ruleChain.getId()); - ruleChainService.saveRuleChainMetaData(TenantId.SYS_TENANT_ID, ruleChainMetaData); + ruleChainService.saveRuleChainMetaData(TenantId.SYS_TENANT_ID, ruleChainMetaData, Function.identity()); return ruleChain; } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index d0f3bbdeb3..f832b04c21 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -81,7 +81,7 @@ import org.thingsboard.server.dao.sql.device.DeviceProfileRepository; import org.thingsboard.server.dao.tenant.TenantProfileService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.service.bean.BeanDiscoveryService; +import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.install.SystemDataLoaderService; @@ -92,6 +92,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.StringUtils.isBlank; @@ -139,7 +140,7 @@ public class DefaultDataUpdateService implements DataUpdateService { private QueueService queueService; @Autowired - private BeanDiscoveryService beanDiscoveryService; + private ComponentDiscoveryService componentDiscoveryService; @Autowired private SystemDataLoaderService systemDataLoaderService; @@ -221,11 +222,12 @@ public class DefaultDataUpdateService implements DataUpdateService { public void upgradeRuleNodes() { try { log.info("Lookup rule nodes to upgrade ..."); - var nodeClassToVersionMap = getNodeClassToVersionMap(); + var nodeClassToVersionMap = componentDiscoveryService.getVersionedNodes(); log.info("Found {} versioned nodes to check for upgrade!", nodeClassToVersionMap.size()); - nodeClassToVersionMap.forEach((clazz, toVersion) -> { - var ruleNodeType = clazz.getName(); + nodeClassToVersionMap.forEach(clazz -> { + var ruleNodeType = clazz.getClassName(); var ruleNodeTypeForLogs = clazz.getSimpleName(); + var toVersion = clazz.getCurrentVersion(); log.info("Going to check for nodes with type: {} to upgrade to version: {}.", ruleNodeTypeForLogs, toVersion); var ruleNodesToUpdate = new PageDataIterable<>( pageLink -> ruleChainService.findAllRuleNodesByTypeAndVersionLessThan(ruleNodeType, toVersion, pageLink), 1024 @@ -240,7 +242,7 @@ public class DefaultDataUpdateService implements DataUpdateService { log.info("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion); try { - var tbVersionedNode = (TbVersionedNode) clazz.getDeclaredConstructor().newInstance(); + var tbVersionedNode = (TbVersionedNode) clazz.getClazz().getDeclaredConstructor().newInstance(); TbPair upgradeRuleNodeConfigurationResult = tbVersionedNode.upgrade(fromVersion, oldConfiguration); if (upgradeRuleNodeConfigurationResult.getFirst()) { ruleNode.setConfiguration(upgradeRuleNodeConfigurationResult.getSecond()); @@ -262,26 +264,6 @@ public class DefaultDataUpdateService implements DataUpdateService { } } - private Map, Integer> getNodeClassToVersionMap() { - var ruleNodeDefinitions = beanDiscoveryService.discoverBeansByAnnotationType( - org.thingsboard.rule.engine.api.RuleNode.class - ); - var tbVersionedNodes = new HashMap, Integer>(); - for (var def : ruleNodeDefinitions) { - String clazzName = def.getBeanClassName(); - try { - var clazz = Class.forName(clazzName); - if (TbVersionedNode.class.isAssignableFrom(clazz)) { - TbVersionedNode tbVersionedNode = (TbVersionedNode) clazz.getDeclaredConstructor().newInstance(); - tbVersionedNodes.put(clazz, tbVersionedNode.getCurrentVersion()); - } - } catch (Exception e) { - log.warn("Failed to create instance of rule node type: {} due to: ", clazzName, e); - } - } - return tbVersionedNodes; - } - private final PaginatedUpdater deviceProfileEntityDynamicConditionsUpdater = new PaginatedUpdater<>() { @@ -516,7 +498,7 @@ public class DefaultDataUpdateService implements DataUpdateService { md.getNodes().add(ruleNode); md.setFirstNodeIndex(newIdx); md.addConnectionInfo(newIdx, oldIdx, "Success"); - ruleChainService.saveRuleChainMetaData(tenant.getId(), md); + ruleChainService.saveRuleChainMetaData(tenant.getId(), md, Function.identity()); } } catch (Exception e) { log.error("[{}] Unable to update Tenant: {}", tenant.getId(), tenant.getName(), e); diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index c2e425e14a..5756101ee1 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -15,10 +15,13 @@ */ package org.thingsboard.server.service.rule; +import com.fasterxml.jackson.databind.JsonNode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbVersionedNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNode; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode; @@ -42,12 +45,13 @@ import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; +import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.install.InstallScripts; -import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; import java.util.ArrayList; import java.util.Collections; @@ -70,8 +74,7 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement private final RuleChainService ruleChainService; private final RelationService relationService; private final InstallScripts installScripts; - - private final EntitiesVersionControlService vcService; + private final ComponentDiscoveryService componentDiscoveryService; @Override public Set getRuleChainOutputLabels(TenantId tenantId, RuleChainId ruleChainId) { @@ -277,7 +280,7 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement RuleChainId ruleChainId = ruleChain.getId(); RuleChainId ruleChainMetaDataId = ruleChainMetaData.getRuleChainId(); try { - RuleChainUpdateResult result = ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData); + RuleChainUpdateResult result = ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData, this::updateRuleNodeConfiguration); checkNotNull(result.isSuccess() ? true : null); List updatedRuleChains; @@ -404,6 +407,45 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement } } + @Override + public RuleNode updateRuleNodeConfiguration(RuleNode node) { + var ruleChainId = node.getRuleChainId(); + var ruleNodeId = node.getId(); + var ruleNodeType = node.getType(); + try { + var ruleNodeClass = componentDiscoveryService.getRuleNodeInfo(ruleNodeType) + .orElseThrow(() -> new RuntimeException("Rule node " + ruleNodeType + " is not supported!")); + if (ruleNodeClass.isVersioned()) { + TbVersionedNode tbVersionedNode = (TbVersionedNode) ruleNodeClass.getClazz().getDeclaredConstructor().newInstance(); + int fromVersion = node.getConfigurationVersion(); + int toVersion = ruleNodeClass.getCurrentVersion(); + if (fromVersion < toVersion) { + log.debug("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", + ruleNodeId, ruleNodeType, fromVersion, toVersion); + try { + TbPair upgradeResult = tbVersionedNode.upgrade(fromVersion, node.getConfiguration()); + if (upgradeResult.getFirst()) { + node.setConfiguration(upgradeResult.getSecond()); + } + node.setConfigurationVersion(toVersion); + log.debug("Successfully upgrade rule node with id: {} type: {}, rule chain id: {} fromVersion: {} toVersion: {}", + ruleNodeId, ruleNodeType, ruleChainId, fromVersion, toVersion); + } catch (TbNodeException e) { + log.warn("Failed to upgrade rule node with id: {} type: {} rule chain id: {} fromVersion: {} toVersion: {} due to: ", + ruleNodeId, ruleNodeType, ruleChainId, fromVersion, toVersion, e); + } + } else { + log.debug("Rule node with id: {} type: {} ruleChainId: {} already set to latest version!", + ruleNodeId, ruleChainId, ruleNodeType); + } + } + } catch (Exception e) { + log.error("Failed to update the rule node with id: {} type: {}, rule chain id: {}", + ruleNodeId, ruleNodeType, ruleChainId, e); + } + return node; + } + private Set updateRelatedRuleChains(TenantId tenantId, RuleChainId ruleChainId, Map labelsMap) { Set updatedRuleChains = new HashSet<>(); List usageList = getOutputLabelUsage(tenantId, ruleChainId); diff --git a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java index 02b79544f4..17f1338bba 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/TbRuleChainService.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainOutputLabelsUsage; import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; +import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.service.entitiy.SimpleTbEntityService; import java.util.List; @@ -54,4 +55,6 @@ public interface TbRuleChainService extends SimpleTbEntityService { RuleChain setAutoAssignToEdgeRuleChain(TenantId tenantId, RuleChain ruleChain, User user) throws ThingsboardException; RuleChain unsetAutoAssignToEdgeRuleChain(TenantId tenantId, RuleChain ruleChain, User user) throws ThingsboardException; + + RuleNode updateRuleNodeConfiguration(RuleNode ruleNode); } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/RuleChainImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/RuleChainImportService.java index eb54fce21e..021522986d 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/RuleChainImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/RuleChainImportService.java @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.sync.ie.RuleChainExportData; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleNodeDao; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.rule.TbRuleChainService; import org.thingsboard.server.service.sync.vc.data.EntitiesImportCtx; import java.util.Arrays; @@ -52,6 +53,7 @@ public class RuleChainImportService extends BaseEntityImportService HINTS = new LinkedHashSet<>(Arrays.asList(EntityType.RULE_CHAIN, EntityType.DEVICE, EntityType.ASSET)); + private final TbRuleChainService tbRuleChainService; private final RuleChainService ruleChainService; private final RuleNodeDao ruleNodeDao; @@ -106,7 +108,7 @@ public class RuleChainImportService extends BaseEntityImportService 0); Assert.assertEquals(ruleChain.getName(), savedRuleChain.getName()); - TbVersionedNode tbVersionedNode = new TbGetRelatedAttributeNode(); - String ruleNodeType = tbVersionedNode.getClass().getName(); - int currentVersion = tbVersionedNode.getCurrentVersion(); + var annotation = TbGetRelatedAttributeNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class); + String ruleNodeType = TbGetRelatedAttributeNode.class.getName(); + int currentVersion = annotation.version(); String oldConfig = "{\"attrMapping\":{\"serialNumber\":\"sn\"}," + "\"relationsQuery\":{\"direction\":\"FROM\",\"maxLevel\":1," + "\"filters\":[{\"relationType\":\"Contains\",\"entityTypes\":[]}]," + "\"fetchLastLevelOnly\":false},\"telemetry\":false}"; - String newConfig = JacksonUtil.toString(new TbGetRelatedDataNodeConfiguration().defaultConfiguration()); + TbGetRelatedDataNodeConfiguration defaultConfiguration = new TbGetRelatedDataNodeConfiguration().defaultConfiguration(); + String newConfig = JacksonUtil.toString(defaultConfiguration); var ruleChainMetaData = createRuleChainMetadataWithTbVersionedNodes( ruleChainId, @@ -170,7 +172,7 @@ public class RuleChainControllerTest extends AbstractControllerTest { for (RuleNode ruleNode : savedRuleChainMetaData.getNodes()) { Assert.assertNotNull(ruleNode.getId()); Assert.assertEquals(currentVersion, ruleNode.getConfigurationVersion()); - Assert.assertEquals(JacksonUtil.toJsonNode(newConfig), ruleNode.getConfiguration()); + Assert.assertEquals(defaultConfiguration, JacksonUtil.treeToValue(ruleNode.getConfiguration(), defaultConfiguration.getClass())); } } diff --git a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java index f2079d5d65..6c2e5e9c5e 100644 --- a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java @@ -28,6 +28,7 @@ import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.metadata.FetchTo; +import org.thingsboard.rule.engine.metadata.TbGetAttributesNode; import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.common.data.DataConstants; @@ -138,6 +139,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule RuleNode ruleNode1 = new RuleNode(); ruleNode1.setName("Simple Rule Node 1"); ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); ruleNode1.setDebugMode(true); TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration(); configuration1.setFetchTo(FetchTo.METADATA); @@ -147,6 +149,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule RuleNode ruleNode2 = new RuleNode(); ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); ruleNode2.setDebugMode(true); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setFetchTo(FetchTo.METADATA); @@ -242,6 +245,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule RuleNode ruleNode1 = new RuleNode(); ruleNode1.setName("Simple Rule Node 1"); ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); ruleNode1.setDebugMode(true); TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration(); configuration1.setFetchTo(FetchTo.METADATA); @@ -275,6 +279,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule RuleNode ruleNode2 = new RuleNode(); ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); ruleNode2.setDebugMode(true); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setFetchTo(FetchTo.METADATA); diff --git a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java index e914511ceb..9753f06aff 100644 --- a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java @@ -25,6 +25,7 @@ import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.metadata.FetchTo; +import org.thingsboard.rule.engine.metadata.TbGetAttributesNode; import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.common.data.DataConstants; @@ -93,6 +94,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac RuleNode ruleNode = new RuleNode(); ruleNode.setName("Simple Rule Node"); ruleNode.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); ruleNode.setDebugMode(true); TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration(); configuration.setFetchTo(FetchTo.METADATA); diff --git a/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java b/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java index aa15b1da4c..39b61c6c47 100644 --- a/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sync/ie/BaseExportImportServiceTest.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.debug.TbMsgGeneratorNode; import org.thingsboard.rule.engine.debug.TbMsgGeneratorNodeConfiguration; +import org.thingsboard.rule.engine.metadata.TbGetAttributesNode; import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; @@ -86,6 +87,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collections; import java.util.UUID; +import java.util.function.Function; import static org.assertj.core.api.Assertions.assertThat; @@ -333,6 +335,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest RuleNode ruleNode2 = new RuleNode(); ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); ruleNode2.setDebugMode(true); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); @@ -341,7 +344,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2)); metaData.setFirstNodeIndex(0); metaData.addConnectionInfo(0, 1, "Success"); - ruleChainService.saveRuleChainMetaData(tenantId, metaData); + ruleChainService.saveRuleChainMetaData(tenantId, metaData, Function.identity()); return ruleChainService.findRuleChainById(tenantId, ruleChain.getId()); } @@ -361,6 +364,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest RuleNode ruleNode1 = new RuleNode(); ruleNode1.setName("Simple Rule Node 1"); ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); ruleNode1.setDebugMode(true); TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration(); configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1")); @@ -369,6 +373,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest RuleNode ruleNode2 = new RuleNode(); ruleNode2.setName("Simple Rule Node 2"); ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); ruleNode2.setDebugMode(true); TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); @@ -377,7 +382,7 @@ public abstract class BaseExportImportServiceTest extends AbstractControllerTest metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2)); metaData.setFirstNodeIndex(0); metaData.addConnectionInfo(0, 1, "Success"); - ruleChainService.saveRuleChainMetaData(tenantId, metaData); + ruleChainService.saveRuleChainMetaData(tenantId, metaData, Function.identity()); return ruleChainService.findRuleChainById(tenantId, ruleChain.getId()); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index 612be9087b..95cdc0e02d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java @@ -35,6 +35,7 @@ import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.Collection; import java.util.List; +import java.util.function.Function; /** * Created by igor on 3/12/18. @@ -45,7 +46,7 @@ public interface RuleChainService extends EntityDaoService { boolean setRootRuleChain(TenantId tenantId, RuleChainId ruleChainId); - RuleChainUpdateResult saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData); + RuleChainUpdateResult saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData, Function ruleNodeUpdater); RuleChainMetaData loadRuleChainMetaData(TenantId tenantId, RuleChainId ruleChainId); @@ -75,7 +76,7 @@ public interface RuleChainService extends EntityDaoService { RuleChainData exportTenantRuleChains(TenantId tenantId, PageLink pageLink) throws ThingsboardException; - List importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite); + List importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite, Function ruleNodeUpdater); RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 8e0789a5c1..56e6969c9a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -73,6 +73,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.DataConstants.TENANT; @@ -145,7 +146,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } @Override - public RuleChainUpdateResult saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData) { + public RuleChainUpdateResult saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData, Function ruleNodeUpdater) { Validator.validateId(ruleChainMetaData.getRuleChainId(), "Incorrect rule chain id."); RuleChain ruleChain = findRuleChainById(tenantId, ruleChainMetaData.getRuleChainId()); if (ruleChain == null) { @@ -189,38 +190,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (nodes != null) { for (RuleNode node : toAddOrUpdate) { node.setRuleChainId(ruleChainId); - String ruleNodeType = node.getType(); - RuleNodeId ruleNodeId = node.getId(); - try { - var ruleNodeClazz = Class.forName(ruleNodeType); - if (TbVersionedNode.class.isAssignableFrom(ruleNodeClazz)) { - TbVersionedNode tbVersionedNode = (TbVersionedNode) ruleNodeClazz.getDeclaredConstructor().newInstance(); - int fromVersion = node.getConfigurationVersion(); - int toVersion = tbVersionedNode.getCurrentVersion(); - if (fromVersion < toVersion) { - log.debug("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", - ruleNodeId, ruleNodeType, fromVersion, toVersion); - try { - TbPair upgradeResult = tbVersionedNode.upgrade(fromVersion, node.getConfiguration()); - if (upgradeResult.getFirst()) { - node.setConfiguration(upgradeResult.getSecond()); - } - node.setConfigurationVersion(toVersion); - log.debug("Successfully upgrade rule node with id: {} type: {}, rule chain id: {} fromVersion: {} toVersion: {}", - ruleNodeId, ruleNodeType, ruleChainId, fromVersion, toVersion); - } catch (TbNodeException e) { - log.warn("Failed to upgrade rule node with id: {} type: {} rule chain id: {} fromVersion: {} toVersion: {} due to: ", - ruleNodeId, ruleNodeType, ruleChainId, fromVersion, toVersion, e); - } - } else { - log.debug("Rule node with id: {} type: {} ruleChainId: {} already set to latest version!", - ruleNodeId, ruleChainId, ruleNodeType); - } - } - } catch (Exception e) { - log.error("Failed to create instance of rule node with id: {} type: {}, rule chain id: {}", - ruleNodeId, ruleNodeType, ruleChainId); - } + node = ruleNodeUpdater.apply(node); RuleNode savedNode = ruleNodeDao.save(tenantId, node); relations.add(new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); @@ -484,7 +454,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } @Override - public List importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite) { + public List importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite, Function ruleNodeUpdater) { List importResults = new ArrayList<>(); setRandomRuleChainIds(ruleChainData); @@ -521,7 +491,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } if (CollectionUtils.isNotEmpty(ruleChainData.getMetadata())) { - ruleChainData.getMetadata().forEach(md -> saveRuleChainMetaData(tenantId, md)); + ruleChainData.getMetadata().forEach(md -> saveRuleChainMetaData(tenantId, md, ruleNodeUpdater)); } return importResults; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/EdgeServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/EdgeServiceTest.java index 02515dcfbe..adeb543625 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/EdgeServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/EdgeServiceTest.java @@ -44,6 +44,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.function.Function; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @@ -639,7 +640,7 @@ public class EdgeServiceTest extends AbstractServiceTest { ruleChainMetaData3.setNodes(Arrays.asList(ruleNode1, ruleNode2)); ruleChainMetaData3.setFirstNodeIndex(0); ruleChainMetaData3.setRuleChainId(ruleChain3.getId()); - ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData3); + ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData3, Function.identity()); ruleChainService.assignRuleChainToEdge(tenantId, ruleChain3.getId(), savedEdge.getId()); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/RuleChainServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/RuleChainServiceTest.java index e821a1e223..dd68e4ae76 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/RuleChainServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/RuleChainServiceTest.java @@ -40,6 +40,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Function; /** * Created by igor on 3/13/18. @@ -280,7 +281,7 @@ public class RuleChainServiceTest extends AbstractServiceTest { ruleNodes.set(name3Index, ruleNode4); - Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, savedRuleChainMetaData).isSuccess()); + Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, savedRuleChainMetaData, Function.identity()).isSuccess()); RuleChainMetaData updatedRuleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, savedRuleChainMetaData.getRuleChainId()); Assert.assertEquals(3, updatedRuleChainMetaData.getNodes().size()); @@ -311,14 +312,14 @@ public class RuleChainServiceTest extends AbstractServiceTest { @Test public void testUpdateRuleChainMetaDataWithCirclingRelation() { Assertions.assertThrows(DataValidationException.class, () -> { - ruleChainService.saveRuleChainMetaData(tenantId, createRuleChainMetadataWithCirclingRelation()); + ruleChainService.saveRuleChainMetaData(tenantId, createRuleChainMetadataWithCirclingRelation(), Function.identity()); }); } @Test public void testUpdateRuleChainMetaDataWithCirclingRelation2() { Assertions.assertThrows(DataValidationException.class, () -> { - ruleChainService.saveRuleChainMetaData(tenantId, createRuleChainMetadataWithCirclingRelation2()); + ruleChainService.saveRuleChainMetaData(tenantId, createRuleChainMetadataWithCirclingRelation2(), Function.identity()); }); } @@ -395,7 +396,7 @@ public class RuleChainServiceTest extends AbstractServiceTest { ruleChainMetaData.addConnectionInfo(0,2,"fail"); ruleChainMetaData.addConnectionInfo(1,2,"success"); - Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData).isSuccess()); + Assert.assertTrue(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData, Function.identity()).isSuccess()); return ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId()); } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java index 99d073df44..7ee61bac1d 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java @@ -65,4 +65,6 @@ public @interface RuleNode { RuleChainType[] ruleChainTypes() default {RuleChainType.CORE, RuleChainType.EDGE}; + int version() default 0; + } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbVersionedNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbVersionedNode.java index ce9a63111b..be9a5d01e2 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbVersionedNode.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbVersionedNode.java @@ -22,6 +22,4 @@ public interface TbVersionedNode extends TbNode { TbPair upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException; - int getCurrentVersion(); - } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java index 924092ad87..16b51d02c0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java @@ -41,11 +41,6 @@ public abstract class TbAbstractNodeWithFetchTo Date: Fri, 26 May 2023 10:50:32 +0300 Subject: [PATCH 077/421] UI refactoring --- .../relation/relation-filters.component.html | 25 ++++++++++--------- .../relation/relation-filters.component.scss | 6 ++++- .../entity/entity-subtype-list.component.html | 5 ++-- .../entity/entity-type-list.component.html | 4 +-- .../entity/entity-type-list.component.ts | 7 +++++- .../relation-type-autocomplete.component.html | 5 ++-- .../relation-type-autocomplete.component.ts | 4 ++- .../assets/locale/locale.constant-ca_ES.json | 1 - .../assets/locale/locale.constant-cs_CZ.json | 1 - .../assets/locale/locale.constant-da_DK.json | 1 - .../assets/locale/locale.constant-de_DE.json | 1 - .../assets/locale/locale.constant-el_GR.json | 1 - .../assets/locale/locale.constant-es_ES.json | 1 - .../assets/locale/locale.constant-fa_IR.json | 1 - .../assets/locale/locale.constant-fr_FR.json | 1 - .../assets/locale/locale.constant-it_IT.json | 1 - .../assets/locale/locale.constant-ko_KR.json | 1 - .../assets/locale/locale.constant-lv_LV.json | 1 - .../assets/locale/locale.constant-ro_RO.json | 1 - .../assets/locale/locale.constant-ru_RU.json | 1 - .../assets/locale/locale.constant-uk_UA.json | 2 +- .../assets/locale/locale.constant-zh_CN.json | 1 - .../assets/locale/locale.constant-zh_TW.json | 1 - 23 files changed, 34 insertions(+), 39 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html index 71965c4ba1..b052a1816c 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html @@ -22,14 +22,16 @@ fxLayoutAlign="start center" formArrayName="relationFilters" *ngFor="let relationFilterControl of relationFiltersFormArray.controls; let $index = index">
-
+
- @@ -49,14 +51,13 @@ relation.any-relation
-
- -
+
diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss index 5713fa2461..a2d4232f24 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss @@ -29,7 +29,7 @@ } .body { - max-height: 300px; + max-height: 363px; overflow: auto; .row { @@ -48,5 +48,9 @@ .any-filter{ margin: 10px 0 20px; } + + .add-button { + margin: 5px 0px 15px; + } } } diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html index 909d780e45..3ad2ef2824 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.html @@ -15,8 +15,8 @@ limitations under the License. --> - - {{ label | translate }} + + {{ label }} \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$e,decorators:[{type:r,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Je extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[ne,ae,oe],this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,r=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([G.required]),this.createAlarmConfigForm.get("severity").setValidators([G.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let n=this.createAlarmConfigForm.get("scriptLang").value;n!==d.TBEL||this.tbelEnabled||(n=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(n,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const a=!1===t||!0===r;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(a&&n===d.JS?[G.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(a&&n===d.TBEL?[G.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",n=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Je,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,decorators:[{type:r,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[G.required]],entityType:[e?e.entityType:null,[G.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[G.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[G.required,G.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([G.required,G.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([G.required,G.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",Qe),Qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qe,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,decorators:[{type:r,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[G.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[G.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[G.required,G.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([G.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([G.required,G.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ye,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,decorators:[{type:r,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,G.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,G.required]})}}e("DeviceProfileConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:We,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,decorators:[{type:r,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Xe extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[G.required,G.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[G.required,G.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",n=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var Ze;e("GeneratorConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xe,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:$.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,decorators:[{type:r,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(Ze||(Ze={}));const et=new Map([[Ze.CUSTOMER,"tb.rulenode.originator-customer"],[Ze.TENANT,"tb.rulenode.originator-tenant"],[Ze.RELATED,"tb.rulenode.originator-related"],[Ze.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[Ze.ENTITY,"tb.rulenode.originator-entity"]]);var tt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(tt||(tt={}));const rt=new Map([[tt.CIRCLE,"tb.rulenode.perimeter-circle"],[tt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var nt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(nt||(nt={}));const at=new Map([[nt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[nt.SECONDS,"tb.rulenode.time-unit-seconds"],[nt.MINUTES,"tb.rulenode.time-unit-minutes"],[nt.HOURS,"tb.rulenode.time-unit-hours"],[nt.DAYS,"tb.rulenode.time-unit-days"]]);var ot;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(ot||(ot={}));const it=new Map([[ot.METER,"tb.rulenode.range-unit-meter"],[ot.KILOMETER,"tb.rulenode.range-unit-kilometer"],[ot.FOOT,"tb.rulenode.range-unit-foot"],[ot.MILE,"tb.rulenode.range-unit-mile"],[ot.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var lt;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(lt||(lt={}));const st=new Map([[lt.ID,"tb.rulenode.entity-details-id"],[lt.TITLE,"tb.rulenode.entity-details-title"],[lt.COUNTRY,"tb.rulenode.entity-details-country"],[lt.STATE,"tb.rulenode.entity-details-state"],[lt.CITY,"tb.rulenode.entity-details-city"],[lt.ZIP,"tb.rulenode.entity-details-zip"],[lt.ADDRESS,"tb.rulenode.entity-details-address"],[lt.ADDRESS2,"tb.rulenode.entity-details-address2"],[lt.PHONE,"tb.rulenode.entity-details-phone"],[lt.EMAIL,"tb.rulenode.entity-details-email"],[lt.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var mt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(mt||(mt={}));const ut=new Map([[mt.FIRST,"tb.rulenode.first-message"],[mt.LAST,"tb.rulenode.last-message"],[mt.ALL,"tb.rulenode.all-messages"]]);var pt,dt;!function(e){e.ASC="ASC",e.DESC="DESC"}(pt||(pt={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(dt||(dt={}));const ct=new Map([[dt.STANDARD,"tb.rulenode.sqs-queue-standard"],[dt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),ft=["anonymous","basic","cert.PEM"],gt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),yt=["sas","cert.PEM"],xt=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var bt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(bt||(bt={}));const ht=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Ct=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Ft;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Ft||(Ft={}));const vt=new Map([[Ft.CUSTOM,{value:Ft.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Ft.ADD,{value:Ft.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Ft.SUB,{value:Ft.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Ft.MULT,{value:Ft.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Ft.DIV,{value:Ft.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Ft.SIN,{value:Ft.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Ft.SINH,{value:Ft.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Ft.COS,{value:Ft.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Ft.COSH,{value:Ft.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Ft.TAN,{value:Ft.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Ft.TANH,{value:Ft.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Ft.ACOS,{value:Ft.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Ft.ASIN,{value:Ft.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Ft.ATAN,{value:Ft.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Ft.ATAN2,{value:Ft.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Ft.EXP,{value:Ft.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Ft.EXPM1,{value:Ft.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Ft.SQRT,{value:Ft.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Ft.CBRT,{value:Ft.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Ft.GET_EXP,{value:Ft.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Ft.HYPOT,{value:Ft.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Ft.LOG,{value:Ft.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Ft.LOG10,{value:Ft.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Ft.LOG1P,{value:Ft.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Ft.CEIL,{value:Ft.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Ft.FLOOR,{value:Ft.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Ft.FLOOR_DIV,{value:Ft.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Ft.FLOOR_MOD,{value:Ft.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Ft.ABS,{value:Ft.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Ft.MIN,{value:Ft.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Ft.MAX,{value:Ft.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Ft.POW,{value:Ft.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Ft.SIGNUM,{value:Ft.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Ft.RAD,{value:Ft.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Ft.DEG,{value:Ft.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Lt,kt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Lt||(Lt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(kt||(kt={}));const It=new Map([[Lt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Lt.TIME_SERIES,"tb.rulenode.time-series-type"],[Lt.CONSTANT,"tb.rulenode.constant-type"],[Lt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Lt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),Tt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Nt,qt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Nt||(Nt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(qt||(qt={}));const St=new Map([[Nt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Nt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Nt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=tt,this.perimeterTypes=Object.keys(tt),this.perimeterTypeTranslationMap=rt,this.rangeUnits=Object.keys(ot),this.rangeUnitTranslationMap=it,this.timeUnits=Object.keys(nt),this.timeUnitsTranslationMap=at}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[G.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[G.required]],perimeterType:[e?e.perimeterType:null,[G.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[G.required,G.min(1),G.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[G.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[G.required,G.min(1),G.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[G.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([G.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||r!==tt.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([G.required,G.min(-90),G.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([G.required,G.min(-180),G.max(180)]),this.geoActionConfigForm.get("range").setValidators([G.required,G.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([G.required])),t||r!==tt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([G.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Mt),Mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Mt,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mt,decorators:[{type:r,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class At extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",n=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",At),At.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:At,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),At.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:At,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:At,decorators:[{type:r,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[G.required,G.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[G.required]]})}}e("MsgCountConfigComponent",Gt),Gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Gt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gt,decorators:[{type:r,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[G.required,G.min(1),G.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([G.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([G.required,G.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Et),Et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Et,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Et,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Et,decorators:[{type:r,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]]})}}e("PushToCloudConfigComponent",Dt),Dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Dt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dt,decorators:[{type:r,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]]})}}e("PushToEdgeConfigComponent",Vt),Vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Vt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vt,decorators:[{type:r,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",Pt),Pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Pt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pt,decorators:[{type:r,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[G.required,G.min(0)]]})}}e("RpcRequestConfigComponent",Rt),Rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Rt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rt,decorators:[{type:r,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class wt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.injector=r,this.fb=n,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(E),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const r of Object.keys(e))Object.prototype.hasOwnProperty.call(e,r)&&t.push(this.fb.group({key:[r,[G.required]],value:[e[r],[G.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[G.required]],value:["",[G.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",wt),wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wt,deps:[{token:M.Store},{token:U.TranslateService},{token:t.Injector},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:wt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:D,useExisting:o((()=>wt)),multi:!0},{provide:V,useExisting:o((()=>wt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:de.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ce.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wt,decorators:[{type:r,args:[{selector:"tb-kv-map-config",providers:[{provide:D,useExisting:o((()=>wt)),multi:!0},{provide:V,useExisting:o((()=>wt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:t.Injector},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[G.required,G.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[G.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Ot),Ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ot,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ot,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ot,decorators:[{type:r,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[G.required,G.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ht,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,decorators:[{type:r,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[G.required,G.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[G.required,G.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,decorators:[{type:r,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]],keys:[e?e.keys:null,[G.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Bt,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,decorators:[{type:r,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:a,args:["attributeChipList"]}]}});class Ut extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup())}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.injector=r,this.fb=n,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=vt,this.ArgumentType=Lt,this.attributeScopeMap=St,this.argumentTypeResultMap=It,this.arguments=Object.values(Lt),this.attributeScope=Object.values(Nt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(E),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({}),this.argumentsFormGroup.addControl("arguments",this.fb.array([])),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),r=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,r),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):this.argumentsFormGroup.enable({emitEvent:!1})}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()));const t=[];e&&e.forEach(((e,r)=>{t.push(this.createArgumentControl(e,r))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t)),this.setupArgumentsFormGroup(),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()})))}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(){const e=this.argumentsFormGroup.get("arguments"),t=this.createArgumentControl(null,e.length);e.push(t)}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Ft.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([G.minLength(this.minArgs),G.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(r),r.get("attributeScope").updateValueAndValidity({emitEvent:!0}),r.get("defaultValue").updateValueAndValidity({emitEvent:!0})}))),r}updateArgumentControlValidators(e){const t=e.get("type").value;t===Lt.ATTRIBUTE?e.get("attributeScope").enable():e.get("attributeScope").disable(),t&&t!==Lt.CONSTANT?e.get("defaultValue").enable():e.get("defaultValue").disable()}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Tt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,deps:[{token:M.Store},{token:U.TranslateService},{token:t.Injector},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ut,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:D,useExisting:o((()=>Ut)),multi:!0},{provide:V,useExisting:o((()=>Ut)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:de.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:fe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:fe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:ge.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:ge.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:ge.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ce.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,decorators:[{type:r,args:[{selector:"tb-arguments-map-config",providers:[{provide:D,useExisting:o((()=>Ut)),multi:!0},{provide:V,useExisting:o((()=>Ut)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:t.Injector},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class zt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.injector=r,this.fb=n,this.searchText="",this.dirty=!1,this.mathOperation=[...vt.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(ye((e=>{let t;t="string"==typeof e&&Ft[e]?Ft[e]:null,this.updateView(t)})),xe((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=vt.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,deps:[{token:M.Store},{token:U.TranslateService},{token:t.Injector},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:zt,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:D,useExisting:o((()=>zt)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,decorators:[{type:r,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:D,useExisting:o((()=>zt)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:t.Injector},{type:A.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:a,args:["operationInput",{static:!0}]}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Ft,this.ArgumentTypeResult=kt,this.argumentTypeResultMap=It,this.attributeScopeMap=St,this.argumentsResult=Object.values(kt),this.attributeScopeResult=Object.values(qt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[G.required]],arguments:[e?e.arguments:null,[G.required]],customFunction:[e?e.customFunction:"",[G.required]],result:this.fb.group({type:[e?e.result.type:null,[G.required]],attributeScope:[e?e.result.attributeScope:null],key:[e?e.result.key:"",[G.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,r=this.mathFunctionConfigForm.get("result").get("type").value;t===Ft.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),r===kt.ATTRIBUTE?this.mathFunctionConfigForm.get("result").get("attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result").get("attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result").get("attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:jt,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:A.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ut,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:zt,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,decorators:[{type:r,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class _t{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[G.required,G.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(ye((e=>{this.updateView(e)})),xe((e=>e||"")),be((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,ke(this.messageTypes).pipe(xe((r=>r.filter((r=>t?!!e&&r===e:!e||r.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:_t,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:D,useExisting:o((()=>_t)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,decorators:[{type:r,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:D,useExisting:o((()=>_t)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{messageTypeInput:[{type:a,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Ie,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=mt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=ut}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[Y(e?.interval)?e.interval:null,[G.required,G.min(1)]],strategy:[Y(e?.strategy)?e.strategy:null,[G.required]],outMsgType:[Y(e?.outMsgType)?e.outMsgType:null,[G.required]],queueName:[Y(e?.queueName)?e.queueName:null,[G.required]],maxPendingMsgs:[Y(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[G.required,G.min(1),G.max(1e3)]],maxRetries:[Y(e?.maxRetries)?e.maxRetries:null,[G.required,G.min(0),G.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(he(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$t,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:$.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Te.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Te.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Te.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:_t,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,decorators:[{type:r,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Jt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[G.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[G.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Jt,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:D,useExisting:o((()=>Jt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:qe.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled","subscriptSizing"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,decorators:[{type:r,args:[{selector:"tb-device-relations-query-config",providers:[{provide:D,useExisting:o((()=>Jt)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class Qt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[G.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:D,useExisting:o((()=>Qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Me.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,decorators:[{type:r,args:[{selector:"tb-relations-query-config",providers:[{provide:D,useExisting:o((()=>Qt)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class Yt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.truncate=r,this.fb=n,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[ne,ae,oe],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(h))this.messageTypesList.push({name:C.get(h[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Ce(""),xe((e=>e||"")),be((e=>this.fetchMessageTypes(e))),Fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return ke(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return ke(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const r=e.trim(),n=this.messageTypesList.find((e=>e.name===r));t=n?{name:n.name,value:n.value}:{name:r,value:r},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,deps:[{token:M.Store},{token:U.TranslateService},{token:F.TruncatePipe},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Yt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:D,useExisting:o((()=>Yt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ve.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,decorators:[{type:r,args:[{selector:"tb-message-types-config",providers:[{provide:D,useExisting:o((()=>Yt)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:F.TruncatePipe},{type:A.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:a,args:["chipList",{static:!1}]}],matAutocomplete:[{type:a,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:a,args:["messageTypeInput",{static:!1}]}]}});class Wt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=ft,this.credentialsTypeTranslationsMap=gt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[G.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const r=e[t];if(!r.firstChange&&r.currentValue!==r.previousValue&&r.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){Y(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([G.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[G.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(G.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return r=>{t||(t=[Object.keys(r.controls)]);return r?.controls&&t.some((t=>t.every((t=>!e(r.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,deps:[{token:M.Store},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Wt,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:D,useExisting:o((()=>Wt)),multi:!0},{provide:V,useExisting:o((()=>Wt)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Te.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Te.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Te.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Te.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ae.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,decorators:[{type:r,args:[{selector:"tb-credentials-config",providers:[{provide:D,useExisting:o((()=>Wt)),multi:!0},{provide:V,useExisting:o((()=>Wt)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class Xt{}e("RulenodeCoreConfigCommonModule",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Xt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Xt,declarations:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t],imports:[w,v,Ne],exports:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t]}),Xt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,imports:[w,v,Ne]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,decorators:[{type:l,args:[{declarations:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t],imports:[w,v,Ne],exports:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t]}]}]});class Zt{}e("RuleNodeCoreConfigActionModule",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Zt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Zt,declarations:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t],imports:[w,v,Ne,Xt],exports:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t]}),Zt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,imports:[w,v,Ne,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,decorators:[{type:l,args:[{declarations:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t],imports:[w,v,Ne,Xt],exports:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t]}]}]});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[G.required]],outputValueKey:[e?e.outputValueKey:null,[G.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[G.min(0),G.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([G.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:er,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,decorators:[{type:r,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[G.required]]})}}e("CustomerAttributesConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tr,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[G.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],fetchToData:[!!e&&e.fetchToData,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}prepareInputConfig(e){return W(e)&&X(e?.fetchToData)&&(e.fetchToData=!1),e}}e("DeviceAttributesConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rr,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Jt,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class nr extends s{constructor(e,t,r){super(e),this.store=e,this.translate=t,this.fb=r,this.entityDetailsTranslationsMap=st,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(lt))this.entityDetailsList.push(lt[e]);this.detailsFormControl=new P(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(Ce(""),xe((e=>e||"")),be((e=>this.fetchEntityDetails(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],e}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[G.required]],addToMetadata:[!!e&&e.addToMetadata,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(st.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return ke(this.entityDetailsList.filter((t=>this.translate.instant(st.get(lt[t])).toUpperCase().includes(e))))}return ke(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,deps:[{token:M.Store},{token:U.TranslateService},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nr,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ve.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:A.UntypedFormBuilder}]},propDecorators:{detailsInput:[{type:a,args:["detailsInput",{static:!1}]}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe],this.aggregationTypes=L,this.aggregations=Object.keys(L),this.aggregationTypesTranslations=k,this.fetchMode=mt,this.fetchModes=Object.keys(mt),this.samplingOrders=Object.keys(pt),this.timeUnits=Object.values(nt),this.timeUnitsTranslationMap=at}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[G.required]],fetchMode:[e?e.fetchMode:null,[G.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===mt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([G.required,G.min(2),G.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([G.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([G.required,G.min(1),G.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([G.required,G.min(1),G.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}}e("GetTelemetryFromDatabaseConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ar,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeseries-key\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,decorators:[{type:r,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n tb.rulenode.timeseries-key\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],fetchToData:[!!Y(e?.fetchToData)&&e.fetchToData,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}prepareInputConfig(e){return W(e)&&X(e?.fetchToData)&&(e.fetchToData=!1),e}}e("OriginatorAttributesConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:or,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,decorators:[{type:r,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[G.required]],ignoreNullStrings:[e?e.ignoreNullStrings:null]})}}e("OriginatorFieldsConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ir,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n {{ "tb.rulenode.ignore-null-strings" | translate }}\n
{{ "tb.rulenode.ignore-null-strings-hint" | translate }}
\n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,decorators:[{type:r,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n {{ "tb.rulenode.ignore-null-strings" | translate }}\n
{{ "tb.rulenode.ignore-null-strings-hint" | translate }}
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[G.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[G.required]]})}}e("RelatedAttributesConfigComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:lr,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"component",type:Qt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class sr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[G.required]]})}}e("TenantAttributesConfigComponent",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:sr,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class mr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchToMetadata:[e?e.fetchToMetadata:null,[]]})}}e("FetchDeviceCredentialsConfigComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:mr,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n {{ \'tb.rulenode.fetch-credentials-to-metadata\' | translate }}\n
\n',dependencies:[{kind:"component",type:De.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,decorators:[{type:r,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n {{ \'tb.rulenode.fetch-credentials-to-metadata\' | translate }}\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class ur{}e("RulenodeCoreConfigEnrichmentModule",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ur,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ur.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:ur,declarations:[tr,nr,rr,or,ir,ar,lr,sr,er,mr],imports:[w,v,Xt],exports:[tr,nr,rr,or,ir,ar,lr,sr,er,mr]}),ur.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ur,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ur,decorators:[{type:l,args:[{declarations:[tr,nr,rr,or,ir,ar,lr,sr,er,mr],imports:[w,v,Xt],exports:[tr,nr,rr,or,ir,ar,lr,sr,er,mr]}]}]});class pr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=yt,this.azureIotHubCredentialsTypeTranslationsMap=xt}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[G.required]],host:[e?e.host:null,[G.required]],port:[e?e.port:null,[G.required,G.min(1),G.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[G.required,G.min(1),G.max(200)]],clientId:[e?e.clientId:null,[G.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[G.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([G.required]);break;case"cert.PEM":t.get("privateKey").setValidators([G.required]),t.get("privateKeyFileName").setValidators([G.required]),t.get("cert").setValidators([G.required]),t.get("certFileName").setValidators([G.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:pr,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Te.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Te.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Te.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Te.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Te.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:A.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Ae.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pr,decorators:[{type:r,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class dr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=ht,this.ToByteStandartCharsetTypeTranslationMap=Ct}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[G.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[G.required]],retries:[e?e.retries:null,[G.min(0)]],batchSize:[e?e.batchSize:null,[G.min(0)]],linger:[e?e.linger:null,[G.min(0)]],bufferMemory:[e?e.bufferMemory:null,[G.min(0)]],acks:[e?e.acks:null,[G.required]],keySerializer:[e?e.keySerializer:null,[G.required]],valueSerializer:[e?e.valueSerializer:null,[G.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([G.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),dr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:dr,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dr,decorators:[{type:r,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class cr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[G.required]],host:[e?e.host:null,[G.required]],port:[e?e.port:null,[G.required,G.min(1),G.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[G.required,G.min(1),G.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&Z(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{Z(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",cr),cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),cr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:cr,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cr,decorators:[{type:r,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class fr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=I,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[G.required]],targets:[e?e.targets:[],[G.required]]})}}e("NotificationConfigComponent",fr),fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fr,deps:[{token:M.Store},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:fr,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Ve.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","disabled","notificationTypes"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fr,decorators:[{type:r,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.FormBuilder}]}});class gr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[G.required]],topicName:[e?e.topicName:null,[G.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[G.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[G.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",gr),gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),gr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:gr,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ae.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gr,decorators:[{type:r,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class yr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[G.required]],port:[e?e.port:null,[G.required,G.min(1),G.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[G.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[G.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",yr),yr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),yr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:yr,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yr,decorators:[{type:r,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class xr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(bt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[G.required]],requestMethod:[e?e.requestMethod:null,[G.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[G.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[G.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[G.required,G.min(1),G.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([G.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([G.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",xr),xr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),xr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:xr,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"component",type:Wt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xr,decorators:[{type:r,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class br extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([G.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([G.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([G.required,G.min(1),G.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([G.required,G.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[G.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[G.required,G.min(1),G.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",br),br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:br,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:br,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Re.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:br,decorators:[{type:r,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class hr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[G.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[G.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([G.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",hr),hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),hr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:hr,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hr,decorators:[{type:r,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Cr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(T),this.slackChanelTypesTranslateMap=N}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[G.required]],conversationType:[e?e.conversationType:null,[G.required]],conversation:[e?e.conversation:null,[G.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([G.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Cr),Cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cr,deps:[{token:M.Store},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Cr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Cr,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cr,decorators:[{type:r,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.FormBuilder}]}});class Fr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[G.required]],accessKeyId:[e?e.accessKeyId:null,[G.required]],secretAccessKey:[e?e.secretAccessKey:null,[G.required]],region:[e?e.region:null,[G.required]]})}}e("SnsConfigComponent",Fr),Fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Fr,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fr,decorators:[{type:r,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class vr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=dt,this.sqsQueueTypes=Object.keys(dt),this.sqsQueueTypeTranslationsMap=ct}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[G.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[G.required]],delaySeconds:[e?e.delaySeconds:null,[G.min(0),G.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[G.required]],secretAccessKey:[e?e.secretAccessKey:null,[G.required]],region:[e?e.region:null,[G.required]]})}}e("SqsConfigComponent",vr),vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),vr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:vr,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vr,decorators:[{type:r,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Lr{}e("RulenodeCoreConfigExternalModule",Lr),Lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Lr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Lr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Lr,declarations:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr],imports:[w,v,Ne,Xt],exports:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr]}),Lr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Lr,imports:[w,v,Ne,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Lr,decorators:[{type:l,args:[{declarations:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr],imports:[w,v,Ne,Xt],exports:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr]}]}]});class kr extends s{constructor(e,t,r){super(e),this.store=e,this.translate=t,this.fb=r,this.alarmStatusTranslationsMap=q,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(S))this.alarmStatusList.push(S[e]);this.statusFormControl=new P(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(Ce(""),xe((e=>e||"")),be((e=>this.fetchAlarmStatus(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[G.required]]})}displayStatus(e){return e?this.translate.instant(q.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return ke(t.filter((t=>this.translate.instant(q.get(S[t])).toUpperCase().includes(e))))}return ke(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",kr),kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kr,deps:[{token:M.Store},{token:U.TranslateService},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:kr,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ve.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kr,decorators:[{type:r,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:A.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:a,args:["alarmStatusInput",{static:!1}]}]}});class Ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",Ir),Ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ir,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ir,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ir,decorators:[{type:r,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[G.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[G.required]:[]],relationType:[e?e.relationType:null,[G.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[G.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[G.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",Tr),Tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Tr,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:He.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled","subscriptSizing"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tr,decorators:[{type:r,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=tt,this.perimeterTypes=Object.keys(tt),this.perimeterTypeTranslationMap=rt,this.rangeUnits=Object.keys(ot),this.rangeUnitTranslationMap=it}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[G.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[G.required]],perimeterType:[e?e.perimeterType:null,[G.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([G.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||r!==tt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([G.required,G.min(-90),G.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([G.required,G.min(-180),G.max(180)]),this.geoFilterConfigForm.get("range").setValidators([G.required,G.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([G.required])),t||r!==tt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([G.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",Nr),Nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Nr,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nr,decorators:[{type:r,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class qr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[G.required]]})}}e("MessageTypeConfigComponent",qr),qr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),qr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:qr,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Yt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qr,decorators:[{type:r,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Sr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[G.required]]})}}e("OriginatorTypeConfigComponent",Sr),Sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Sr,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:Ke.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sr,decorators:[{type:r,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Mr extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",n=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Mr),Mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mr,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Mr,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mr,decorators:[{type:r,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Ar extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",n=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Ar),Ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ar,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ar,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ar,decorators:[{type:r,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Gr{}e("RuleNodeCoreConfigFilterModule",Gr),Gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Gr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Gr,declarations:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr],imports:[w,v,Xt],exports:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr]}),Gr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gr,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gr,decorators:[{type:l,args:[{declarations:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr],imports:[w,v,Xt],exports:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr]}]}]});class Er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=Ze,this.originatorSources=Object.keys(Ze),this.originatorSourceTranslationMap=et,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[G.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===Ze.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([G.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===Ze.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([G.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([G.required,G.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Er),Er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Er,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Er,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Er,decorators:[{type:r,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Dr extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[G.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",n=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Dr),Dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dr,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Dr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Dr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dr,decorators:[{type:r,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Vr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[G.required]],toTemplate:[e?e.toTemplate:null,[G.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[G.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[G.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(Ce([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(G.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",Vr),Vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Vr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vr,decorators:[{type:r,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Pr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[G.required]],keys:[e?e.keys:null,[G.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",Pr),Pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Pr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pr,decorators:[{type:r,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[G.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[G.required]]})}}e("RenameKeysConfigComponent",Rr),Rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Rr,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rr,decorators:[{type:r,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class wr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[G.required]]})}}e("NodeJsonPathConfigComponent",wr),wr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:wr,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wr,decorators:[{type:r,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[G.required]],keys:[e?e.keys:null,[G.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",Or),Or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Or,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Or,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Or,decorators:[{type:r,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Hr{}e("RulenodeCoreConfigTransformModule",Hr),Hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Hr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Hr,declarations:[Er,Dr,Vr,Pr,Rr,wr,Or],imports:[w,v,Xt],exports:[Er,Dr,Vr,Pr,Rr,wr,Or]}),Hr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hr,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hr,decorators:[{type:l,args:[{declarations:[Er,Dr,Vr,Pr,Rr,wr,Or],imports:[w,v,Xt],exports:[Er,Dr,Vr,Pr,Rr,wr,Or]}]}]});class Kr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[G.required]]})}}e("RuleChainInputComponent",Kr),Kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:He.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kr,decorators:[{type:r,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Br extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",Br),Br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Br,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Br,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Br,decorators:[{type:r,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ur{}e("RuleNodeCoreConfigFlowModule",Ur),Ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ur,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Ur.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Ur,declarations:[Kr,Br],imports:[w,v,Xt],exports:[Kr,Br]}),Ur.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ur,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ur,decorators:[{type:l,args:[{declarations:[Kr,Br],imports:[w,v,Xt],exports:[Kr,Br]}]}]});class zr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attribute keys","shared-attributes":"Shared attribute keys","server-attributes":"Server attribute keys","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-key":"Time-series key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.","first-message":"First Message","last-message":"Last Message","all-messages":"All Messages","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required.","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body to substitute "Source" and "Target" key names',"shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",zr),zr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zr,deps:[{token:U.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),zr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:zr,declarations:[Be],imports:[w,v],exports:[Zt,Gr,ur,Lr,Hr,Ur,Be]}),zr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zr,imports:[w,v,Zt,Gr,ur,Lr,Hr,Ur]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zr,decorators:[{type:l,args:[{declarations:[Be],imports:[w,v],exports:[Zt,Gr,ur,Lr,Hr,Ur,Be]}]}],ctorParameters:function(){return[{type:U.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","tslib","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@angular/material/slide-toggle","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@angular/material/button-toggle","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,v,F,L,k,T,I,N,S,q,M,A,G,E,D,V,w,P,R,O,H,K,B,U,z,_,j,$,Q,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,ve,Fe,Le,ke,Te,Ie,Ne,Se,qe,Me,Ae,Ge,Ee,De,Ve,we,Pe,Re,Oe,He,Ke,Be,Ue,ze,_e,je;return{setters:[function(e){t=e,n=e.Component,r=e.Pipe,o=e.ViewChild,a=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.coerceBoolean,C=e.MessageType,v=e.messageTypeNames,F=e,L=e.SharedModule,k=e.AggregationType,T=e.aggregationTranslations,I=e.NotificationType,N=e.SlackChanelType,S=e.SlackChanelTypesTranslateMap,q=e.alarmStatusTranslations,M=e.AlarmStatus},function(e){A=e},function(e){G=e,E=e.Validators,D=e.NgControl,V=e.NG_VALUE_ACCESSOR,w=e.NG_VALIDATORS,P=e.FormControl,R=e.UntypedFormControl},function(e){O=e,H=e.CommonModule},function(e){K=e},function(e){B=e},function(e){U=e},function(e){z=e},function(e){_=e},function(e){j=e},function(e){$=e},function(e){Q=e},function(e){J=e},function(e){Y=e.getCurrentAuthState,W=e,X=e.isDefinedAndNotNull,Z=e.isObject,ee=e.isNotEmptyStr},function(e){te=e},function(e){ne=e},function(e){re=e},function(e){oe=e.ENTER,ae=e.COMMA,ie=e.SEMICOLON},function(e){le=e},function(e){se=e},function(e){me=e},function(e){ue=e},function(e){pe=e.coerceBooleanProperty},function(e){de=e},function(e){ce=e},function(e){fe=e},function(e){ge=e},function(e){ye=e},function(e){xe=e.tap,be=e.map,he=e.mergeMap,Ce=e.takeUntil,ve=e.startWith,Fe=e.share,Le=e.distinctUntilChanged},function(e){ke=e},function(e){Te=e},function(e){Ie=e.of,Ne=e.Subject},function(e){Se=e},function(e){qe=e.HomeComponentsModule},function(e){Me=e.__decorate},function(e){Ae=e},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){we=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e},function(e){Be=e},function(e){Ue=e},function(e){ze=e},function(e){_e=e},function(e){je=e}],execute:function(){class $e extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",$e),$e.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$e,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$e.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$e,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$e,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qe{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Qe),Qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,deps:[{token:j.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Qe.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Qe,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:j.DomSanitizer}]}});class Je extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[E.required,E.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[E.required,E.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Je,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ye,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[E.required]]})}}e("CheckPointConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:We,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Xe extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[E.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[E.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[E.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.clearAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",r=this.clearAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.clearAlarmConfigForm.get(t).setValue(e)}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xe,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Ze extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[oe,ae,ie],this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([E.required]),this.createAlarmConfigForm.get("severity").setValidators([E.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[E.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[E.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",r=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ze,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ze,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[E.required]],entityType:[e?e.entityType:null,[E.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[E.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[E.required,E.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([E.required,E.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:et,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:et,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[E.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[E.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[E.required,E.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([E.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,E.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,E.required]})}}e("DeviceProfileConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nt,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class rt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[E.required,E.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[E.required,E.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",r=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var ot;e("GeneratorConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rt,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rt,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(ot||(ot={}));const at=new Map([[ot.CUSTOMER,"tb.rulenode.originator-customer"],[ot.TENANT,"tb.rulenode.originator-tenant"],[ot.RELATED,"tb.rulenode.originator-related"],[ot.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[ot.ENTITY,"tb.rulenode.originator-entity"]]);var it;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(it||(it={}));const lt=new Map([[it.CIRCLE,"tb.rulenode.perimeter-circle"],[it.POLYGON,"tb.rulenode.perimeter-polygon"]]);var st;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(st||(st={}));const mt=new Map([[st.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[st.SECONDS,"tb.rulenode.time-unit-seconds"],[st.MINUTES,"tb.rulenode.time-unit-minutes"],[st.HOURS,"tb.rulenode.time-unit-hours"],[st.DAYS,"tb.rulenode.time-unit-days"]]);var ut;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(ut||(ut={}));const pt=new Map([[ut.METER,"tb.rulenode.range-unit-meter"],[ut.KILOMETER,"tb.rulenode.range-unit-kilometer"],[ut.FOOT,"tb.rulenode.range-unit-foot"],[ut.MILE,"tb.rulenode.range-unit-mile"],[ut.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var dt,ct;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(dt||(dt={})),function(e){e.NAME="name",e.CREATED_TIME="createdTime",e.TYPE="type",e.FIRST_NAME="firstName",e.LAST_NAME="lastName",e.EMAIL="email",e.TITLE="title",e.COUNTRY="county",e.STATE="state",e.CITY="city",e.ADDRESS="address",e.ADDRESS2="address2",e.ZIP="zip",e.PHONE="phone",e.LABEL="label"}(ct||(ct={}));const ft=new Map([[ct.NAME,"tb.rulenode.name"],[ct.CREATED_TIME,"tb.rulenode.created-time"],[ct.TYPE,"tb.rulenode.type"],[ct.FIRST_NAME,"tb.rulenode.first-name"],[ct.LAST_NAME,"tb.rulenode.last-name"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.LABEL,"tb.rulenode.label"]]),gt=new Map([[dt.ID,"tb.rulenode.entity-details-id"],[dt.TITLE,"tb.rulenode.entity-details-title"],[dt.COUNTRY,"tb.rulenode.entity-details-country"],[dt.STATE,"tb.rulenode.entity-details-state"],[dt.CITY,"tb.rulenode.entity-details-city"],[dt.ZIP,"tb.rulenode.entity-details-zip"],[dt.ADDRESS,"tb.rulenode.entity-details-address"],[dt.ADDRESS2,"tb.rulenode.entity-details-address2"],[dt.PHONE,"tb.rulenode.entity-details-phone"],[dt.EMAIL,"tb.rulenode.entity-details-email"],[dt.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var yt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(yt||(yt={}));const xt=new Map([[yt.FIRST,"tb.rulenode.first"],[yt.LAST,"tb.rulenode.last"],[yt.ALL,"tb.rulenode.all"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const Ct=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var vt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(vt||(vt={}));const Ft=new Map([[vt.STANDARD,"tb.rulenode.sqs-queue-standard"],[vt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Lt=["anonymous","basic","cert.PEM"],kt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Tt=["sas","cert.PEM"],It=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Nt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Nt||(Nt={}));const St=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],qt=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Mt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Mt||(Mt={}));const At=new Map([[Mt.CUSTOM,{value:Mt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Mt.ADD,{value:Mt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Mt.SUB,{value:Mt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Mt.MULT,{value:Mt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Mt.DIV,{value:Mt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Mt.SIN,{value:Mt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Mt.SINH,{value:Mt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Mt.COS,{value:Mt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Mt.COSH,{value:Mt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Mt.TAN,{value:Mt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Mt.TANH,{value:Mt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Mt.ACOS,{value:Mt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Mt.ASIN,{value:Mt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Mt.ATAN,{value:Mt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Mt.ATAN2,{value:Mt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Mt.EXP,{value:Mt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Mt.EXPM1,{value:Mt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Mt.SQRT,{value:Mt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Mt.CBRT,{value:Mt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Mt.GET_EXP,{value:Mt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Mt.HYPOT,{value:Mt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Mt.LOG,{value:Mt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Mt.LOG10,{value:Mt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Mt.LOG1P,{value:Mt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Mt.CEIL,{value:Mt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Mt.FLOOR,{value:Mt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Mt.FLOOR_DIV,{value:Mt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Mt.FLOOR_MOD,{value:Mt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Mt.ABS,{value:Mt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Mt.MIN,{value:Mt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Mt.MAX,{value:Mt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Mt.POW,{value:Mt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Mt.SIGNUM,{value:Mt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Mt.RAD,{value:Mt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Mt.DEG,{value:Mt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Gt,Et,Dt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Gt||(Gt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Et||(Et={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Dt||(Dt={}));const Vt=new Map([[Gt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Gt.TIME_SERIES,"tb.rulenode.time-series-type"],[Gt.CONSTANT,"tb.rulenode.constant-type"],[Gt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Gt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),wt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Pt,Rt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Pt||(Pt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Rt||(Rt={}));const Ot=new Map([[Pt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Pt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Pt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=it,this.perimeterTypes=Object.keys(it),this.perimeterTypeTranslationMap=lt,this.rangeUnits=Object.keys(ut),this.rangeUnitTranslationMap=pt,this.timeUnits=Object.keys(st),this.timeUnitsTranslationMap=mt}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[E.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[E.required]],perimeterType:[e?e.perimeterType:null,[E.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[E.required,E.min(1),E.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[E.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[E.required,E.min(1),E.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[E.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([E.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==it.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([E.required,E.min(-90),E.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([E.required,E.min(-180),E.max(180)]),this.geoActionConfigForm.get("range").setValidators([E.required,E.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([E.required])),t||n!==it.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([E.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ht,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Kt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",r=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[E.required,E.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[E.required]]})}}e("MsgCountConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Bt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[E.required,E.min(1),E.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([E.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([E.required,E.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ut,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]]})}}e("PushToCloudConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:zt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]]})}}e("PushToEdgeConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:_t,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:jt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[E.required,E.min(0)]]})}}e("RpcRequestConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$t,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required]],value:[e[n],[E.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[E.required]],value:["",[E.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigOldComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:V,useExisting:a((()=>Qt)),multi:!0},{provide:w,useExisting:a((()=>Qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:V,useExisting:a((()=>Qt)),multi:!0},{provide:w,useExisting:a((()=>Qt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[E.required,E.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[E.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Jt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[E.required,E.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Yt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Wt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[E.required,E.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[E.required,E.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Wt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]],keys:[e?e.keys:null,[E.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xt,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class Zt extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup())}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=At,this.ArgumentType=Gt,this.attributeScopeMap=Ot,this.argumentTypeResultMap=Vt,this.arguments=Object.values(Gt),this.attributeScope=Object.values(Pt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({}),this.argumentsFormGroup.addControl("arguments",this.fb.array([])),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):this.argumentsFormGroup.enable({emitEvent:!1})}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()));const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t)),this.setupArgumentsFormGroup(),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()})))}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(){const e=this.argumentsFormGroup.get("arguments"),t=this.createArgumentControl(null,e.length);e.push(t)}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Mt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([E.minLength(this.minArgs),E.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!0}),n.get("defaultValue").updateValueAndValidity({emitEvent:!0})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Gt.ATTRIBUTE?e.get("attributeScope").enable():e.get("attributeScope").disable(),t&&t!==Gt.CONSTANT?e.get("defaultValue").enable():e.get("defaultValue").disable()}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(wt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Zt,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:V,useExisting:a((()=>Zt)),multi:!0},{provide:w,useExisting:a((()=>Zt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"],dependencies:[{kind:"directive",type:O.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ge.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:ge.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:ye.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:ye.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:ye.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:V,useExisting:a((()=>Zt)),multi:!0},{provide:w,useExisting:a((()=>Zt)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class en extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...At.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(xe((e=>{let t;t="string"==typeof e&&Mt[e]?Mt[e]:null,this.updateView(t)})),be((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=At.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:en,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:en,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:V,useExisting:a((()=>en)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:en,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:V,useExisting:a((()=>en)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Mt,this.ArgumentTypeResult=Et,this.argumentTypeResultMap=Vt,this.attributeScopeMap=Ot,this.argumentsResult=Object.values(Et),this.attributeScopeResult=Object.values(Rt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[E.required]],arguments:[e?e.arguments:null,[E.required]],customFunction:[e?e.customFunction:"",[E.required]],result:this.fb.group({type:[e?e.result.type:null,[E.required]],attributeScope:[e?e.result.attributeScope:null],key:[e?e.result.key:"",[E.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result").get("type").value;t===Mt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Et.ATTRIBUTE?this.mathFunctionConfigForm.get("result").get("attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result").get("attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result").get("attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tn,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Zt,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:en,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tn,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nn{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[E.required,E.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(xe((e=>{this.updateView(e)})),be((e=>e||"")),he((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,Ie(this.messageTypes).pipe(be((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nn,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:V,useExisting:a((()=>nn)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:V,useExisting:a((()=>nn)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Ne,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=yt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=xt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[X(e?.interval)?e.interval:null,[E.required,E.min(1)]],strategy:[X(e?.strategy)?e.strategy:null,[E.required]],outMsgType:[X(e?.outMsgType)?e.outMsgType:null,[E.required]],queueName:[X(e?.queueName)?e.queueName:null,[E.required]],maxPendingMsgs:[X(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[E.required,E.min(1),E.max(1e3)]],maxRetries:[X(e?.maxRetries)?e.maxRetries:null,[E.required,E.min(0),E.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:nn,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class on extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:on,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:on,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:V,useExisting:a((()=>on)),multi:!0},{provide:w,useExisting:a((()=>on)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n \n \n \n
\n
\n {{ hintText }}\n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),Me([h()],on.prototype,"disabled",void 0),Me([h()],on.prototype,"uniqueKeyValuePairValidator",void 0),Me([h()],on.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:V,useExisting:a((()=>on)),multi:!0},{provide:w,useExisting:a((()=>on)),multi:!0}],template:'
\n
\n \n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n \n \n \n
\n
\n {{ hintText }}\n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class an{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne}ngOnInit(){this.slideToggleControlGroup=this.fb.group({slideToggleControl:[null,[]]}),this.slideToggleControlGroup.get("slideToggleControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.slideToggleControlGroup.get("slideToggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SlideToggleComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:an,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:an,selector:"tb-slide-toggle",inputs:{slideToggleName:"slideToggleName",slideToggleTooltip:"slideToggleTooltip"},providers:[{provide:V,useExisting:a((()=>an)),multi:!0}],ngImport:t,template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"],dependencies:[{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:De.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-slide-toggle",providers:[{provide:V,useExisting:a((()=>an)),multi:!0}],template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{slideToggleName:[{type:i}],slideToggleTooltip:[{type:i}]}});class ln extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[E.min(1)]],relationType:[null],deviceTypes:[null,[E.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ln,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ln,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>ln)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["label","required","disabled","entityType"]},{kind:"component",type:Ee.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","required","disabled","subscriptSizing"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:V,useExisting:a((()=>ln)),multi:!0}],template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class sn{set required(e){this.requiredValue=pe(e)}get required(){return this.requiredValue}}e("FieldsetComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sn,deps:[],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:sn,selector:"tb-fieldset-component",inputs:{label:"label",required:"required"},ngImport:t,template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-fieldset-component",template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],propDecorators:{label:[{type:i}],required:[{type:i}]}});class mn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[E.min(1)]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:mn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>mn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:V,useExisting:a((()=>mn)),multi:!0}],template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class un extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[oe,ae,ie],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(C))this.messageTypesList.push({name:v.get(C[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchMessageTypes(e))),Fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ie(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:un,deps:[{token:A.Store},{token:_.TranslateService},{token:F.TruncatePipe},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:un,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:V,useExisting:a((()=>un)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:V,useExisting:a((()=>un)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:F.TruncatePipe},{type:G.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class pn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Lt,this.credentialsTypeTranslationsMap=kt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[E.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(Le()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){X(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([E.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[E.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(E.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:pn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:V,useExisting:a((()=>pn)),multi:!0},{provide:w,useExisting:a((()=>pn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Se.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:V,useExisting:a((()=>pn)),multi:!0},{provide:w,useExisting:a((()=>pn)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRquired:[{type:i}]}});class dn{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne,this.fetchTo=Dt}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:dn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:V,useExisting:a((()=>dn)),multi:!0}],ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.message\' | translate }}\n {{ \'tb.rulenode.metadata\' | translate }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"],dependencies:[{kind:"component",type:se.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:se.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:V,useExisting:a((()=>dn)),multi:!0}],template:'
\n \n \n {{ \'tb.rulenode.message\' | translate }}\n {{ \'tb.rulenode.metadata\' | translate }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{labelText:[{type:i}]}});class cn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Ne,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required]],value:[e[n],[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.updateModel()}))}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value)t.push(this.selectOptions.find((t=>t===e.key)));const n=[];for(const r of this.selectOptions)X(t.find((e=>e===r)))&&r!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[E.required]],value:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.controls[e.length-1])}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Ce(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.svListFormGroup.valid?null:{kvFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cn,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:cn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",selectOptionsTranslate:"selectOptionsTranslate",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:V,useExisting:a((()=>cn)),multi:!0},{provide:w,useExisting:a((()=>cn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n \n {{ selectText }}\n \n \n {{selectOptionsTranslate.get(option) | translate}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n \n \n
\n
\n {{ hintText }}\n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),Me([h()],cn.prototype,"disabled",void 0),Me([h()],cn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:V,useExisting:a((()=>cn)),multi:!0},{provide:w,useExisting:a((()=>cn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n \n {{ selectText }}\n \n \n {{selectOptionsTranslate.get(option) | translate}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n \n \n
\n
\n {{ hintText }}\n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],selectOptionsTranslate:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigOldComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:fn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:V,useExisting:a((()=>fn)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class gn{set enableFieldToggle(e){this._enableFieldToggle=pe(e)}get enableFieldToggle(){return this._enableFieldToggle}constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne,this.DataToFetch=ht}ngOnInit(){this.toggleControlGroup=this.fb.group({toggleControl:[null,[]]}),this.toggleControlGroup.get("toggleControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.toggleControlGroup.get("toggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("FetchToDataToggleComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:gn,selector:"tb-fetch-to-data-toggle",inputs:{enableFieldToggle:"enableFieldToggle"},providers:[{provide:V,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n \n {{ \'tb.rulenode.attributes\' | translate }}\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n {{ \'tb.rulenode.fields\' | translate }}\n \n
\n',styles:[":host ::ng-deep{margin-bottom:12px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;width:215px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Re.MatButtonToggleGroup,selector:"mat-button-toggle-group",inputs:["appearance","name","vertical","value","multiple","disabled"],outputs:["valueChange","change"],exportAs:["matButtonToggleGroup"]},{kind:"component",type:Re.MatButtonToggle,selector:"mat-button-toggle",inputs:["disableRipple","aria-label","aria-labelledby","id","name","value","tabIndex","appearance","checked","disabled"],outputs:["change"],exportAs:["matButtonToggle"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-fetch-to-data-toggle",providers:[{provide:V,useExisting:a((()=>gn)),multi:!0}],template:'
\n \n {{ \'tb.rulenode.attributes\' | translate }}\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n {{ \'tb.rulenode.fields\' | translate }}\n \n
\n',styles:[":host ::ng-deep{margin-bottom:12px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;width:215px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{enableFieldToggle:[{type:i}]}});class yn{constructor(e,t,n){this.store=e,this.translate=t,this.fb=n,this.destroy$=new Ne,this.separatorKeysCodes=[oe,ae,ie]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]}),this.attributeControlGroup.valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.attributeControlGroup.patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}removeKey(e,t){const n=this.attributeControlGroup.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.attributeControlGroup.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.attributeControlGroup.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.attributeControlGroup.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}clearChipGrid(e){this.attributeControlGroup.get(e).patchValue([],{emitEvent:!0})}}e("SelectAttributesComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:yn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:V,useExisting:a((()=>yn)),multi:!0}],ngImport:t,template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin:10px 0 12px;display:block}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:V,useExisting:a((()=>yn)),multi:!0}],template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin:10px 0 12px;display:block}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class xn{}e("RulenodeCoreConfigCommonModule",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),xn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:xn,declarations:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn],imports:[H,L,qe],exports:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn]}),xn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,imports:[H,L,qe]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,decorators:[{type:l,args:[{declarations:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn],imports:[H,L,qe],exports:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn]}]}]});class bn{}e("RuleNodeCoreConfigActionModule",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),bn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:bn,declarations:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn],imports:[H,L,qe,xn],exports:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn]}),bn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,imports:[H,L,qe,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,decorators:[{type:l,args:[{declarations:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn],imports:[H,L,qe,xn],exports:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn]}]}]});class hn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[E.min(0),E.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:X(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:X(e?.outputValueKey)?e.outputValueKey:null,useCache:!X(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!X(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:X(e?.periodValueKey)?e.periodValueKey:null,round:X(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!X(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return e.inputValueKey=e.inputValueKey.trim(),e.outputValueKey=e.outputValueKey.trim(),e}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([E.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:hn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Cn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n].trim();return e.dataMapping=t,e}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Cn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class vn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[E.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return Z(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:X(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!X(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:vn,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:yn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.entityDetailsTranslationsMap=gt,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(dt))this.entityDetailsList.push(dt[e]);this.detailsFormControl=new P(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchEntityDetails(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],t=X(e?.addToMetadata)?e.addToMetadata?Dt.METADATA:Dt.DATA:e?.fetchTo?e.fetchTo:Dt.DATA,{detailsList:X(e?.detailsList)?e.detailsList:null,fetchTo:t}}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[E.required]],fetchTo:[e.fetchTo,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(gt.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(this.entityDetailsList.filter((t=>this.translate.instant(gt.get(dt[t])).toUpperCase().includes(e))))}return Ie(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clearChipGrid(){this.detailsList=[],this.entityDetailsConfigForm.get("detailsList").patchValue([],{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Fn,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]},propDecorators:{detailsInput:[{type:o,args:["detailsInput",{static:!1}]}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[oe,ae,ie],this.aggregationTypes=k,this.aggregations=Object.keys(k),this.aggregationTypesTranslations=T,this.fetchMode=yt,this.fetchModes=Object.keys(yt),this.deduplicationStrategiesTranslations=xt,this.samplingOrders=Object.keys(bt),this.samplingOrdersTranslate=Ct,this.timeUnits=Object.values(st),this.timeUnitsTranslationMap=mt,this.timeUnitMap={[st.MILLISECONDS]:1,[st.SECONDS]:1e3,[st.MINUTES]:6e4,[st.HOURS]:36e5,[st.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[]],aggregation:[e.aggregation,[E.required]],fetchMode:[e.fetchMode,[E.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,e.startIntervalPattern=e.startIntervalPattern.trim(),e.endIntervalPattern=e.endIntervalPattern.trim(),delete e.interval,e}prepareInputConfig(e){return Z(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:X(e?.aggregation)?e.aggregation:k.NONE,fetchMode:X(e?.fetchMode)?e.fetchMode:yt.FIRST,orderBy:X(e?.orderBy)?e.orderBy:bt.ASC,limit:X(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!X(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:X(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:X(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:st.MINUTES,endInterval:X(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:X(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:st.MINUTES},startIntervalPattern:X(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:X(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===yt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([E.required,E.min(2),E.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([E.required,E.min(1),E.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([E.required,E.min(1),E.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}fetchModeHintSelector(){let e;switch(this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value){case yt.ALL:e="tb.rulenode.all-mode-hint";break;case yt.LAST:e="tb.rulenode.last-mode-hint";break;case yt.FIRST:e="tb.rulenode.first-mode-hint"}return e}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ln,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ln,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n {{ deduplicationStrategiesTranslations.get(fetchMode) | translate}}\n \n
\n {{ fetchModeHintSelector() | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle mat-button-toggle{width:215px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .additional-inputs{margin-bottom:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:Re.MatButtonToggleGroup,selector:"mat-button-toggle-group",inputs:["appearance","name","vertical","value","multiple","disabled"],outputs:["valueChange","change"],exportAs:["matButtonToggleGroup"]},{kind:"component",type:Re.MatButtonToggle,selector:"mat-button-toggle",inputs:["disableRipple","aria-label","aria-labelledby","id","name","value","tabIndex","appearance","checked","disabled"],outputs:["change"],exportAs:["matButtonToggle"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n {{ deduplicationStrategiesTranslations.get(fetchMode) | translate}}\n \n
\n {{ fetchModeHintSelector() | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle mat-button-toggle{width:215px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .additional-inputs{margin-bottom:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return Z(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA,tellFailureIfAbsent:!!X(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:X(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:kn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:yn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorFields=[],this.originatorFieldsTranslations=ft;for(const e of Object.keys(ct))this.originatorFields.push(ct[e])}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){for(const t of Object.keys(e.dataMapping))e.dataMapping[t]=e.dataMapping[t].trim();return e}prepareInputConfig(e){return{dataMapping:X(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:X(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[E.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Tn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:cn,selector:"tb-sv-map-config",inputs:["selectOptions","selectOptionsTranslate","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class In extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht,this.originatorFieldsTranslations=ft,this.originatorFields=[],this.destroy$=new Ne,this.defaultKvMap={serialNumber:"sn"},this.defaultSvMap={name:"relatedEntityName",type:"relatedEntityType"},this.dataToFetchPrevValue="";for(const e of Object.keys(ct))this.originatorFields.push(ct[e])}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n].trim();return e.dataMapping=t,e}prepareInputConfig(e){let t;return X(e?.telemetry)?this.dataToFetchPrevValue=e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:this.dataToFetchPrevValue=X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,t=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{relationsQuery:X(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:this.dataToFetchPrevValue,dataMapping:t,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[E.required]],dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{e===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultSvMap,{emitEvent:!1}),e!==ht.FIELDS&&this.dataToFetchPrevValue===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultKvMap,{emitEvent:!1}),this.dataToFetchPrevValue=e}))}msgMetadataChipLabel(){switch(this.relatedAttributesConfigForm.get("dataToFetch").value){case ht.ATTRIBUTES:return"tb.rulenode.add-mapped-attribute-to";case ht.LATEST_TELEMETRY:return"tb.rulenode.add-mapped-latest-telemetry-to";case ht.FIELDS:return"tb.rulenode.add-mapped-fields-to"}}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:In,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:In,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:mn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:cn,selector:"tb-sv-map-config",inputs:["selectOptions","selectOptionsTranslate","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Nn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Nn,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Sn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Sn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class qn{}e("RulenodeCoreConfigEnrichmentModule",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),qn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:qn,declarations:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn],imports:[H,L,xn],exports:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn]}),qn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,decorators:[{type:l,args:[{declarations:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn],imports:[H,L,xn],exports:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn]}]}]});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Tt,this.azureIotHubCredentialsTypeTranslationsMap=It}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[E.required,E.min(1),E.max(200)]],clientId:[e?e.clientId:null,[E.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[E.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([E.required]);break;case"cert.PEM":t.get("privateKey").setValidators([E.required]),t.get("privateKeyFileName").setValidators([E.required]),t.get("cert").setValidators([E.required]),t.get("certFileName").setValidators([E.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Mn,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Se.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class An extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=St,this.ToByteStandartCharsetTypeTranslationMap=qt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[E.required]],retries:[e?e.retries:null,[E.min(0)]],batchSize:[e?e.batchSize:null,[E.min(0)]],linger:[e?e.linger:null,[E.min(0)]],bufferMemory:[e?e.bufferMemory:null,[E.min(0)]],acks:[e?e.acks:null,[E.required]],keySerializer:[e?e.keySerializer:null,[E.required]],valueSerializer:[e?e.valueSerializer:null,[E.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([E.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:An,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:An,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Gn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[E.required,E.min(1),E.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&ee(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{ee(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Gn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=I,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[E.required]],targets:[e?e.targets:[],[E.required]]})}}e("NotificationConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:En,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:En,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Oe.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","disabled","notificationTypes"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[E.required]],topicName:[e?e.topicName:null,[E.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[E.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[E.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Dn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Vn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[E.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[E.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Vn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class wn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Nt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[E.required]],requestMethod:[e?e.requestMethod:null,[E.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[E.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[E.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[E.required,E.min(1),E.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([E.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([E.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:wn,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,n=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([E.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([E.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([E.required,E.min(1),E.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([E.required,E.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[E.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[E.required,E.min(1),E.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Pn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ke.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[E.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[E.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([E.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Rn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Be.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(N),this.slackChanelTypesTranslateMap=S}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[E.required]],conversationType:[e?e.conversationType:null,[E.required]],conversation:[e?e.conversation:null,[E.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([E.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:On,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:On,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ze.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[E.required]],accessKeyId:[e?e.accessKeyId:null,[E.required]],secretAccessKey:[e?e.secretAccessKey:null,[E.required]],region:[e?e.region:null,[E.required]]})}}e("SnsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Hn,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Kn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=vt,this.sqsQueueTypes=Object.keys(vt),this.sqsQueueTypeTranslationsMap=Ft}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[E.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[E.required]],delaySeconds:[e?e.delaySeconds:null,[E.min(0),E.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[E.required]],secretAccessKey:[e?e.secretAccessKey:null,[E.required]],region:[e?e.region:null,[E.required]]})}}e("SqsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Bn{}e("RulenodeCoreConfigExternalModule",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Bn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Bn,declarations:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On],imports:[H,L,qe,xn],exports:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On]}),Bn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,imports:[H,L,qe,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,decorators:[{type:l,args:[{declarations:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On],imports:[H,L,qe,xn],exports:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On]}]}]});class Un extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.alarmStatusTranslationsMap=q,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(M))this.alarmStatusList.push(M[e]);this.statusFormControl=new R(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchAlarmStatus(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[E.required]]})}displayStatus(e){return e?this.translate.instant(q.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(t.filter((t=>this.translate.instant(q.get(M[t])).toUpperCase().includes(e))))}return Ie(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const n=t.indexOf(e);n>=0&&(t.splice(n,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Un,deps:[{token:A.Store},{token:_.TranslateService},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Un,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:o,args:["alarmStatusInput",{static:!1}]}]}});class zn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:zn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class _n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[E.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[E.required]:[]],relationType:[e?e.relationType:null,[E.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[E.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[E.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_n,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:_n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:_e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Ee.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","required","disabled","subscriptSizing"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=it,this.perimeterTypes=Object.keys(it),this.perimeterTypeTranslationMap=lt,this.rangeUnits=Object.keys(ut),this.rangeUnitTranslationMap=pt}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[E.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[E.required]],perimeterType:[e?e.perimeterType:null,[E.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([E.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==it.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([E.required,E.min(-90),E.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([E.required,E.min(-180),E.max(180)]),this.geoFilterConfigForm.get("range").setValidators([E.required,E.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([E.required])),t||n!==it.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([E.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[E.required]]})}}e("MessageTypeConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$n,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$n,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:un,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[E.required]]})}}e("OriginatorTypeConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:je.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Jn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Yn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",r=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Yn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Wn{}e("RuleNodeCoreConfigFilterModule",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Wn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Wn,declarations:[zn,_n,jn,$n,Qn,Jn,Yn,Un],imports:[H,L,xn],exports:[zn,_n,jn,$n,Qn,Jn,Yn,Un]}),Wn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,decorators:[{type:l,args:[{declarations:[zn,_n,jn,$n,Qn,Jn,Yn,Un],imports:[H,L,xn],exports:[zn,_n,jn,$n,Qn,Jn,Yn,Un]}]}]});class Xn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=ot,this.originatorSources=Object.keys(ot),this.originatorSourceTranslationMap=at,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[E.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===ot.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([E.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===ot.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([E.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xn,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Zn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[E.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Zn,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[E.required]],toTemplate:[e?e.toTemplate:null,[E.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[E.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[E.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(ve([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(E.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:er,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],keys:[e?e.keys:null,[E.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[E.required]]})}}e("RenameKeysConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nr,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[E.required]]})}}e("NodeJsonPathConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rr,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],keys:[e?e.keys:null,[E.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:or,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class ar{}e("RulenodeCoreConfigTransformModule",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ar.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:ar,declarations:[Xn,Zn,er,tr,nr,rr,or],imports:[H,L,xn],exports:[Xn,Zn,er,tr,nr,rr,or]}),ar.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,decorators:[{type:l,args:[{declarations:[Xn,Zn,er,tr,nr,rr,or],imports:[H,L,xn],exports:[Xn,Zn,er,tr,nr,rr,or]}]}]});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[E.required]]})}}e("RuleChainInputComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ir,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:_e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:lr,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class sr{}e("RuleNodeCoreConfigFlowModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:sr,declarations:[ir,lr],imports:[H,L,xn],exports:[ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,decorators:[{type:l,args:[{declarations:[ir,lr],imports:[H,L,xn],exports:[ir,lr]}]}]});class mr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required!","limit-range":"Limit should be in a range from 2 to 1000!","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647!","start-interval-value-required":"Start interval value is required!","end-interval-value-required":"End interval value is required!",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","add-timeseries-key":"Add timeseries key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Max relation level should be greater than 0 or unspecified!","relation-type":"Relation type","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required!","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required!","target-key":"Target key","target-key-required":"Target key is required!","attr-mapping-required":"At least one mapping entry should be specified!","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","source-field":"Source field","source-field-required":"Source field is required!","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required!","end-interval-required":"Interval end is required!","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","entity-details-list-empty":"No entity details selected!","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required!","output-value-key":"Output value key","output-value-key-required":"Output value key is required!","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15!","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-cashing":"Use cashing","use-cashing-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required!","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","attributes-mapping":"Attributes mapping*","latest-telemetry-mapping":"Latest telemetry mapping*","add-mapped-attribute-to":"Add mapped attributes to:","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to:","add-mapped-fields-to":"Add mapped fields to:","add-selected-details-to":"Add selected details to:","clear-selected-details":"Clear selected details","clear-selected-keys":"Clear selected keys","fetch-credentials-to":"Fetch credentials to:","add-originator-attributes-to":"Add originator attributes to:","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell Failure","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to:",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output message metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end")!',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch:","mapping-of-customers":"Mapping of customer's:",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to:","device-profiles":"Device profiles","mapping-of-tenant":"Mapping of tenant's:","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,deps:[{token:_.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),mr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:mr,declarations:[$e],imports:[H,L],exports:[bn,Wn,qn,Bn,ar,sr,$e]}),mr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,imports:[H,L,bn,Wn,qn,Bn,ar,sr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,decorators:[{type:l,args:[{declarations:[$e],imports:[H,L],exports:[bn,Wn,qn,Bn,ar,sr,$e]}]}],ctorParameters:function(){return[{type:_.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map From d6ec789cb50e519986b97d25f963d6201cdfdb3a Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 1 Jun 2023 12:27:20 +0300 Subject: [PATCH 084/421] add java doc for upgrade method in TbVersionedNode interface --- .../thingsboard/rule/engine/api/TbVersionedNode.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbVersionedNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbVersionedNode.java index be9a5d01e2..95b93fa222 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbVersionedNode.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbVersionedNode.java @@ -20,6 +20,16 @@ import org.thingsboard.server.common.data.util.TbPair; public interface TbVersionedNode extends TbNode { + /** + * Upgrades the configuration from a specific version to the current version specified in the + * {@link RuleNode} annotation for the instance of {@link TbVersionedNode}. + * + * @param fromVersion The version from which the configuration needs to be upgraded. + * @param oldConfiguration The old configuration to be upgraded. + * @return A pair consisting of a Boolean flag indicating the success of the upgrade + * and a JsonNode representing the upgraded configuration. + * @throws TbNodeException If an error occurs during the upgrade process. + */ TbPair upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException; } From 877c917f08b4815672ffc6598d438fbbdaebffa1 Mon Sep 17 00:00:00 2001 From: kalytka Date: Thu, 1 Jun 2023 14:53:13 +0300 Subject: [PATCH 085/421] new rulenode-core-config.js --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 69953bd64f..414c734227 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1 +1 @@ -System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","tslib","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@angular/material/slide-toggle","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@angular/material/button-toggle","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,v,F,L,k,T,I,N,S,q,M,A,G,E,D,V,w,P,R,O,H,K,B,U,z,_,j,$,Q,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,ve,Fe,Le,ke,Te,Ie,Ne,Se,qe,Me,Ae,Ge,Ee,De,Ve,we,Pe,Re,Oe,He,Ke,Be,Ue,ze,_e,je;return{setters:[function(e){t=e,n=e.Component,r=e.Pipe,o=e.ViewChild,a=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.coerceBoolean,C=e.MessageType,v=e.messageTypeNames,F=e,L=e.SharedModule,k=e.AggregationType,T=e.aggregationTranslations,I=e.NotificationType,N=e.SlackChanelType,S=e.SlackChanelTypesTranslateMap,q=e.alarmStatusTranslations,M=e.AlarmStatus},function(e){A=e},function(e){G=e,E=e.Validators,D=e.NgControl,V=e.NG_VALUE_ACCESSOR,w=e.NG_VALIDATORS,P=e.FormControl,R=e.UntypedFormControl},function(e){O=e,H=e.CommonModule},function(e){K=e},function(e){B=e},function(e){U=e},function(e){z=e},function(e){_=e},function(e){j=e},function(e){$=e},function(e){Q=e},function(e){J=e},function(e){Y=e.getCurrentAuthState,W=e,X=e.isDefinedAndNotNull,Z=e.isObject,ee=e.isNotEmptyStr},function(e){te=e},function(e){ne=e},function(e){re=e},function(e){oe=e.ENTER,ae=e.COMMA,ie=e.SEMICOLON},function(e){le=e},function(e){se=e},function(e){me=e},function(e){ue=e},function(e){pe=e.coerceBooleanProperty},function(e){de=e},function(e){ce=e},function(e){fe=e},function(e){ge=e},function(e){ye=e},function(e){xe=e.tap,be=e.map,he=e.mergeMap,Ce=e.takeUntil,ve=e.startWith,Fe=e.share,Le=e.distinctUntilChanged},function(e){ke=e},function(e){Te=e},function(e){Ie=e.of,Ne=e.Subject},function(e){Se=e},function(e){qe=e.HomeComponentsModule},function(e){Me=e.__decorate},function(e){Ae=e},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){we=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e},function(e){Be=e},function(e){Ue=e},function(e){ze=e},function(e){_e=e},function(e){je=e}],execute:function(){class $e extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",$e),$e.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$e,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$e.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$e,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$e,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qe{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Qe),Qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,deps:[{token:j.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Qe.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Qe,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:j.DomSanitizer}]}});class Je extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[E.required,E.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[E.required,E.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Je,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ye,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[E.required]]})}}e("CheckPointConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:We,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Xe extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[E.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[E.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[E.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.clearAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",r=this.clearAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.clearAlarmConfigForm.get(t).setValue(e)}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xe,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Ze extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[oe,ae,ie],this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([E.required]),this.createAlarmConfigForm.get("severity").setValidators([E.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[E.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[E.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",r=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ze,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ze,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[E.required]],entityType:[e?e.entityType:null,[E.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[E.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[E.required,E.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([E.required,E.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:et,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:et,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[E.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[E.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[E.required,E.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([E.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,E.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,E.required]})}}e("DeviceProfileConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nt,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class rt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[E.required,E.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[E.required,E.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",r=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var ot;e("GeneratorConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rt,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rt,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(ot||(ot={}));const at=new Map([[ot.CUSTOMER,"tb.rulenode.originator-customer"],[ot.TENANT,"tb.rulenode.originator-tenant"],[ot.RELATED,"tb.rulenode.originator-related"],[ot.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[ot.ENTITY,"tb.rulenode.originator-entity"]]);var it;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(it||(it={}));const lt=new Map([[it.CIRCLE,"tb.rulenode.perimeter-circle"],[it.POLYGON,"tb.rulenode.perimeter-polygon"]]);var st;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(st||(st={}));const mt=new Map([[st.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[st.SECONDS,"tb.rulenode.time-unit-seconds"],[st.MINUTES,"tb.rulenode.time-unit-minutes"],[st.HOURS,"tb.rulenode.time-unit-hours"],[st.DAYS,"tb.rulenode.time-unit-days"]]);var ut;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(ut||(ut={}));const pt=new Map([[ut.METER,"tb.rulenode.range-unit-meter"],[ut.KILOMETER,"tb.rulenode.range-unit-kilometer"],[ut.FOOT,"tb.rulenode.range-unit-foot"],[ut.MILE,"tb.rulenode.range-unit-mile"],[ut.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var dt,ct;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(dt||(dt={})),function(e){e.NAME="name",e.CREATED_TIME="createdTime",e.TYPE="type",e.FIRST_NAME="firstName",e.LAST_NAME="lastName",e.EMAIL="email",e.TITLE="title",e.COUNTRY="county",e.STATE="state",e.CITY="city",e.ADDRESS="address",e.ADDRESS2="address2",e.ZIP="zip",e.PHONE="phone",e.LABEL="label"}(ct||(ct={}));const ft=new Map([[ct.NAME,"tb.rulenode.name"],[ct.CREATED_TIME,"tb.rulenode.created-time"],[ct.TYPE,"tb.rulenode.type"],[ct.FIRST_NAME,"tb.rulenode.first-name"],[ct.LAST_NAME,"tb.rulenode.last-name"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.LABEL,"tb.rulenode.label"]]),gt=new Map([[dt.ID,"tb.rulenode.entity-details-id"],[dt.TITLE,"tb.rulenode.entity-details-title"],[dt.COUNTRY,"tb.rulenode.entity-details-country"],[dt.STATE,"tb.rulenode.entity-details-state"],[dt.CITY,"tb.rulenode.entity-details-city"],[dt.ZIP,"tb.rulenode.entity-details-zip"],[dt.ADDRESS,"tb.rulenode.entity-details-address"],[dt.ADDRESS2,"tb.rulenode.entity-details-address2"],[dt.PHONE,"tb.rulenode.entity-details-phone"],[dt.EMAIL,"tb.rulenode.entity-details-email"],[dt.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var yt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(yt||(yt={}));const xt=new Map([[yt.FIRST,"tb.rulenode.first"],[yt.LAST,"tb.rulenode.last"],[yt.ALL,"tb.rulenode.all"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const Ct=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var vt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(vt||(vt={}));const Ft=new Map([[vt.STANDARD,"tb.rulenode.sqs-queue-standard"],[vt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Lt=["anonymous","basic","cert.PEM"],kt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Tt=["sas","cert.PEM"],It=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Nt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Nt||(Nt={}));const St=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],qt=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Mt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Mt||(Mt={}));const At=new Map([[Mt.CUSTOM,{value:Mt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Mt.ADD,{value:Mt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Mt.SUB,{value:Mt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Mt.MULT,{value:Mt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Mt.DIV,{value:Mt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Mt.SIN,{value:Mt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Mt.SINH,{value:Mt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Mt.COS,{value:Mt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Mt.COSH,{value:Mt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Mt.TAN,{value:Mt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Mt.TANH,{value:Mt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Mt.ACOS,{value:Mt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Mt.ASIN,{value:Mt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Mt.ATAN,{value:Mt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Mt.ATAN2,{value:Mt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Mt.EXP,{value:Mt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Mt.EXPM1,{value:Mt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Mt.SQRT,{value:Mt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Mt.CBRT,{value:Mt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Mt.GET_EXP,{value:Mt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Mt.HYPOT,{value:Mt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Mt.LOG,{value:Mt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Mt.LOG10,{value:Mt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Mt.LOG1P,{value:Mt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Mt.CEIL,{value:Mt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Mt.FLOOR,{value:Mt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Mt.FLOOR_DIV,{value:Mt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Mt.FLOOR_MOD,{value:Mt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Mt.ABS,{value:Mt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Mt.MIN,{value:Mt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Mt.MAX,{value:Mt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Mt.POW,{value:Mt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Mt.SIGNUM,{value:Mt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Mt.RAD,{value:Mt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Mt.DEG,{value:Mt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Gt,Et,Dt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Gt||(Gt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Et||(Et={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Dt||(Dt={}));const Vt=new Map([[Gt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Gt.TIME_SERIES,"tb.rulenode.time-series-type"],[Gt.CONSTANT,"tb.rulenode.constant-type"],[Gt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Gt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),wt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Pt,Rt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Pt||(Pt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Rt||(Rt={}));const Ot=new Map([[Pt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Pt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Pt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=it,this.perimeterTypes=Object.keys(it),this.perimeterTypeTranslationMap=lt,this.rangeUnits=Object.keys(ut),this.rangeUnitTranslationMap=pt,this.timeUnits=Object.keys(st),this.timeUnitsTranslationMap=mt}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[E.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[E.required]],perimeterType:[e?e.perimeterType:null,[E.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[E.required,E.min(1),E.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[E.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[E.required,E.min(1),E.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[E.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([E.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==it.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([E.required,E.min(-90),E.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([E.required,E.min(-180),E.max(180)]),this.geoActionConfigForm.get("range").setValidators([E.required,E.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([E.required])),t||n!==it.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([E.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ht,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Kt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",r=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[E.required,E.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[E.required]]})}}e("MsgCountConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Bt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[E.required,E.min(1),E.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([E.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([E.required,E.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ut,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]]})}}e("PushToCloudConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:zt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]]})}}e("PushToEdgeConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:_t,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:jt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[E.required,E.min(0)]]})}}e("RpcRequestConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$t,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required]],value:[e[n],[E.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[E.required]],value:["",[E.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigOldComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:V,useExisting:a((()=>Qt)),multi:!0},{provide:w,useExisting:a((()=>Qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:V,useExisting:a((()=>Qt)),multi:!0},{provide:w,useExisting:a((()=>Qt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[E.required,E.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[E.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Jt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[E.required,E.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Yt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Wt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[E.required,E.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[E.required,E.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Wt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]],keys:[e?e.keys:null,[E.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xt,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class Zt extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup())}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=At,this.ArgumentType=Gt,this.attributeScopeMap=Ot,this.argumentTypeResultMap=Vt,this.arguments=Object.values(Gt),this.attributeScope=Object.values(Pt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({}),this.argumentsFormGroup.addControl("arguments",this.fb.array([])),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):this.argumentsFormGroup.enable({emitEvent:!1})}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()));const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t)),this.setupArgumentsFormGroup(),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()})))}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(){const e=this.argumentsFormGroup.get("arguments"),t=this.createArgumentControl(null,e.length);e.push(t)}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Mt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([E.minLength(this.minArgs),E.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!0}),n.get("defaultValue").updateValueAndValidity({emitEvent:!0})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Gt.ATTRIBUTE?e.get("attributeScope").enable():e.get("attributeScope").disable(),t&&t!==Gt.CONSTANT?e.get("defaultValue").enable():e.get("defaultValue").disable()}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(wt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Zt,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:V,useExisting:a((()=>Zt)),multi:!0},{provide:w,useExisting:a((()=>Zt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"],dependencies:[{kind:"directive",type:O.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ge.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:ge.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:ye.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:ye.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:ye.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:V,useExisting:a((()=>Zt)),multi:!0},{provide:w,useExisting:a((()=>Zt)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class en extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...At.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(xe((e=>{let t;t="string"==typeof e&&Mt[e]?Mt[e]:null,this.updateView(t)})),be((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=At.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:en,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:en,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:V,useExisting:a((()=>en)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:en,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:V,useExisting:a((()=>en)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Mt,this.ArgumentTypeResult=Et,this.argumentTypeResultMap=Vt,this.attributeScopeMap=Ot,this.argumentsResult=Object.values(Et),this.attributeScopeResult=Object.values(Rt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[E.required]],arguments:[e?e.arguments:null,[E.required]],customFunction:[e?e.customFunction:"",[E.required]],result:this.fb.group({type:[e?e.result.type:null,[E.required]],attributeScope:[e?e.result.attributeScope:null],key:[e?e.result.key:"",[E.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result").get("type").value;t===Mt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Et.ATTRIBUTE?this.mathFunctionConfigForm.get("result").get("attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result").get("attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result").get("attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tn,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Zt,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:en,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tn,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nn{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[E.required,E.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(xe((e=>{this.updateView(e)})),be((e=>e||"")),he((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,Ie(this.messageTypes).pipe(be((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nn,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:V,useExisting:a((()=>nn)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:V,useExisting:a((()=>nn)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Ne,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=yt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=xt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[X(e?.interval)?e.interval:null,[E.required,E.min(1)]],strategy:[X(e?.strategy)?e.strategy:null,[E.required]],outMsgType:[X(e?.outMsgType)?e.outMsgType:null,[E.required]],queueName:[X(e?.queueName)?e.queueName:null,[E.required]],maxPendingMsgs:[X(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[E.required,E.min(1),E.max(1e3)]],maxRetries:[X(e?.maxRetries)?e.maxRetries:null,[E.required,E.min(0),E.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:nn,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class on extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:on,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:on,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:V,useExisting:a((()=>on)),multi:!0},{provide:w,useExisting:a((()=>on)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n \n \n \n
\n
\n {{ hintText }}\n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),Me([h()],on.prototype,"disabled",void 0),Me([h()],on.prototype,"uniqueKeyValuePairValidator",void 0),Me([h()],on.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:V,useExisting:a((()=>on)),multi:!0},{provide:w,useExisting:a((()=>on)),multi:!0}],template:'
\n
\n \n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n \n \n \n
\n
\n {{ hintText }}\n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class an{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne}ngOnInit(){this.slideToggleControlGroup=this.fb.group({slideToggleControl:[null,[]]}),this.slideToggleControlGroup.get("slideToggleControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.slideToggleControlGroup.get("slideToggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SlideToggleComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:an,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:an,selector:"tb-slide-toggle",inputs:{slideToggleName:"slideToggleName",slideToggleTooltip:"slideToggleTooltip"},providers:[{provide:V,useExisting:a((()=>an)),multi:!0}],ngImport:t,template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"],dependencies:[{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:De.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-slide-toggle",providers:[{provide:V,useExisting:a((()=>an)),multi:!0}],template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{slideToggleName:[{type:i}],slideToggleTooltip:[{type:i}]}});class ln extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[E.min(1)]],relationType:[null],deviceTypes:[null,[E.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ln,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ln,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>ln)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["label","required","disabled","entityType"]},{kind:"component",type:Ee.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","required","disabled","subscriptSizing"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:V,useExisting:a((()=>ln)),multi:!0}],template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class sn{set required(e){this.requiredValue=pe(e)}get required(){return this.requiredValue}}e("FieldsetComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sn,deps:[],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:sn,selector:"tb-fieldset-component",inputs:{label:"label",required:"required"},ngImport:t,template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-fieldset-component",template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],propDecorators:{label:[{type:i}],required:[{type:i}]}});class mn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[E.min(1)]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:mn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>mn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:V,useExisting:a((()=>mn)),multi:!0}],template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class un extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[oe,ae,ie],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(C))this.messageTypesList.push({name:v.get(C[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchMessageTypes(e))),Fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ie(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:un,deps:[{token:A.Store},{token:_.TranslateService},{token:F.TruncatePipe},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:un,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:V,useExisting:a((()=>un)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:V,useExisting:a((()=>un)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:F.TruncatePipe},{type:G.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class pn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Lt,this.credentialsTypeTranslationsMap=kt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[E.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(Le()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){X(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([E.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[E.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(E.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:pn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:V,useExisting:a((()=>pn)),multi:!0},{provide:w,useExisting:a((()=>pn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Se.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:V,useExisting:a((()=>pn)),multi:!0},{provide:w,useExisting:a((()=>pn)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRquired:[{type:i}]}});class dn{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne,this.fetchTo=Dt}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:dn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:V,useExisting:a((()=>dn)),multi:!0}],ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.message\' | translate }}\n {{ \'tb.rulenode.metadata\' | translate }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"],dependencies:[{kind:"component",type:se.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:se.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:V,useExisting:a((()=>dn)),multi:!0}],template:'
\n \n \n {{ \'tb.rulenode.message\' | translate }}\n {{ \'tb.rulenode.metadata\' | translate }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{labelText:[{type:i}]}});class cn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Ne,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required]],value:[e[n],[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.updateModel()}))}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value)t.push(this.selectOptions.find((t=>t===e.key)));const n=[];for(const r of this.selectOptions)X(t.find((e=>e===r)))&&r!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[E.required]],value:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.controls[e.length-1])}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Ce(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{kvMapRequired:!0}:this.svListFormGroup.valid?null:{kvFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cn,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:cn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",selectOptionsTranslate:"selectOptionsTranslate",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:V,useExisting:a((()=>cn)),multi:!0},{provide:w,useExisting:a((()=>cn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n \n {{ selectText }}\n \n \n {{selectOptionsTranslate.get(option) | translate}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n \n \n
\n
\n {{ hintText }}\n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),Me([h()],cn.prototype,"disabled",void 0),Me([h()],cn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:V,useExisting:a((()=>cn)),multi:!0},{provide:w,useExisting:a((()=>cn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n \n {{ selectText }}\n \n \n {{selectOptionsTranslate.get(option) | translate}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n \n \n
\n
\n {{ hintText }}\n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],selectOptionsTranslate:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigOldComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:fn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:V,useExisting:a((()=>fn)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class gn{set enableFieldToggle(e){this._enableFieldToggle=pe(e)}get enableFieldToggle(){return this._enableFieldToggle}constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne,this.DataToFetch=ht}ngOnInit(){this.toggleControlGroup=this.fb.group({toggleControl:[null,[]]}),this.toggleControlGroup.get("toggleControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.toggleControlGroup.get("toggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("FetchToDataToggleComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:gn,selector:"tb-fetch-to-data-toggle",inputs:{enableFieldToggle:"enableFieldToggle"},providers:[{provide:V,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n \n {{ \'tb.rulenode.attributes\' | translate }}\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n {{ \'tb.rulenode.fields\' | translate }}\n \n
\n',styles:[":host ::ng-deep{margin-bottom:12px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;width:215px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Re.MatButtonToggleGroup,selector:"mat-button-toggle-group",inputs:["appearance","name","vertical","value","multiple","disabled"],outputs:["valueChange","change"],exportAs:["matButtonToggleGroup"]},{kind:"component",type:Re.MatButtonToggle,selector:"mat-button-toggle",inputs:["disableRipple","aria-label","aria-labelledby","id","name","value","tabIndex","appearance","checked","disabled"],outputs:["change"],exportAs:["matButtonToggle"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-fetch-to-data-toggle",providers:[{provide:V,useExisting:a((()=>gn)),multi:!0}],template:'
\n \n {{ \'tb.rulenode.attributes\' | translate }}\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n {{ \'tb.rulenode.fields\' | translate }}\n \n
\n',styles:[":host ::ng-deep{margin-bottom:12px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;width:215px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{enableFieldToggle:[{type:i}]}});class yn{constructor(e,t,n){this.store=e,this.translate=t,this.fb=n,this.destroy$=new Ne,this.separatorKeysCodes=[oe,ae,ie]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]}),this.attributeControlGroup.valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.attributeControlGroup.patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}removeKey(e,t){const n=this.attributeControlGroup.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.attributeControlGroup.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.attributeControlGroup.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.attributeControlGroup.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}clearChipGrid(e){this.attributeControlGroup.get(e).patchValue([],{emitEvent:!0})}}e("SelectAttributesComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:yn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:V,useExisting:a((()=>yn)),multi:!0}],ngImport:t,template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin:10px 0 12px;display:block}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:V,useExisting:a((()=>yn)),multi:!0}],template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin:10px 0 12px;display:block}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class xn{}e("RulenodeCoreConfigCommonModule",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),xn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:xn,declarations:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn],imports:[H,L,qe],exports:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn]}),xn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,imports:[H,L,qe]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,decorators:[{type:l,args:[{declarations:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn],imports:[H,L,qe],exports:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn]}]}]});class bn{}e("RuleNodeCoreConfigActionModule",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),bn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:bn,declarations:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn],imports:[H,L,qe,xn],exports:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn]}),bn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,imports:[H,L,qe,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,decorators:[{type:l,args:[{declarations:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn],imports:[H,L,qe,xn],exports:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn]}]}]});class hn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[E.min(0),E.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:X(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:X(e?.outputValueKey)?e.outputValueKey:null,useCache:!X(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!X(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:X(e?.periodValueKey)?e.periodValueKey:null,round:X(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!X(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return e.inputValueKey=e.inputValueKey.trim(),e.outputValueKey=e.outputValueKey.trim(),e}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([E.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:hn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Cn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n].trim();return e.dataMapping=t,e}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Cn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class vn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[E.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return Z(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:X(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!X(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:vn,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:yn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.entityDetailsTranslationsMap=gt,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(dt))this.entityDetailsList.push(dt[e]);this.detailsFormControl=new P(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchEntityDetails(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],t=X(e?.addToMetadata)?e.addToMetadata?Dt.METADATA:Dt.DATA:e?.fetchTo?e.fetchTo:Dt.DATA,{detailsList:X(e?.detailsList)?e.detailsList:null,fetchTo:t}}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[E.required]],fetchTo:[e.fetchTo,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(gt.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(this.entityDetailsList.filter((t=>this.translate.instant(gt.get(dt[t])).toUpperCase().includes(e))))}return Ie(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clearChipGrid(){this.detailsList=[],this.entityDetailsConfigForm.get("detailsList").patchValue([],{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Fn,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]},propDecorators:{detailsInput:[{type:o,args:["detailsInput",{static:!1}]}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[oe,ae,ie],this.aggregationTypes=k,this.aggregations=Object.keys(k),this.aggregationTypesTranslations=T,this.fetchMode=yt,this.fetchModes=Object.keys(yt),this.deduplicationStrategiesTranslations=xt,this.samplingOrders=Object.keys(bt),this.samplingOrdersTranslate=Ct,this.timeUnits=Object.values(st),this.timeUnitsTranslationMap=mt,this.timeUnitMap={[st.MILLISECONDS]:1,[st.SECONDS]:1e3,[st.MINUTES]:6e4,[st.HOURS]:36e5,[st.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[]],aggregation:[e.aggregation,[E.required]],fetchMode:[e.fetchMode,[E.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,e.startIntervalPattern=e.startIntervalPattern.trim(),e.endIntervalPattern=e.endIntervalPattern.trim(),delete e.interval,e}prepareInputConfig(e){return Z(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:X(e?.aggregation)?e.aggregation:k.NONE,fetchMode:X(e?.fetchMode)?e.fetchMode:yt.FIRST,orderBy:X(e?.orderBy)?e.orderBy:bt.ASC,limit:X(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!X(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:X(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:X(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:st.MINUTES,endInterval:X(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:X(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:st.MINUTES},startIntervalPattern:X(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:X(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===yt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([E.required,E.min(2),E.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([E.required,E.min(1),E.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([E.required,E.min(1),E.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}fetchModeHintSelector(){let e;switch(this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value){case yt.ALL:e="tb.rulenode.all-mode-hint";break;case yt.LAST:e="tb.rulenode.last-mode-hint";break;case yt.FIRST:e="tb.rulenode.first-mode-hint"}return e}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ln,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ln,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n {{ deduplicationStrategiesTranslations.get(fetchMode) | translate}}\n \n
\n {{ fetchModeHintSelector() | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle mat-button-toggle{width:215px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .additional-inputs{margin-bottom:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:Re.MatButtonToggleGroup,selector:"mat-button-toggle-group",inputs:["appearance","name","vertical","value","multiple","disabled"],outputs:["valueChange","change"],exportAs:["matButtonToggleGroup"]},{kind:"component",type:Re.MatButtonToggle,selector:"mat-button-toggle",inputs:["disableRipple","aria-label","aria-labelledby","id","name","value","tabIndex","appearance","checked","disabled"],outputs:["change"],exportAs:["matButtonToggle"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n {{ deduplicationStrategiesTranslations.get(fetchMode) | translate}}\n \n
\n {{ fetchModeHintSelector() | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle mat-button-toggle{width:215px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .additional-inputs{margin-bottom:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return Z(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA,tellFailureIfAbsent:!!X(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:X(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:kn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:yn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorFields=[],this.originatorFieldsTranslations=ft;for(const e of Object.keys(ct))this.originatorFields.push(ct[e])}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){for(const t of Object.keys(e.dataMapping))e.dataMapping[t]=e.dataMapping[t].trim();return e}prepareInputConfig(e){return{dataMapping:X(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:X(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[E.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Tn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:cn,selector:"tb-sv-map-config",inputs:["selectOptions","selectOptionsTranslate","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class In extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht,this.originatorFieldsTranslations=ft,this.originatorFields=[],this.destroy$=new Ne,this.defaultKvMap={serialNumber:"sn"},this.defaultSvMap={name:"relatedEntityName",type:"relatedEntityType"},this.dataToFetchPrevValue="";for(const e of Object.keys(ct))this.originatorFields.push(ct[e])}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n].trim();return e.dataMapping=t,e}prepareInputConfig(e){let t;return X(e?.telemetry)?this.dataToFetchPrevValue=e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:this.dataToFetchPrevValue=X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,t=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{relationsQuery:X(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:this.dataToFetchPrevValue,dataMapping:t,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[E.required]],dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{e===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultSvMap,{emitEvent:!1}),e!==ht.FIELDS&&this.dataToFetchPrevValue===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultKvMap,{emitEvent:!1}),this.dataToFetchPrevValue=e}))}msgMetadataChipLabel(){switch(this.relatedAttributesConfigForm.get("dataToFetch").value){case ht.ATTRIBUTES:return"tb.rulenode.add-mapped-attribute-to";case ht.LATEST_TELEMETRY:return"tb.rulenode.add-mapped-latest-telemetry-to";case ht.FIELDS:return"tb.rulenode.add-mapped-fields-to"}}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:In,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:In,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:mn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:cn,selector:"tb-sv-map-config",inputs:["selectOptions","selectOptionsTranslate","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Nn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Nn,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Sn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Sn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class qn{}e("RulenodeCoreConfigEnrichmentModule",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),qn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:qn,declarations:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn],imports:[H,L,xn],exports:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn]}),qn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,decorators:[{type:l,args:[{declarations:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn],imports:[H,L,xn],exports:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn]}]}]});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Tt,this.azureIotHubCredentialsTypeTranslationsMap=It}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[E.required,E.min(1),E.max(200)]],clientId:[e?e.clientId:null,[E.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[E.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([E.required]);break;case"cert.PEM":t.get("privateKey").setValidators([E.required]),t.get("privateKeyFileName").setValidators([E.required]),t.get("cert").setValidators([E.required]),t.get("certFileName").setValidators([E.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Mn,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Se.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class An extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=St,this.ToByteStandartCharsetTypeTranslationMap=qt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[E.required]],retries:[e?e.retries:null,[E.min(0)]],batchSize:[e?e.batchSize:null,[E.min(0)]],linger:[e?e.linger:null,[E.min(0)]],bufferMemory:[e?e.bufferMemory:null,[E.min(0)]],acks:[e?e.acks:null,[E.required]],keySerializer:[e?e.keySerializer:null,[E.required]],valueSerializer:[e?e.valueSerializer:null,[E.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([E.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:An,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:An,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Gn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[E.required,E.min(1),E.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&ee(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{ee(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Gn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=I,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[E.required]],targets:[e?e.targets:[],[E.required]]})}}e("NotificationConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:En,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:En,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Oe.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","disabled","notificationTypes"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[E.required]],topicName:[e?e.topicName:null,[E.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[E.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[E.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Dn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Vn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[E.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[E.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Vn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class wn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Nt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[E.required]],requestMethod:[e?e.requestMethod:null,[E.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[E.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[E.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[E.required,E.min(1),E.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([E.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([E.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:wn,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,n=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([E.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([E.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([E.required,E.min(1),E.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([E.required,E.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[E.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[E.required,E.min(1),E.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Pn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ke.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[E.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[E.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([E.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Rn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Be.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(N),this.slackChanelTypesTranslateMap=S}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[E.required]],conversationType:[e?e.conversationType:null,[E.required]],conversation:[e?e.conversation:null,[E.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([E.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:On,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:On,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ze.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[E.required]],accessKeyId:[e?e.accessKeyId:null,[E.required]],secretAccessKey:[e?e.secretAccessKey:null,[E.required]],region:[e?e.region:null,[E.required]]})}}e("SnsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Hn,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Kn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=vt,this.sqsQueueTypes=Object.keys(vt),this.sqsQueueTypeTranslationsMap=Ft}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[E.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[E.required]],delaySeconds:[e?e.delaySeconds:null,[E.min(0),E.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[E.required]],secretAccessKey:[e?e.secretAccessKey:null,[E.required]],region:[e?e.region:null,[E.required]]})}}e("SqsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Bn{}e("RulenodeCoreConfigExternalModule",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Bn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Bn,declarations:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On],imports:[H,L,qe,xn],exports:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On]}),Bn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,imports:[H,L,qe,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,decorators:[{type:l,args:[{declarations:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On],imports:[H,L,qe,xn],exports:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On]}]}]});class Un extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.alarmStatusTranslationsMap=q,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(M))this.alarmStatusList.push(M[e]);this.statusFormControl=new R(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchAlarmStatus(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[E.required]]})}displayStatus(e){return e?this.translate.instant(q.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(t.filter((t=>this.translate.instant(q.get(M[t])).toUpperCase().includes(e))))}return Ie(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const n=t.indexOf(e);n>=0&&(t.splice(n,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Un,deps:[{token:A.Store},{token:_.TranslateService},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Un,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:o,args:["alarmStatusInput",{static:!1}]}]}});class zn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:zn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class _n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[E.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[E.required]:[]],relationType:[e?e.relationType:null,[E.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[E.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[E.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_n,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:_n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:_e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Ee.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","required","disabled","subscriptSizing"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=it,this.perimeterTypes=Object.keys(it),this.perimeterTypeTranslationMap=lt,this.rangeUnits=Object.keys(ut),this.rangeUnitTranslationMap=pt}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[E.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[E.required]],perimeterType:[e?e.perimeterType:null,[E.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([E.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==it.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([E.required,E.min(-90),E.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([E.required,E.min(-180),E.max(180)]),this.geoFilterConfigForm.get("range").setValidators([E.required,E.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([E.required])),t||n!==it.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([E.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[E.required]]})}}e("MessageTypeConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$n,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$n,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:un,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[E.required]]})}}e("OriginatorTypeConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:je.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Jn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Yn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",r=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Yn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Wn{}e("RuleNodeCoreConfigFilterModule",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Wn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Wn,declarations:[zn,_n,jn,$n,Qn,Jn,Yn,Un],imports:[H,L,xn],exports:[zn,_n,jn,$n,Qn,Jn,Yn,Un]}),Wn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,decorators:[{type:l,args:[{declarations:[zn,_n,jn,$n,Qn,Jn,Yn,Un],imports:[H,L,xn],exports:[zn,_n,jn,$n,Qn,Jn,Yn,Un]}]}]});class Xn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=ot,this.originatorSources=Object.keys(ot),this.originatorSourceTranslationMap=at,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[E.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===ot.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([E.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===ot.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([E.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xn,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Zn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[E.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Zn,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[E.required]],toTemplate:[e?e.toTemplate:null,[E.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[E.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[E.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(ve([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(E.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:er,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],keys:[e?e.keys:null,[E.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[E.required]]})}}e("RenameKeysConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nr,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[E.required]]})}}e("NodeJsonPathConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rr,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],keys:[e?e.keys:null,[E.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:or,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class ar{}e("RulenodeCoreConfigTransformModule",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ar.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:ar,declarations:[Xn,Zn,er,tr,nr,rr,or],imports:[H,L,xn],exports:[Xn,Zn,er,tr,nr,rr,or]}),ar.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,decorators:[{type:l,args:[{declarations:[Xn,Zn,er,tr,nr,rr,or],imports:[H,L,xn],exports:[Xn,Zn,er,tr,nr,rr,or]}]}]});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[E.required]]})}}e("RuleChainInputComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ir,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:_e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:lr,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class sr{}e("RuleNodeCoreConfigFlowModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:sr,declarations:[ir,lr],imports:[H,L,xn],exports:[ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,decorators:[{type:l,args:[{declarations:[ir,lr],imports:[H,L,xn],exports:[ir,lr]}]}]});class mr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required!","limit-range":"Limit should be in a range from 2 to 1000!","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647!","start-interval-value-required":"Start interval value is required!","end-interval-value-required":"End interval value is required!",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","add-timeseries-key":"Add timeseries key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Max relation level should be greater than 0 or unspecified!","relation-type":"Relation type","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required!","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required!","target-key":"Target key","target-key-required":"Target key is required!","attr-mapping-required":"At least one mapping entry should be specified!","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","source-field":"Source field","source-field-required":"Source field is required!","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required!","end-interval-required":"Interval end is required!","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","entity-details-list-empty":"No entity details selected!","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required!","output-value-key":"Output value key","output-value-key-required":"Output value key is required!","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15!","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-cashing":"Use cashing","use-cashing-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required!","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","attributes-mapping":"Attributes mapping*","latest-telemetry-mapping":"Latest telemetry mapping*","add-mapped-attribute-to":"Add mapped attributes to:","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to:","add-mapped-fields-to":"Add mapped fields to:","add-selected-details-to":"Add selected details to:","clear-selected-details":"Clear selected details","clear-selected-keys":"Clear selected keys","fetch-credentials-to":"Fetch credentials to:","add-originator-attributes-to":"Add originator attributes to:","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell Failure","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to:",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output message metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end")!',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch:","mapping-of-customers":"Mapping of customer's:",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to:","device-profiles":"Device profiles","mapping-of-tenant":"Mapping of tenant's:","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,deps:[{token:_.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),mr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:mr,declarations:[$e],imports:[H,L],exports:[bn,Wn,qn,Bn,ar,sr,$e]}),mr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,imports:[H,L,bn,Wn,qn,Bn,ar,sr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,decorators:[{type:l,args:[{declarations:[$e],imports:[H,L],exports:[bn,Wn,qn,Bn,ar,sr,$e]}]}],ctorParameters:function(){return[{type:_.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","tslib","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@angular/material/slide-toggle","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@angular/material/button-toggle","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,v,F,L,k,T,I,N,S,q,M,A,G,E,D,V,w,P,R,O,H,K,B,U,z,_,j,$,Q,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,ve,Fe,Le,ke,Te,Ie,Ne,Se,qe,Me,Ae,Ge,Ee,De,Ve,we,Pe,Re,Oe,He,Ke,Be,Ue,ze,_e,je;return{setters:[function(e){t=e,n=e.Component,r=e.Pipe,o=e.ViewChild,a=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.coerceBoolean,C=e.MessageType,v=e.messageTypeNames,F=e,L=e.SharedModule,k=e.AggregationType,T=e.aggregationTranslations,I=e.NotificationType,N=e.SlackChanelType,S=e.SlackChanelTypesTranslateMap,q=e.alarmStatusTranslations,M=e.AlarmStatus},function(e){A=e},function(e){G=e,E=e.Validators,D=e.NgControl,V=e.NG_VALUE_ACCESSOR,w=e.NG_VALIDATORS,P=e.FormControl,R=e.UntypedFormControl},function(e){O=e,H=e.CommonModule},function(e){K=e},function(e){B=e},function(e){U=e},function(e){z=e},function(e){_=e},function(e){j=e},function(e){$=e},function(e){Q=e},function(e){J=e},function(e){Y=e.getCurrentAuthState,W=e,X=e.isDefinedAndNotNull,Z=e.isObject,ee=e.isNotEmptyStr},function(e){te=e},function(e){ne=e},function(e){re=e},function(e){oe=e.ENTER,ae=e.COMMA,ie=e.SEMICOLON},function(e){le=e},function(e){se=e},function(e){me=e},function(e){ue=e},function(e){pe=e.coerceBooleanProperty},function(e){de=e},function(e){ce=e},function(e){fe=e},function(e){ge=e},function(e){ye=e},function(e){xe=e.tap,be=e.map,he=e.mergeMap,Ce=e.takeUntil,ve=e.startWith,Fe=e.share,Le=e.distinctUntilChanged},function(e){ke=e},function(e){Te=e},function(e){Ie=e.of,Ne=e.Subject},function(e){Se=e},function(e){qe=e.HomeComponentsModule},function(e){Me=e.__decorate},function(e){Ae=e},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){we=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e},function(e){Be=e},function(e){Ue=e},function(e){ze=e},function(e){_e=e},function(e){je=e}],execute:function(){class $e extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",$e),$e.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$e,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$e.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$e,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$e,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qe{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Qe),Qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,deps:[{token:j.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Qe.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Qe,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:j.DomSanitizer}]}});class Je extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[E.required,E.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[E.required,E.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Je,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ye,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[E.required]]})}}e("CheckPointConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:We,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Xe extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[E.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[E.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[E.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.clearAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",r=this.clearAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.clearAlarmConfigForm.get(t).setValue(e)}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xe,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Ze extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[oe,ae,ie],this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([E.required]),this.createAlarmConfigForm.get("severity").setValidators([E.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[E.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[E.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",r=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ze,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ze,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[E.required]],entityType:[e?e.entityType:null,[E.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[E.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[E.required,E.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([E.required,E.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:et,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:et,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[E.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[E.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[E.required,E.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([E.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,E.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,E.required]})}}e("DeviceProfileConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nt,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class rt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[E.required,E.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[E.required,E.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",r=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var ot;e("GeneratorConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rt,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rt,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(ot||(ot={}));const at=new Map([[ot.CUSTOMER,"tb.rulenode.originator-customer"],[ot.TENANT,"tb.rulenode.originator-tenant"],[ot.RELATED,"tb.rulenode.originator-related"],[ot.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[ot.ENTITY,"tb.rulenode.originator-entity"]]);var it;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(it||(it={}));const lt=new Map([[it.CIRCLE,"tb.rulenode.perimeter-circle"],[it.POLYGON,"tb.rulenode.perimeter-polygon"]]);var st;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(st||(st={}));const mt=new Map([[st.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[st.SECONDS,"tb.rulenode.time-unit-seconds"],[st.MINUTES,"tb.rulenode.time-unit-minutes"],[st.HOURS,"tb.rulenode.time-unit-hours"],[st.DAYS,"tb.rulenode.time-unit-days"]]);var ut;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(ut||(ut={}));const pt=new Map([[ut.METER,"tb.rulenode.range-unit-meter"],[ut.KILOMETER,"tb.rulenode.range-unit-kilometer"],[ut.FOOT,"tb.rulenode.range-unit-foot"],[ut.MILE,"tb.rulenode.range-unit-mile"],[ut.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var dt,ct;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(dt||(dt={})),function(e){e.NAME="name",e.CREATED_TIME="createdTime",e.TYPE="type",e.FIRST_NAME="firstName",e.LAST_NAME="lastName",e.EMAIL="email",e.TITLE="title",e.COUNTRY="county",e.STATE="state",e.CITY="city",e.ADDRESS="address",e.ADDRESS2="address2",e.ZIP="zip",e.PHONE="phone",e.LABEL="label"}(ct||(ct={}));const ft=new Map([[ct.NAME,"tb.rulenode.name"],[ct.CREATED_TIME,"tb.rulenode.created-time"],[ct.TYPE,"tb.rulenode.type"],[ct.FIRST_NAME,"tb.rulenode.first-name"],[ct.LAST_NAME,"tb.rulenode.last-name"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.LABEL,"tb.rulenode.label"]]),gt=new Map([[dt.ID,"tb.rulenode.entity-details-id"],[dt.TITLE,"tb.rulenode.entity-details-title"],[dt.COUNTRY,"tb.rulenode.entity-details-country"],[dt.STATE,"tb.rulenode.entity-details-state"],[dt.CITY,"tb.rulenode.entity-details-city"],[dt.ZIP,"tb.rulenode.entity-details-zip"],[dt.ADDRESS,"tb.rulenode.entity-details-address"],[dt.ADDRESS2,"tb.rulenode.entity-details-address2"],[dt.PHONE,"tb.rulenode.entity-details-phone"],[dt.EMAIL,"tb.rulenode.entity-details-email"],[dt.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var yt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(yt||(yt={}));const xt=new Map([[yt.FIRST,"tb.rulenode.first"],[yt.LAST,"tb.rulenode.last"],[yt.ALL,"tb.rulenode.all"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const Ct=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var vt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(vt||(vt={}));const Ft=new Map([[vt.STANDARD,"tb.rulenode.sqs-queue-standard"],[vt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Lt=["anonymous","basic","cert.PEM"],kt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Tt=["sas","cert.PEM"],It=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Nt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Nt||(Nt={}));const St=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],qt=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Mt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Mt||(Mt={}));const At=new Map([[Mt.CUSTOM,{value:Mt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Mt.ADD,{value:Mt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Mt.SUB,{value:Mt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Mt.MULT,{value:Mt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Mt.DIV,{value:Mt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Mt.SIN,{value:Mt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Mt.SINH,{value:Mt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Mt.COS,{value:Mt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Mt.COSH,{value:Mt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Mt.TAN,{value:Mt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Mt.TANH,{value:Mt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Mt.ACOS,{value:Mt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Mt.ASIN,{value:Mt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Mt.ATAN,{value:Mt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Mt.ATAN2,{value:Mt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Mt.EXP,{value:Mt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Mt.EXPM1,{value:Mt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Mt.SQRT,{value:Mt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Mt.CBRT,{value:Mt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Mt.GET_EXP,{value:Mt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Mt.HYPOT,{value:Mt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Mt.LOG,{value:Mt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Mt.LOG10,{value:Mt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Mt.LOG1P,{value:Mt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Mt.CEIL,{value:Mt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Mt.FLOOR,{value:Mt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Mt.FLOOR_DIV,{value:Mt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Mt.FLOOR_MOD,{value:Mt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Mt.ABS,{value:Mt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Mt.MIN,{value:Mt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Mt.MAX,{value:Mt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Mt.POW,{value:Mt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Mt.SIGNUM,{value:Mt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Mt.RAD,{value:Mt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Mt.DEG,{value:Mt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Gt,Et,Dt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Gt||(Gt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Et||(Et={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Dt||(Dt={}));const Vt=new Map([[Gt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Gt.TIME_SERIES,"tb.rulenode.time-series-type"],[Gt.CONSTANT,"tb.rulenode.constant-type"],[Gt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Gt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),wt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Pt,Rt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Pt||(Pt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Rt||(Rt={}));const Ot=new Map([[Pt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Pt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Pt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=it,this.perimeterTypes=Object.keys(it),this.perimeterTypeTranslationMap=lt,this.rangeUnits=Object.keys(ut),this.rangeUnitTranslationMap=pt,this.timeUnits=Object.keys(st),this.timeUnitsTranslationMap=mt}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[E.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[E.required]],perimeterType:[e?e.perimeterType:null,[E.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[E.required,E.min(1),E.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[E.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[E.required,E.min(1),E.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[E.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([E.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==it.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([E.required,E.min(-90),E.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([E.required,E.min(-180),E.max(180)]),this.geoActionConfigForm.get("range").setValidators([E.required,E.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([E.required])),t||n!==it.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([E.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ht,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Kt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",r=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[E.required,E.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[E.required]]})}}e("MsgCountConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Bt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[E.required,E.min(1),E.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([E.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([E.required,E.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ut,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]]})}}e("PushToCloudConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:zt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]]})}}e("PushToEdgeConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:_t,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:jt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[E.required,E.min(0)]]})}}e("RpcRequestConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$t,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required]],value:[e[n],[E.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[E.required]],value:["",[E.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigOldComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:V,useExisting:a((()=>Qt)),multi:!0},{provide:w,useExisting:a((()=>Qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:V,useExisting:a((()=>Qt)),multi:!0},{provide:w,useExisting:a((()=>Qt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[E.required,E.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[E.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Jt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[E.required,E.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Yt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Wt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[E.required,E.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[E.required,E.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Wt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]],keys:[e?e.keys:null,[E.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xt,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class Zt extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup())}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=At,this.ArgumentType=Gt,this.attributeScopeMap=Ot,this.argumentTypeResultMap=Vt,this.arguments=Object.values(Gt),this.attributeScope=Object.values(Pt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({}),this.argumentsFormGroup.addControl("arguments",this.fb.array([])),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):this.argumentsFormGroup.enable({emitEvent:!1})}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()));const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t)),this.setupArgumentsFormGroup(),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()})))}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(){const e=this.argumentsFormGroup.get("arguments"),t=this.createArgumentControl(null,e.length);e.push(t)}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Mt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([E.minLength(this.minArgs),E.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!0}),n.get("defaultValue").updateValueAndValidity({emitEvent:!0})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Gt.ATTRIBUTE?e.get("attributeScope").enable():e.get("attributeScope").disable(),t&&t!==Gt.CONSTANT?e.get("defaultValue").enable():e.get("defaultValue").disable()}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(wt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Zt,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:V,useExisting:a((()=>Zt)),multi:!0},{provide:w,useExisting:a((()=>Zt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"],dependencies:[{kind:"directive",type:O.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ge.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:ge.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:ye.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:ye.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:ye.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:V,useExisting:a((()=>Zt)),multi:!0},{provide:w,useExisting:a((()=>Zt)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class en extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...At.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(xe((e=>{let t;t="string"==typeof e&&Mt[e]?Mt[e]:null,this.updateView(t)})),be((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=At.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:en,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:en,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:V,useExisting:a((()=>en)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:en,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:V,useExisting:a((()=>en)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Mt,this.ArgumentTypeResult=Et,this.argumentTypeResultMap=Vt,this.attributeScopeMap=Ot,this.argumentsResult=Object.values(Et),this.attributeScopeResult=Object.values(Rt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[E.required]],arguments:[e?e.arguments:null,[E.required]],customFunction:[e?e.customFunction:"",[E.required]],result:this.fb.group({type:[e?e.result.type:null,[E.required]],attributeScope:[e?e.result.attributeScope:null],key:[e?e.result.key:"",[E.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result").get("type").value;t===Mt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Et.ATTRIBUTE?this.mathFunctionConfigForm.get("result").get("attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result").get("attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result").get("attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tn,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Zt,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:en,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tn,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nn{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[E.required,E.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(xe((e=>{this.updateView(e)})),be((e=>e||"")),he((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,Ie(this.messageTypes).pipe(be((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nn,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:V,useExisting:a((()=>nn)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:V,useExisting:a((()=>nn)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Ne,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=yt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=xt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[X(e?.interval)?e.interval:null,[E.required,E.min(1)]],strategy:[X(e?.strategy)?e.strategy:null,[E.required]],outMsgType:[X(e?.outMsgType)?e.outMsgType:null,[E.required]],queueName:[X(e?.queueName)?e.queueName:null,[E.required]],maxPendingMsgs:[X(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[E.required,E.min(1),E.max(1e3)]],maxRetries:[X(e?.maxRetries)?e.maxRetries:null,[E.required,E.min(0),E.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:nn,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class on extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:on,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:on,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:V,useExisting:a((()=>on)),multi:!0},{provide:w,useExisting:a((()=>on)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n {{ hintText }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),Me([h()],on.prototype,"disabled",void 0),Me([h()],on.prototype,"uniqueKeyValuePairValidator",void 0),Me([h()],on.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:V,useExisting:a((()=>on)),multi:!0},{provide:w,useExisting:a((()=>on)),multi:!0}],template:'
\n
\n \n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n {{ hintText }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class an{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne}ngOnInit(){this.slideToggleControlGroup=this.fb.group({slideToggleControl:[null,[]]}),this.slideToggleControlGroup.get("slideToggleControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.slideToggleControlGroup.get("slideToggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SlideToggleComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:an,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:an,selector:"tb-slide-toggle",inputs:{slideToggleName:"slideToggleName",slideToggleTooltip:"slideToggleTooltip"},providers:[{provide:V,useExisting:a((()=>an)),multi:!0}],ngImport:t,template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"],dependencies:[{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:De.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-slide-toggle",providers:[{provide:V,useExisting:a((()=>an)),multi:!0}],template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{slideToggleName:[{type:i}],slideToggleTooltip:[{type:i}]}});class ln extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[E.min(1)]],relationType:[null],deviceTypes:[null,[E.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ln,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ln,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>ln)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["label","required","disabled","entityType"]},{kind:"component",type:Ee.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","required","disabled","subscriptSizing"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:V,useExisting:a((()=>ln)),multi:!0}],template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class sn{set required(e){this.requiredValue=pe(e)}get required(){return this.requiredValue}}e("FieldsetComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sn,deps:[],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:sn,selector:"tb-fieldset-component",inputs:{label:"label",required:"required"},ngImport:t,template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-fieldset-component",template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],propDecorators:{label:[{type:i}],required:[{type:i}]}});class mn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[E.min(1)]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:mn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>mn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:V,useExisting:a((()=>mn)),multi:!0}],template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class un extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[oe,ae,ie],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(C))this.messageTypesList.push({name:v.get(C[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchMessageTypes(e))),Fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ie(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:un,deps:[{token:A.Store},{token:_.TranslateService},{token:F.TruncatePipe},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:un,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:V,useExisting:a((()=>un)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:V,useExisting:a((()=>un)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:F.TruncatePipe},{type:G.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class pn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Lt,this.credentialsTypeTranslationsMap=kt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[E.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(Le()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){X(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([E.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[E.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(E.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:pn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:V,useExisting:a((()=>pn)),multi:!0},{provide:w,useExisting:a((()=>pn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Se.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:V,useExisting:a((()=>pn)),multi:!0},{provide:w,useExisting:a((()=>pn)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRquired:[{type:i}]}});class dn{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne,this.fetchTo=Dt}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:dn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:V,useExisting:a((()=>dn)),multi:!0}],ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.message\' | translate }}\n {{ \'tb.rulenode.metadata\' | translate }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"],dependencies:[{kind:"component",type:se.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:se.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:V,useExisting:a((()=>dn)),multi:!0}],template:'
\n \n \n {{ \'tb.rulenode.message\' | translate }}\n {{ \'tb.rulenode.metadata\' | translate }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{labelText:[{type:i}]}});class cn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Ne,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required]],value:[e[n],[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.updateModel()}))}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value)t.push(this.selectOptions.find((t=>t===e.key)));const n=[];for(const r of this.selectOptions)X(t.find((e=>e===r)))&&r!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[E.required]],value:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.controls[e.length-1])}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Ce(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cn,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:cn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",selectOptionsTranslate:"selectOptionsTranslate",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:V,useExisting:a((()=>cn)),multi:!0},{provide:w,useExisting:a((()=>cn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n \n {{ selectText }}\n \n \n {{selectOptionsTranslate.get(option) | translate}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n {{ hintText }}\n \n
\n
\n
\n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),Me([h()],cn.prototype,"disabled",void 0),Me([h()],cn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:V,useExisting:a((()=>cn)),multi:!0},{provide:w,useExisting:a((()=>cn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n \n {{ selectText }}\n \n \n {{selectOptionsTranslate.get(option) | translate}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n {{ hintText }}\n \n
\n
\n
\n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],selectOptionsTranslate:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigOldComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:fn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:V,useExisting:a((()=>fn)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class gn{set enableFieldToggle(e){this._enableFieldToggle=pe(e)}get enableFieldToggle(){return this._enableFieldToggle}constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne,this.DataToFetch=ht}ngOnInit(){this.toggleControlGroup=this.fb.group({toggleControl:[null,[]]}),this.toggleControlGroup.get("toggleControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.toggleControlGroup.get("toggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("FetchToDataToggleComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:gn,selector:"tb-fetch-to-data-toggle",inputs:{enableFieldToggle:"enableFieldToggle"},providers:[{provide:V,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n \n {{ \'tb.rulenode.attributes\' | translate }}\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n {{ \'tb.rulenode.fields\' | translate }}\n \n
\n',styles:[":host ::ng-deep{margin-bottom:12px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;width:215px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Re.MatButtonToggleGroup,selector:"mat-button-toggle-group",inputs:["appearance","name","vertical","value","multiple","disabled"],outputs:["valueChange","change"],exportAs:["matButtonToggleGroup"]},{kind:"component",type:Re.MatButtonToggle,selector:"mat-button-toggle",inputs:["disableRipple","aria-label","aria-labelledby","id","name","value","tabIndex","appearance","checked","disabled"],outputs:["change"],exportAs:["matButtonToggle"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-fetch-to-data-toggle",providers:[{provide:V,useExisting:a((()=>gn)),multi:!0}],template:'
\n \n {{ \'tb.rulenode.attributes\' | translate }}\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n {{ \'tb.rulenode.fields\' | translate }}\n \n
\n',styles:[":host ::ng-deep{margin-bottom:12px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;width:215px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{enableFieldToggle:[{type:i}]}});class yn{constructor(e,t,n){this.store=e,this.translate=t,this.fb=n,this.destroy$=new Ne,this.separatorKeysCodes=[oe,ae,ie]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]}),this.attributeControlGroup.valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.attributeControlGroup.patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}removeKey(e,t){const n=this.attributeControlGroup.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.attributeControlGroup.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.attributeControlGroup.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.attributeControlGroup.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}clearChipGrid(e){this.attributeControlGroup.get(e).patchValue([],{emitEvent:!0})}}e("SelectAttributesComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:yn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:V,useExisting:a((()=>yn)),multi:!0}],ngImport:t,template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin:10px 0 12px;display:block}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:V,useExisting:a((()=>yn)),multi:!0}],template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin:10px 0 12px;display:block}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class xn{}e("RulenodeCoreConfigCommonModule",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),xn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:xn,declarations:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn],imports:[H,L,qe],exports:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn]}),xn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,imports:[H,L,qe]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,decorators:[{type:l,args:[{declarations:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn],imports:[H,L,qe],exports:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn]}]}]});class bn{}e("RuleNodeCoreConfigActionModule",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),bn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:bn,declarations:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn],imports:[H,L,qe,xn],exports:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn]}),bn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,imports:[H,L,qe,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,decorators:[{type:l,args:[{declarations:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn],imports:[H,L,qe,xn],exports:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn]}]}]});class hn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[E.min(0),E.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:X(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:X(e?.outputValueKey)?e.outputValueKey:null,useCache:!X(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!X(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:X(e?.periodValueKey)?e.periodValueKey:null,round:X(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!X(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return e.inputValueKey=e.inputValueKey.trim(),e.outputValueKey=e.outputValueKey.trim(),e}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([E.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:hn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Cn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n].trim();return e.dataMapping=t,e}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Cn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class vn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[E.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return Z(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:X(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!X(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:vn,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:yn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.entityDetailsTranslationsMap=gt,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(dt))this.entityDetailsList.push(dt[e]);this.detailsFormControl=new P(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchEntityDetails(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],t=X(e?.addToMetadata)?e.addToMetadata?Dt.METADATA:Dt.DATA:e?.fetchTo?e.fetchTo:Dt.DATA,{detailsList:X(e?.detailsList)?e.detailsList:null,fetchTo:t}}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[E.required]],fetchTo:[e.fetchTo,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(gt.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(this.entityDetailsList.filter((t=>this.translate.instant(gt.get(dt[t])).toUpperCase().includes(e))))}return Ie(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clearChipGrid(){this.detailsList=[],this.entityDetailsConfigForm.get("detailsList").patchValue([],{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Fn,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]},propDecorators:{detailsInput:[{type:o,args:["detailsInput",{static:!1}]}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[oe,ae,ie],this.aggregationTypes=k,this.aggregations=Object.keys(k),this.aggregationTypesTranslations=T,this.fetchMode=yt,this.fetchModes=Object.keys(yt),this.deduplicationStrategiesTranslations=xt,this.samplingOrders=Object.keys(bt),this.samplingOrdersTranslate=Ct,this.timeUnits=Object.values(st),this.timeUnitsTranslationMap=mt,this.timeUnitMap={[st.MILLISECONDS]:1,[st.SECONDS]:1e3,[st.MINUTES]:6e4,[st.HOURS]:36e5,[st.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[]],aggregation:[e.aggregation,[E.required]],fetchMode:[e.fetchMode,[E.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,e.startIntervalPattern=e.startIntervalPattern.trim(),e.endIntervalPattern=e.endIntervalPattern.trim(),delete e.interval,e}prepareInputConfig(e){return Z(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:X(e?.aggregation)?e.aggregation:k.NONE,fetchMode:X(e?.fetchMode)?e.fetchMode:yt.FIRST,orderBy:X(e?.orderBy)?e.orderBy:bt.ASC,limit:X(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!X(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:X(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:X(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:st.MINUTES,endInterval:X(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:X(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:st.MINUTES},startIntervalPattern:X(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:X(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===yt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([E.required,E.min(2),E.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([E.required,E.min(1),E.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([E.required,E.min(1),E.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}fetchModeHintSelector(){let e;switch(this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value){case yt.ALL:e="tb.rulenode.all-mode-hint";break;case yt.LAST:e="tb.rulenode.last-mode-hint";break;case yt.FIRST:e="tb.rulenode.first-mode-hint"}return e}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ln,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ln,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n {{ deduplicationStrategiesTranslations.get(fetchMode) | translate}}\n \n
\n {{ fetchModeHintSelector() | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle mat-button-toggle{width:215px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .additional-inputs{margin-bottom:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:Re.MatButtonToggleGroup,selector:"mat-button-toggle-group",inputs:["appearance","name","vertical","value","multiple","disabled"],outputs:["valueChange","change"],exportAs:["matButtonToggleGroup"]},{kind:"component",type:Re.MatButtonToggle,selector:"mat-button-toggle",inputs:["disableRipple","aria-label","aria-labelledby","id","name","value","tabIndex","appearance","checked","disabled"],outputs:["change"],exportAs:["matButtonToggle"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n {{ deduplicationStrategiesTranslations.get(fetchMode) | translate}}\n \n
\n {{ fetchModeHintSelector() | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle mat-button-toggle{width:215px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .additional-inputs{margin-bottom:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return Z(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA,tellFailureIfAbsent:!!X(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:X(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:kn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:yn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorFields=[],this.originatorFieldsTranslations=ft;for(const e of Object.keys(ct))this.originatorFields.push(ct[e])}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){for(const t of Object.keys(e.dataMapping))e.dataMapping[t]=e.dataMapping[t].trim();return e}prepareInputConfig(e){return{dataMapping:X(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:X(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[E.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Tn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:cn,selector:"tb-sv-map-config",inputs:["selectOptions","selectOptionsTranslate","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class In extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht,this.originatorFieldsTranslations=ft,this.originatorFields=[],this.destroy$=new Ne,this.defaultKvMap={serialNumber:"sn"},this.defaultSvMap={name:"relatedEntityName"},this.dataToFetchPrevValue="";for(const e of Object.keys(ct))this.originatorFields.push(ct[e])}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n].trim();return e.dataMapping=t,e}prepareInputConfig(e){let t;return X(e?.telemetry)?this.dataToFetchPrevValue=e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:this.dataToFetchPrevValue=X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,t=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{relationsQuery:X(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:this.dataToFetchPrevValue,dataMapping:t,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[E.required]],dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{e===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultSvMap,{emitEvent:!1}),e!==ht.FIELDS&&this.dataToFetchPrevValue===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultKvMap,{emitEvent:!1}),this.dataToFetchPrevValue=e}))}msgMetadataChipLabel(){switch(this.relatedAttributesConfigForm.get("dataToFetch").value){case ht.ATTRIBUTES:return"tb.rulenode.add-mapped-attribute-to";case ht.LATEST_TELEMETRY:return"tb.rulenode.add-mapped-latest-telemetry-to";case ht.FIELDS:return"tb.rulenode.add-mapped-fields-to"}}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:In,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:In,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:mn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:cn,selector:"tb-sv-map-config",inputs:["selectOptions","selectOptionsTranslate","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Nn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Nn,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Sn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Sn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class qn{}e("RulenodeCoreConfigEnrichmentModule",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),qn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:qn,declarations:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn],imports:[H,L,xn],exports:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn]}),qn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,decorators:[{type:l,args:[{declarations:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn],imports:[H,L,xn],exports:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn]}]}]});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Tt,this.azureIotHubCredentialsTypeTranslationsMap=It}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[E.required,E.min(1),E.max(200)]],clientId:[e?e.clientId:null,[E.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[E.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([E.required]);break;case"cert.PEM":t.get("privateKey").setValidators([E.required]),t.get("privateKeyFileName").setValidators([E.required]),t.get("cert").setValidators([E.required]),t.get("certFileName").setValidators([E.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Mn,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Se.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class An extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=St,this.ToByteStandartCharsetTypeTranslationMap=qt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[E.required]],retries:[e?e.retries:null,[E.min(0)]],batchSize:[e?e.batchSize:null,[E.min(0)]],linger:[e?e.linger:null,[E.min(0)]],bufferMemory:[e?e.bufferMemory:null,[E.min(0)]],acks:[e?e.acks:null,[E.required]],keySerializer:[e?e.keySerializer:null,[E.required]],valueSerializer:[e?e.valueSerializer:null,[E.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([E.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:An,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:An,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Gn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[E.required,E.min(1),E.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&ee(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{ee(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Gn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=I,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[E.required]],targets:[e?e.targets:[],[E.required]]})}}e("NotificationConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:En,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:En,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Oe.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","disabled","notificationTypes"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[E.required]],topicName:[e?e.topicName:null,[E.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[E.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[E.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Dn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Vn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[E.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[E.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Vn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class wn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Nt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[E.required]],requestMethod:[e?e.requestMethod:null,[E.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[E.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[E.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[E.required,E.min(1),E.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([E.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([E.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:wn,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,n=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([E.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([E.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([E.required,E.min(1),E.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([E.required,E.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[E.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[E.required,E.min(1),E.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Pn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ke.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[E.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[E.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([E.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Rn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Be.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(N),this.slackChanelTypesTranslateMap=S}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[E.required]],conversationType:[e?e.conversationType:null,[E.required]],conversation:[e?e.conversation:null,[E.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([E.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:On,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:On,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ze.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[E.required]],accessKeyId:[e?e.accessKeyId:null,[E.required]],secretAccessKey:[e?e.secretAccessKey:null,[E.required]],region:[e?e.region:null,[E.required]]})}}e("SnsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Hn,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Kn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=vt,this.sqsQueueTypes=Object.keys(vt),this.sqsQueueTypeTranslationsMap=Ft}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[E.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[E.required]],delaySeconds:[e?e.delaySeconds:null,[E.min(0),E.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[E.required]],secretAccessKey:[e?e.secretAccessKey:null,[E.required]],region:[e?e.region:null,[E.required]]})}}e("SqsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Bn{}e("RulenodeCoreConfigExternalModule",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Bn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Bn,declarations:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On],imports:[H,L,qe,xn],exports:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On]}),Bn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,imports:[H,L,qe,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,decorators:[{type:l,args:[{declarations:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On],imports:[H,L,qe,xn],exports:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On]}]}]});class Un extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.alarmStatusTranslationsMap=q,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(M))this.alarmStatusList.push(M[e]);this.statusFormControl=new R(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchAlarmStatus(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[E.required]]})}displayStatus(e){return e?this.translate.instant(q.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(t.filter((t=>this.translate.instant(q.get(M[t])).toUpperCase().includes(e))))}return Ie(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const n=t.indexOf(e);n>=0&&(t.splice(n,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Un,deps:[{token:A.Store},{token:_.TranslateService},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Un,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:o,args:["alarmStatusInput",{static:!1}]}]}});class zn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:zn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class _n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[E.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[E.required]:[]],relationType:[e?e.relationType:null,[E.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[E.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[E.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_n,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:_n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:_e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Ee.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","required","disabled","subscriptSizing"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=it,this.perimeterTypes=Object.keys(it),this.perimeterTypeTranslationMap=lt,this.rangeUnits=Object.keys(ut),this.rangeUnitTranslationMap=pt}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[E.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[E.required]],perimeterType:[e?e.perimeterType:null,[E.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([E.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==it.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([E.required,E.min(-90),E.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([E.required,E.min(-180),E.max(180)]),this.geoFilterConfigForm.get("range").setValidators([E.required,E.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([E.required])),t||n!==it.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([E.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[E.required]]})}}e("MessageTypeConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$n,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$n,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:un,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[E.required]]})}}e("OriginatorTypeConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:je.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Jn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Yn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",r=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Yn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Wn{}e("RuleNodeCoreConfigFilterModule",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Wn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Wn,declarations:[zn,_n,jn,$n,Qn,Jn,Yn,Un],imports:[H,L,xn],exports:[zn,_n,jn,$n,Qn,Jn,Yn,Un]}),Wn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,decorators:[{type:l,args:[{declarations:[zn,_n,jn,$n,Qn,Jn,Yn,Un],imports:[H,L,xn],exports:[zn,_n,jn,$n,Qn,Jn,Yn,Un]}]}]});class Xn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=ot,this.originatorSources=Object.keys(ot),this.originatorSourceTranslationMap=at,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[E.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===ot.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([E.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===ot.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([E.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xn,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Zn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[E.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Zn,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[E.required]],toTemplate:[e?e.toTemplate:null,[E.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[E.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[E.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(ve([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(E.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:er,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],keys:[e?e.keys:null,[E.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[E.required]]})}}e("RenameKeysConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nr,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[E.required]]})}}e("NodeJsonPathConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rr,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],keys:[e?e.keys:null,[E.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:or,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class ar{}e("RulenodeCoreConfigTransformModule",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ar.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:ar,declarations:[Xn,Zn,er,tr,nr,rr,or],imports:[H,L,xn],exports:[Xn,Zn,er,tr,nr,rr,or]}),ar.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,decorators:[{type:l,args:[{declarations:[Xn,Zn,er,tr,nr,rr,or],imports:[H,L,xn],exports:[Xn,Zn,er,tr,nr,rr,or]}]}]});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[E.required]]})}}e("RuleChainInputComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ir,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:_e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:lr,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class sr{}e("RuleNodeCoreConfigFlowModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:sr,declarations:[ir,lr],imports:[H,L,xn],exports:[ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,decorators:[{type:l,args:[{declarations:[ir,lr],imports:[H,L,xn],exports:[ir,lr]}]}]});class mr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required!","limit-range":"Limit should be in a range from 2 to 1000!","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647!","start-interval-value-required":"Start interval value is required!","end-interval-value-required":"End interval value is required!",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","add-timeseries-key":"Add timeseries key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Max relation level should be greater than 0 or unspecified!","relation-type":"Relation type","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required!","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required!","target-key":"Target key","target-key-required":"Target key is required!","attr-mapping-required":"At least one mapping entry should be specified!","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","source-field":"Source field","source-field-required":"Source field is required!","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required!","end-interval-required":"Interval end is required!","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","entity-details-list-empty":"No entity details selected!","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required!","output-value-key":"Output value key","output-value-key-required":"Output value key is required!","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15!","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-cashing":"Use cashing","use-cashing-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required!","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","attributes-mapping":"Attributes mapping*","latest-telemetry-mapping":"Latest telemetry mapping*","add-mapped-attribute-to":"Add mapped attributes to:","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to:","add-mapped-fields-to":"Add mapped fields to:","add-selected-details-to":"Add selected details to:","clear-selected-details":"Clear selected details","clear-selected-keys":"Clear selected keys","fetch-credentials-to":"Fetch credentials to:","add-originator-attributes-to":"Add originator attributes to:","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell Failure","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to:",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output message metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end")!',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch:","mapping-of-customers":"Mapping of customer's:",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to:","device-profiles":"Device profiles","mapping-of-tenant":"Mapping of tenant's:","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,deps:[{token:_.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),mr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:mr,declarations:[$e],imports:[H,L],exports:[bn,Wn,qn,Bn,ar,sr,$e]}),mr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,imports:[H,L,bn,Wn,qn,Bn,ar,sr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,decorators:[{type:l,args:[{declarations:[$e],imports:[H,L],exports:[bn,Wn,qn,Bn,ar,sr,$e]}]}],ctorParameters:function(){return[{type:_.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map From c4c7224dd03d7385600b0673046fb11f1c9c9a87 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 2 Jun 2023 11:50:31 +0300 Subject: [PATCH 086/421] removed one level of nesting in transformSuccess method --- .../transform/TbAbstractTransformNode.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java index b2a1599e8c..093c76a161 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java @@ -60,25 +60,23 @@ public abstract class TbAbstractTransformNode implements TbNode { } protected void transformSuccess(TbContext ctx, TbMsg msg, List msgs) { - if (msgs != null && !msgs.isEmpty()) { - if (msgs.size() == 1) { - ctx.tellSuccess(msgs.get(0)); - } else { - TbMsgCallbackWrapper wrapper = new MultipleTbMsgsCallbackWrapper(msgs.size(), new TbMsgCallback() { - @Override - public void onSuccess() { - ctx.ack(msg); - } - - @Override - public void onFailure(RuleEngineException e) { - ctx.tellFailure(msg, e); - } - }); - msgs.forEach(newMsg -> ctx.enqueueForTellNext(newMsg, TbRelationTypes.SUCCESS, wrapper::onSuccess, wrapper::onFailure)); - } - } else { + if (msgs == null || msgs.isEmpty()) { ctx.tellFailure(msg, new RuntimeException("Message or messages list are empty!")); + } else if (msgs.size() == 1) { + ctx.tellSuccess(msgs.get(0)); + } else { + TbMsgCallbackWrapper wrapper = new MultipleTbMsgsCallbackWrapper(msgs.size(), new TbMsgCallback() { + @Override + public void onSuccess() { + ctx.ack(msg); + } + + @Override + public void onFailure(RuleEngineException e) { + ctx.tellFailure(msg, e); + } + }); + msgs.forEach(newMsg -> ctx.enqueueForTellNext(newMsg, TbRelationTypes.SUCCESS, wrapper::onSuccess, wrapper::onFailure)); } } From 3cb7d517a6989ebe41b63b0d422610a72d4a1f21 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 2 Jun 2023 13:15:47 +0300 Subject: [PATCH 087/421] removed unused import in TbAbstractTransformNode --- .../rule/engine/transform/TbAbstractTransformNode.java | 1 - 1 file changed, 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java index 093c76a161..7bf08e8647 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java @@ -23,7 +23,6 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; -import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.queue.RuleEngineException; import org.thingsboard.server.common.msg.queue.TbMsgCallback; From 2f560315d16b759fd985a979a4eba84c829a4c00 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 2 Jun 2023 15:09:09 +0300 Subject: [PATCH 088/421] Exceeded rate limits notifications; their deduplication; refactoring --- .../config/RateLimitProcessingFilter.java | 6 +- .../server/controller/AuthController.java | 2 +- .../controller/plugin/TbWebSocketHandler.java | 2 +- .../install/ThingsboardInstallService.java | 1 + .../DefaultSystemDataLoaderService.java | 5 + .../install/SystemDataLoaderService.java | 2 + .../DefaultNotificationCenter.java | 2 +- .../DefaultNotificationRuleProcessor.java | 2 +- .../trigger/RateLimitsTriggerProcessor.java | 71 ++++++++++ .../auth/mfa/DefaultTwoFactorAuthService.java | 2 +- .../DefaultEntitiesExportImportService.java | 2 +- .../src/main/resources/thingsboard.yml | 3 + .../service/limits/RateLimitServiceTest.java | 10 +- .../MockNotificationSettingsService.java | 2 +- .../notification/NotificationRuleApiTest.java | 129 +++++++++++++++++- .../NotificationSettingsService.java | 2 + .../NotificationTargetService.java | 3 + .../server/common/data/limit/LimitedApi.java | 70 ++++++++++ .../data/notification/NotificationType.java | 3 +- .../info/RateLimitsNotificationInfo.java | 59 ++++++++ .../NotificationRuleTriggerConfig.java | 1 + .../trigger/NotificationRuleTriggerType.java | 3 +- ...teLimitsNotificationRuleTriggerConfig.java | 45 ++++++ .../trigger/RateLimitsTrigger.java | 62 +++++++++ .../provider/AwsSqsTransportQueueFactory.java | 6 + .../InMemoryTbTransportQueueFactory.java | 6 + .../KafkaTbTransportQueueFactory.java | 12 ++ .../provider/PubSubTransportQueueFactory.java | 7 + .../RabbitMqTransportQueueFactory.java | 7 + .../ServiceBusTransportQueueFactory.java | 7 + .../provider/TbTransportQueueFactory.java | 3 + .../TbTransportQueueProducerProvider.java | 4 +- .../DefaultTransportRateLimitService.java | 27 ++-- .../service/DefaultTransportService.java | 15 +- .../DefaultNotificationSettingsService.java | 32 +++++ .../DefaultNotificationTargetService.java | 6 + .../notification/DefaultNotifications.java | 52 +++++++ .../notification/NotificationTargetDao.java | 3 + .../JpaNotificationTargetDao.java | 6 + .../util/AbstractBufferedRateExecutor.java | 2 +- .../util/limits/DefaultRateLimitService.java | 22 ++- .../server/dao/util/limits/LimitedApi.java | 67 --------- .../dao/util/limits/RateLimitService.java | 1 + .../src/main/resources/tb-vc-executor.yml | 7 + .../src/main/resources/tb-coap-transport.yml | 7 + .../src/main/resources/tb-http-transport.yml | 7 + .../src/main/resources/tb-lwm2m-transport.yml | 7 + .../src/main/resources/tb-mqtt-transport.yml | 7 + .../src/main/resources/tb-snmp-transport.yml | 7 + 49 files changed, 709 insertions(+), 107 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RateLimitsTriggerProcessor.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/limit/LimitedApi.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RateLimitsNotificationInfo.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsNotificationRuleTriggerConfig.java create mode 100644 common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RateLimitsTrigger.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/limits/LimitedApi.java diff --git a/application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java b/application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java index 89f9b751fd..2ecc8590b8 100644 --- a/application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java +++ b/application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java @@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.exception.TenantProfileNotFoundException; import org.thingsboard.server.common.msg.tools.TbRateLimitsException; import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; -import org.thingsboard.server.dao.util.limits.LimitedApi; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import org.thingsboard.server.service.security.model.SecurityUser; @@ -49,7 +49,7 @@ public class RateLimitProcessingFilter extends OncePerRequestFilter { SecurityUser user = getCurrentUser(); if (user != null && !user.isSystemAdmin()) { try { - if (!rateLimitService.checkRateLimit(LimitedApi.REST_REQUESTS, user.getTenantId())) { + if (!rateLimitService.checkRateLimit(LimitedApi.REST_REQUESTS_PER_TENANT, user.getTenantId())) { rateLimitExceeded(EntityType.TENANT, response); return; } @@ -60,7 +60,7 @@ public class RateLimitProcessingFilter extends OncePerRequestFilter { } if (user.isCustomerUser()) { - if (!rateLimitService.checkRateLimit(LimitedApi.REST_REQUESTS, user.getTenantId(), user.getCustomerId())) { + if (!rateLimitService.checkRateLimit(LimitedApi.REST_REQUESTS_PER_CUSTOMER, user.getTenantId(), user.getCustomerId())) { rateLimitExceeded(EntityType.CUSTOMER, response); return; } diff --git a/application/src/main/java/org/thingsboard/server/controller/AuthController.java b/application/src/main/java/org/thingsboard/server/controller/AuthController.java index 566b6900a4..4512334d61 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AuthController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AuthController.java @@ -49,7 +49,7 @@ import org.thingsboard.server.common.data.security.model.JwtPair; import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.dao.util.limits.LimitedApi; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails; import org.thingsboard.server.service.security.model.ActivateUserRequest; diff --git a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java index bc51c5fdd1..91583136f6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java +++ b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java @@ -36,7 +36,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.config.WebSocketConfiguration; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.util.limits.LimitedApi; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.model.SecurityUser; diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 51d7435f0e..c6b9fe08a0 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -260,6 +260,7 @@ public class ThingsboardInstallService { case "3.5.1": log.info("Upgrading ThingsBoard from version 3.5.1 to 3.5.2 ..."); databaseEntitiesUpgradeService.upgradeDatabase("3.5.1"); + systemDataLoaderService.updateDefaultNotificationConfigs(); //TODO DON'T FORGET to update switch statement in the CacheCleanupService if you need to clear the cache break; default: diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 497627f629..7965824274 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -709,4 +709,9 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { executor.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS); } + @Override + public void updateDefaultNotificationConfigs() { + notificationSettingsService.updateDefaultNotificationConfigs(TenantId.SYS_TENANT_ID); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java index fb6b28592c..08de12da78 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java @@ -41,4 +41,6 @@ public interface SystemDataLoaderService { void createDefaultNotificationConfigs(); + void updateDefaultNotificationConfigs(); + } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index 7215776170..cb77cc0948 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.id.NotificationTargetId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.data.notification.AlreadySentException; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; @@ -56,7 +57,6 @@ import org.thingsboard.server.dao.notification.NotificationService; import org.thingsboard.server.dao.notification.NotificationSettingsService; import org.thingsboard.server.dao.notification.NotificationTargetService; import org.thingsboard.server.dao.notification.NotificationTemplateService; -import org.thingsboard.server.dao.util.limits.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.common.TbProtoQueueMsg; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java index 71a59026a2..3a5ae8339d 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.NotificationRequestId; import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.data.notification.NotificationRequest; import org.thingsboard.server.common.data.notification.NotificationRequestConfig; import org.thingsboard.server.common.data.notification.NotificationRequestStatus; @@ -46,7 +47,6 @@ import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTr import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.dao.notification.NotificationRequestService; -import org.thingsboard.server.dao.util.limits.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.service.executors.NotificationExecutorService; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RateLimitsTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RateLimitsTriggerProcessor.java new file mode 100644 index 0000000000..910ef4866f --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RateLimitsTriggerProcessor.java @@ -0,0 +1,71 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.notification.rule.trigger; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.notification.info.RateLimitsNotificationInfo; +import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.util.CollectionsUtil; +import org.thingsboard.server.common.msg.notification.trigger.RateLimitsTrigger; +import org.thingsboard.server.dao.entity.EntityService; +import org.thingsboard.server.dao.tenant.TenantService; + +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class RateLimitsTriggerProcessor implements NotificationRuleTriggerProcessor { + + private final TenantService tenantService; + private final EntityService entityService; + + @Override + public boolean matchesFilter(RateLimitsTrigger trigger, RateLimitsNotificationRuleTriggerConfig triggerConfig) { + return trigger.getLimitLevel() != null && trigger.getApi().getLabel() != null && + CollectionsUtil.emptyOrContains(triggerConfig.getApis(), trigger.getApi()); + } + + @Override + public RuleOriginatedNotificationInfo constructNotificationInfo(RateLimitsTrigger trigger) { + EntityId limitLevel = trigger.getLimitLevel(); + String tenantName = tenantService.findTenantById(trigger.getTenantId()).getName(); + String limitLevelEntityName = null; + if (limitLevel instanceof TenantId) { + limitLevelEntityName = tenantName; + } else if (limitLevel != null) { + limitLevelEntityName = Optional.ofNullable(trigger.getLimitLevelEntityName()) + .orElseGet(() -> entityService.fetchEntityName(trigger.getTenantId(), limitLevel).orElse(null)); + } + return RateLimitsNotificationInfo.builder() + .tenantId(trigger.getTenantId()) + .tenantName(tenantName) + .api(trigger.getApi()) + .limitLevel(limitLevel) + .limitLevelEntityName(limitLevelEntityName) + .build(); + } + + @Override + public NotificationRuleTriggerType getTriggerType() { + return NotificationRuleTriggerType.RATE_LIMITS; + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/DefaultTwoFactorAuthService.java b/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/DefaultTwoFactorAuthService.java index a58c801583..08717986bf 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/DefaultTwoFactorAuthService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/mfa/DefaultTwoFactorAuthService.java @@ -31,7 +31,7 @@ import org.thingsboard.server.common.data.security.model.mfa.account.TwoFaAccoun import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderConfig; import org.thingsboard.server.common.data.security.model.mfa.provider.TwoFaProviderType; import org.thingsboard.server.dao.user.UserService; -import org.thingsboard.server.dao.util.limits.LimitedApi; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.auth.mfa.config.TwoFaConfigManager; diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java index c8f8f945f9..3b37b0fe26 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.util.ThrowingRunnable; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.dao.util.limits.LimitedApi; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import org.thingsboard.server.service.entitiy.TbNotificationEntityService; import org.thingsboard.server.service.sync.ie.exporting.EntityExportService; diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 392587c869..81589d2bce 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1266,6 +1266,9 @@ notification_system: NEW_PLATFORM_VERSION: # In milliseconds, infinitely by default deduplication_duration: "${NEW_PLATFORM_VERSION_NOTIFICATION_RULE_DEDUPLICATION_DURATION:0}" + RATE_LIMITS: + # In milliseconds, 4 hours by default + deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" management: endpoints: diff --git a/application/src/test/java/org/thingsboard/server/service/limits/RateLimitServiceTest.java b/application/src/test/java/org/thingsboard/server/service/limits/RateLimitServiceTest.java index 05ee66f327..c56adb5fd5 100644 --- a/application/src/test/java/org/thingsboard/server/service/limits/RateLimitServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/limits/RateLimitServiceTest.java @@ -24,11 +24,12 @@ import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; +import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.util.limits.DefaultRateLimitService; -import org.thingsboard.server.dao.util.limits.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import java.util.List; @@ -37,6 +38,7 @@ import java.util.UUID; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.when; @@ -50,7 +52,7 @@ public class RateLimitServiceTest { @Before public void beforeEach() { tenantProfileCache = Mockito.mock(TbTenantProfileCache.class); - rateLimitService = new DefaultRateLimitService(tenantProfileCache, 60, 100); + rateLimitService = new DefaultRateLimitService(tenantProfileCache, mock(NotificationRuleProcessor.class), 60, 100); tenantId = new TenantId(UUID.randomUUID()); } @@ -73,14 +75,14 @@ public class RateLimitServiceTest { LimitedApi.ENTITY_EXPORT, LimitedApi.ENTITY_IMPORT, LimitedApi.NOTIFICATION_REQUESTS, - LimitedApi.REST_REQUESTS, + LimitedApi.REST_REQUESTS_PER_CUSTOMER, LimitedApi.CASSANDRA_QUERIES )) { testRateLimits(limitedApi, max, tenantId); } CustomerId customerId = new CustomerId(UUID.randomUUID()); - testRateLimits(LimitedApi.REST_REQUESTS, max, customerId); + testRateLimits(LimitedApi.REST_REQUESTS_PER_CUSTOMER, max, customerId); NotificationRuleId notificationRuleId = new NotificationRuleId(UUID.randomUUID()); testRateLimits(LimitedApi.NOTIFICATION_REQUESTS_PER_RULE, max, notificationRuleId); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java b/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java index a1cc82fd5a..a49f8dc8cb 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java @@ -26,7 +26,7 @@ import org.thingsboard.server.dao.settings.AdminSettingsService; public class MockNotificationSettingsService extends DefaultNotificationSettingsService { public MockNotificationSettingsService(AdminSettingsService adminSettingsService) { - super(adminSettingsService, null, null); + super(adminSettingsService, null, null, null); } @Override diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index 6c4413d1e7..4155e2a4b3 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -51,12 +51,15 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; import org.thingsboard.server.common.data.notification.NotificationRequest; import org.thingsboard.server.common.data.notification.NotificationRequestInfo; import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.info.AlarmNotificationInfo; +import org.thingsboard.server.common.data.notification.info.RateLimitsNotificationInfo; import org.thingsboard.server.common.data.notification.rule.DefaultNotificationRuleRecipientsConfig; import org.thingsboard.server.common.data.notification.rule.EscalatedNotificationRuleRecipientsConfig; import org.thingsboard.server.common.data.notification.rule.NotificationRule; @@ -70,7 +73,10 @@ import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimi import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; +import org.thingsboard.server.common.data.notification.targets.platform.AffectedTenantAdministratorsFilter; +import org.thingsboard.server.common.data.notification.targets.platform.SystemAdministratorsFilter; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -82,12 +88,13 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.common.msg.notification.trigger.NewPlatformVersionTrigger; +import org.thingsboard.server.common.msg.notification.trigger.RateLimitsTrigger; import org.thingsboard.server.dao.notification.DefaultNotifications; import org.thingsboard.server.dao.notification.NotificationRequestService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.service.DaoSqlTest; -import org.thingsboard.server.dao.util.limits.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; +import org.thingsboard.server.service.notification.rule.DefaultNotificationRuleProcessor; import org.thingsboard.server.service.notification.rule.cache.DefaultNotificationRulesCache; import org.thingsboard.server.service.state.DeviceStateService; import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; @@ -103,6 +110,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.offset; @@ -116,7 +124,8 @@ import static org.thingsboard.server.common.data.notification.rule.trigger.Devic @DaoSqlTest @TestPropertySource(properties = { - "transport.http.enabled=true" + "transport.http.enabled=true", + "notification_system.rules.trigger_types_configs.RATE_LIMITS.deduplication_duration=10000" }) public class NotificationRuleApiTest extends AbstractNotificationApiTest { @@ -400,6 +409,60 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { }); } + @Test + public void testNotificationRuleProcessing_exceededRateLimits() throws Exception { + loginSysAdmin(); + NotificationTarget sysadmins = createNotificationTarget(new SystemAdministratorsFilter()); + NotificationTarget affectedTenantAdmins = createNotificationTarget(new AffectedTenantAdministratorsFilter()); + defaultNotifications.create(TenantId.SYS_TENANT_ID, DefaultNotifications.exceededRateLimitsForSysadmin, sysadmins.getId()); + defaultNotifications.create(TenantId.SYS_TENANT_ID, DefaultNotifications.exceededRateLimits, affectedTenantAdmins.getId()); + defaultNotifications.create(TenantId.SYS_TENANT_ID, DefaultNotifications.exceededPerEntityRateLimits, affectedTenantAdmins.getId()); + notificationRulesCache.evict(TenantId.SYS_TENANT_ID); + + int n = 10; + updateDefaultTenantProfile(profileConfiguration -> { + profileConfiguration.setTenantEntityExportRateLimit(n + ":600"); + profileConfiguration.setCustomerServerRestLimitsConfiguration(n + ":600"); + profileConfiguration.setTenantNotificationRequestsPerRuleRateLimit(n + ":600"); + profileConfiguration.setTransportDeviceTelemetryMsgRateLimit(n + ":600"); + }); + loginTenantAdmin(); + NotificationRule rule = createNotificationRule(AlarmCommentNotificationRuleTriggerConfig.builder() + .alarmTypes(Set.of("weklfjkwefa")) + .build(), "Test", "Test", createNotificationTarget(tenantAdminUserId).getId()); + for (int i = 1; i <= n * 2; i++) { + rateLimitService.checkRateLimit(LimitedApi.ENTITY_EXPORT, tenantId); + rateLimitService.checkRateLimit(LimitedApi.REST_REQUESTS_PER_CUSTOMER, tenantId, customerId); + rateLimitService.checkRateLimit(LimitedApi.NOTIFICATION_REQUESTS_PER_RULE, tenantId, rule.getId()); + } + + loginTenantAdmin(); + List notifications = await().atMost(30, TimeUnit.SECONDS) + .until(() -> getMyNotifications(true, 10), list -> list.size() == 3); + assertThat(notifications).allSatisfy(notification -> { + assertThat(notification.getSubject()).isEqualTo("Rate limits exceeded"); + }); + assertThat(notifications).anySatisfy(notification -> { + assertThat(notification.getText()).isEqualTo("Rate limits for entity version creation exceeded"); + }); + assertThat(notifications).anySatisfy(notification -> { + assertThat(notification.getText()).isEqualTo("Rate limits for REST API requests per customer " + + "exceeded for 'Customer'"); + }); + assertThat(notifications).anySatisfy(notification -> { + assertThat(notification.getText()).isEqualTo("Rate limits for notification requests " + + "per rule exceeded for '" + rule.getName() + "'"); + }); + + loginSysAdmin(); + notifications = await().atMost(30, TimeUnit.SECONDS) + .until(() -> getMyNotifications(true, 10), list -> list.size() == 1); + assertThat(notifications).allSatisfy(notification -> { + assertThat(notification.getSubject()).isEqualTo("Rate limits exceeded for tenant " + TEST_TENANT_NAME); + }); + assertThat(notifications.get(0).getText()).isEqualTo("Rate limits for entity version creation exceeded"); + } + @Test public void testNotificationRuleProcessing_alarmAssignment() throws Exception { AlarmAssignmentNotificationRuleTriggerConfig triggerConfig = AlarmAssignmentNotificationRuleTriggerConfig.builder() @@ -617,6 +680,68 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { }); } + @Test + public void testNotificationsDeduplication_exceededRateLimits() throws Exception { + RateLimitsNotificationRuleTriggerConfig triggerConfig = new RateLimitsNotificationRuleTriggerConfig(); + triggerConfig.setApis(Set.of(LimitedApi.ENTITY_EXPORT, LimitedApi.TRANSPORT_MESSAGES_PER_DEVICE)); + + loginSysAdmin(); + NotificationTarget target = createNotificationTarget(tenantAdminUserId); + NotificationRule rule = createNotificationRule(triggerConfig, "Test 1", "Test", target.getId()); + + int n = 5; + updateDefaultTenantProfile(profileConfiguration -> { + profileConfiguration.setTenantEntityExportRateLimit(n + ":600"); + profileConfiguration.setTransportDeviceTelemetryMsgRateLimit(n + ":800"); + }); + + RateLimitsTrigger expectedTrigger = RateLimitsTrigger.builder() + .tenantId(tenantId) + .api(LimitedApi.ENTITY_EXPORT) + .limitLevel(tenantId) + .build(); + assertThat(DefaultNotificationRuleProcessor.getDeduplicationKey(expectedTrigger, rule)) + .isEqualTo("RATE_LIMITS:TENANT:" + tenantId + ":ENTITY_EXPORT_" + + target.getId() + ":ENTITY_EXPORT,TRANSPORT_MESSAGES_PER_DEVICE"); + + loginTenantAdmin(); + getWsClient().subscribeForUnreadNotifications(10).waitForReply(); + getWsClient().registerWaitForUpdate(2); + Device device = createDevice("Test", "Test"); + for (int i = 1; i <= n + 1; i++) { + rateLimitService.checkRateLimit(LimitedApi.ENTITY_EXPORT, tenantId); + doPost("/api/v1/" + device.getName() + "/telemetry", "{\"dp1\":123}", String.class); + } + int expectedNotificationsCount1 = 2; + getWsClient().waitForUpdate(true); + List notifications1 = getMyNotifications(true, 10); + assertThat(notifications1).size().isEqualTo(expectedNotificationsCount1); + assertThat(notifications1) + .anyMatch(notification -> ((RateLimitsNotificationInfo) notification.getInfo()).getApi() == LimitedApi.ENTITY_EXPORT) + .anyMatch(notification -> ((RateLimitsNotificationInfo) notification.getInfo()).getApi() == LimitedApi.TRANSPORT_MESSAGES_PER_DEVICE); + + getWsClient().registerWaitForUpdate(2); + for (int i = 0; i < 10; i++) { + rateLimitService.checkRateLimit(LimitedApi.ENTITY_EXPORT, tenantId); + doPost("/api/v1/" + device.getName() + "/telemetry", "{\"dp1\":123}", String.class); + } + assertThat(getWsClient().waitForUpdate(5000)).isNull(); + + int deduplicationDuration = 10000; // configured in TestPropertySource above + await().atLeast(2, TimeUnit.SECONDS) + .atMost(deduplicationDuration, TimeUnit.MILLISECONDS) + .untilAsserted(() -> { + rateLimitService.checkRateLimit(LimitedApi.ENTITY_EXPORT, tenantId); + doPost("/api/v1/" + device.getName() + "/telemetry", "{\"dp1\":123}", String.class); + + Map notifications2 = getMyNotifications(true, 10).stream() + .map(notification -> (RateLimitsNotificationInfo) notification.getInfo()) + .collect(Collectors.groupingBy(RateLimitsNotificationInfo::getApi, Collectors.counting())); + assertThat(notifications2.get(LimitedApi.ENTITY_EXPORT)).isEqualTo(2); + assertThat(notifications2.get(LimitedApi.TRANSPORT_MESSAGES_PER_DEVICE)).isEqualTo(2); + }); + } + @Test public void testNotificationRuleDisabling() throws Exception { EntityActionNotificationRuleTriggerConfig triggerConfig = new EntityActionNotificationRuleTriggerConfig(); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java index 46eb5ca54e..a5433915b3 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java @@ -26,4 +26,6 @@ public interface NotificationSettingsService { void createDefaultNotificationConfigs(TenantId tenantId); + void updateDefaultNotificationConfigs(TenantId tenantId); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java index 05299c1675..bd442f6bb6 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetService.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; +import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -40,6 +41,8 @@ public interface NotificationTargetService { List findNotificationTargetsByTenantIdAndIds(TenantId tenantId, List ids); + List findNotificationTargetsByTenantIdAndUsersFilterType(TenantId tenantId, UsersFilterType filterType); + PageData findRecipientsForNotificationTarget(TenantId tenantId, CustomerId customerId, NotificationTargetId targetId, PageLink pageLink); PageData findRecipientsForNotificationTargetConfig(TenantId tenantId, PlatformUsersNotificationTargetConfig targetConfig, PageLink pageLink); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/limit/LimitedApi.java b/common/data/src/main/java/org/thingsboard/server/common/data/limit/LimitedApi.java new file mode 100644 index 0000000000..e709ac596e --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/limit/LimitedApi.java @@ -0,0 +1,70 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.limit; + +import lombok.Getter; +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; + +import java.util.Optional; +import java.util.function.Function; + +public enum LimitedApi { + + ENTITY_EXPORT(DefaultTenantProfileConfiguration::getTenantEntityExportRateLimit, "entity version creation", true), + ENTITY_IMPORT(DefaultTenantProfileConfiguration::getTenantEntityImportRateLimit, "entity version load", true), + NOTIFICATION_REQUESTS(DefaultTenantProfileConfiguration::getTenantNotificationRequestsRateLimit, "notification requests", true), + NOTIFICATION_REQUESTS_PER_RULE(DefaultTenantProfileConfiguration::getTenantNotificationRequestsPerRuleRateLimit, "notification requests per rule", false), + REST_REQUESTS_PER_TENANT(DefaultTenantProfileConfiguration::getTenantServerRestLimitsConfiguration, "REST API requests", true), + REST_REQUESTS_PER_CUSTOMER(DefaultTenantProfileConfiguration::getCustomerServerRestLimitsConfiguration, "REST API requests per customer", false), + WS_UPDATES_PER_SESSION(DefaultTenantProfileConfiguration::getWsUpdatesPerSessionRateLimit, "WS updates per session", true), + CASSANDRA_QUERIES(DefaultTenantProfileConfiguration::getCassandraQueryTenantRateLimitsConfiguration, "Cassandra queries", true), + PASSWORD_RESET(false, true), + TWO_FA_VERIFICATION_CODE_SEND(false, true), + TWO_FA_VERIFICATION_CODE_CHECK(false, true), + TRANSPORT_MESSAGES_PER_TENANT("transport messages", true), + TRANSPORT_MESSAGES_PER_DEVICE("transport messages per device", false); + + private Function configExtractor; + @Getter + private final boolean perTenant; + @Getter + private boolean refillRateLimitIntervally; + @Getter + private String label; + + LimitedApi(Function configExtractor, String label, boolean perTenant) { + this.configExtractor = configExtractor; + this.label = label; + this.perTenant = perTenant; + } + + LimitedApi(boolean perTenant, boolean refillRateLimitIntervally) { + this.perTenant = perTenant; + this.refillRateLimitIntervally = refillRateLimitIntervally; + } + + LimitedApi(String label, boolean perTenant) { + this.label = label; + this.perTenant = perTenant; + } + + public String getLimitConfig(DefaultTenantProfileConfiguration profileConfiguration) { + return Optional.ofNullable(configExtractor) + .map(extractor -> extractor.apply(profileConfiguration)) + .orElse(null); + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java index de07d03c67..251fae2ac0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationType.java @@ -27,6 +27,7 @@ public enum NotificationType { NEW_PLATFORM_VERSION, ENTITIES_LIMIT, API_USAGE_LIMIT, - RULE_NODE + RULE_NODE, + RATE_LIMITS } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RateLimitsNotificationInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RateLimitsNotificationInfo.java new file mode 100644 index 0000000000..57fc278cff --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/info/RateLimitsNotificationInfo.java @@ -0,0 +1,59 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.notification.info; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.limit.LimitedApi; + +import java.util.Map; + +import static org.thingsboard.server.common.data.util.CollectionsUtil.mapOf; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class RateLimitsNotificationInfo implements RuleOriginatedNotificationInfo { + + private TenantId tenantId; + private String tenantName; + private LimitedApi api; + private EntityId limitLevel; + private String limitLevelEntityName; + + @Override + public Map getTemplateData() { + return mapOf( + "api", api.getLabel(), + "limitLevelEntityType", limitLevel != null ? limitLevel.getEntityType().getNormalName() : null, + "limitLevelEntityId", limitLevel != null ? limitLevel.getId().toString() : null, + "limitLevelEntityName", limitLevelEntityName, + "tenantName", tenantName, + "tenantId", tenantId.toString() + ); + } + + @Override + public TenantId getAffectedTenantId() { + return tenantId; + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java index b0eec28858..72028a616a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java @@ -35,6 +35,7 @@ import java.io.Serializable; @Type(value = NewPlatformVersionNotificationRuleTriggerConfig.class, name = "NEW_PLATFORM_VERSION"), @Type(value = EntitiesLimitNotificationRuleTriggerConfig.class, name = "ENTITIES_LIMIT"), @Type(value = ApiUsageLimitNotificationRuleTriggerConfig.class, name = "API_USAGE_LIMIT"), + @Type(value = RateLimitsNotificationRuleTriggerConfig.class, name = "RATE_LIMITS"), }) public interface NotificationRuleTriggerConfig extends Serializable { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java index dff86f4ba1..b591fe0245 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java @@ -28,7 +28,8 @@ public enum NotificationRuleTriggerType { RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, NEW_PLATFORM_VERSION(false), ENTITIES_LIMIT(false), - API_USAGE_LIMIT(false); + API_USAGE_LIMIT(false), + RATE_LIMITS(false); private final boolean tenantLevel; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsNotificationRuleTriggerConfig.java new file mode 100644 index 0000000000..f5ea83c47d --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsNotificationRuleTriggerConfig.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.notification.rule.trigger; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.thingsboard.server.common.data.limit.LimitedApi; + +import java.util.Set; +import java.util.stream.Collectors; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RateLimitsNotificationRuleTriggerConfig implements NotificationRuleTriggerConfig { + + private Set apis; + + @Override + public NotificationRuleTriggerType getTriggerType() { + return NotificationRuleTriggerType.RATE_LIMITS; + } + + @Override + public String getDeduplicationKey() { + return apis == null ? "#" : apis.stream().sorted().map(Enum::name).collect(Collectors.joining(",")); + } + +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RateLimitsTrigger.java b/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RateLimitsTrigger.java new file mode 100644 index 0000000000..afb06bb8d1 --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RateLimitsTrigger.java @@ -0,0 +1,62 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.msg.notification.trigger; + +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.limit.LimitedApi; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; + +import java.util.concurrent.TimeUnit; + +@Data +@Builder +public class RateLimitsTrigger implements NotificationRuleTrigger { + + private final TenantId tenantId; + private final LimitedApi api; + private final EntityId limitLevel; + private final String limitLevelEntityName; + + @Override + public NotificationRuleTriggerType getType() { + return NotificationRuleTriggerType.RATE_LIMITS; + } + + @Override + public EntityId getOriginatorEntityId() { + return limitLevel != null ? limitLevel : tenantId; + } + + + @Override + public boolean deduplicate() { + return true; + } + + @Override + public String getDeduplicationKey() { + return String.join(":", NotificationRuleTrigger.super.getDeduplicationKey(), api.toString()); + } + + @Override + public long getDefaultDeduplicationDuration() { + return TimeUnit.HOURS.toMillis(4); + } + +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java index c1ae9fe855..fa16ee9093 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java @@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; @@ -110,6 +111,11 @@ public class AwsSqsTransportQueueFactory implements TbTransportQueueFactory { return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getTopic()); } + @Override + public TbQueueProducer> createTbCoreNotificationsMsgProducer() { + return new TbAwsSqsProducerTemplate<>(notificationAdmin, sqsSettings, coreSettings.getTopic()); + } + @Override public TbQueueConsumer> createTransportNotificationsConsumer() { return new TbAwsSqsConsumerTemplate<>(notificationAdmin, sqsSettings, transportNotificationSettings.getNotificationsTopic() + "_" + serviceInfoProvider.getServiceId(), diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java index 60c464ecab..6b6253acc4 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java @@ -20,6 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; @@ -100,6 +101,11 @@ public class InMemoryTbTransportQueueFactory implements TbTransportQueueFactory return new InMemoryTbQueueProducer<>(storage, coreSettings.getTopic()); } + @Override + public TbQueueProducer> createTbCoreNotificationsMsgProducer() { + return new InMemoryTbQueueProducer<>(storage, coreSettings.getTopic()); + } + @Override public TbQueueConsumer> createTransportNotificationsConsumer() { return new InMemoryTbQueueConsumer<>(storage, transportNotificationSettings.getNotificationsTopic() + "." + serviceInfoProvider.getServiceId()); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java index 51e3dc99c7..300e0a44b6 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java @@ -18,7 +18,9 @@ package org.thingsboard.server.queue.provider; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; @@ -134,6 +136,16 @@ public class KafkaTbTransportQueueFactory implements TbTransportQueueFactory { return requestBuilder.build(); } + @Override + public TbQueueProducer> createTbCoreNotificationsMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + requestBuilder.settings(kafkaSettings); + requestBuilder.clientId("transport-node-to-core-notifications-" + serviceInfoProvider.getServiceId()); + requestBuilder.defaultTopic(coreSettings.getTopic()); + requestBuilder.admin(notificationAdmin); + return requestBuilder.build(); + } + @Override public TbQueueConsumer> createTransportNotificationsConsumer() { TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> responseBuilder = TbKafkaConsumerTemplate.builder(); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTransportQueueFactory.java index d5665e2fbe..5cafaa4c48 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTransportQueueFactory.java @@ -18,7 +18,9 @@ package org.thingsboard.server.queue.provider; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; @@ -108,6 +110,11 @@ public class PubSubTransportQueueFactory implements TbTransportQueueFactory { return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getTopic()); } + @Override + public TbQueueProducer> createTbCoreNotificationsMsgProducer() { + return new TbPubSubProducerTemplate<>(notificationAdmin, pubSubSettings, coreSettings.getTopic()); + } + @Override public TbQueueConsumer> createTransportNotificationsConsumer() { return new TbPubSubConsumerTemplate<>(notificationAdmin, pubSubSettings, diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java index f11a877fc5..bcbd60a14e 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java @@ -18,7 +18,9 @@ package org.thingsboard.server.queue.provider; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; @@ -110,6 +112,11 @@ public class RabbitMqTransportQueueFactory implements TbTransportQueueFactory { return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getTopic()); } + @Override + public TbQueueProducer> createTbCoreNotificationsMsgProducer() { + return new TbRabbitMqProducerTemplate<>(notificationAdmin, rabbitMqSettings, coreSettings.getTopic()); + } + @Override public TbQueueConsumer> createTransportNotificationsConsumer() { return new TbRabbitMqConsumerTemplate<>(notificationAdmin, rabbitMqSettings, transportNotificationSettings.getNotificationsTopic() + "." + serviceInfoProvider.getServiceId(), diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java index 15e661f5b0..0a4bb59663 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java @@ -18,7 +18,9 @@ package org.thingsboard.server.queue.provider; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; @@ -110,6 +112,11 @@ public class ServiceBusTransportQueueFactory implements TbTransportQueueFactory return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getTopic()); } + @Override + public TbQueueProducer> createTbCoreNotificationsMsgProducer() { + return new TbServiceBusProducerTemplate<>(notificationAdmin, serviceBusSettings, coreSettings.getTopic()); + } + @Override public TbQueueConsumer> createTransportNotificationsConsumer() { return new TbServiceBusConsumerTemplate<>(notificationAdmin, serviceBusSettings, diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueFactory.java index feff3830fc..c7d2f78838 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueFactory.java @@ -16,6 +16,7 @@ package org.thingsboard.server.queue.provider; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; @@ -33,6 +34,8 @@ public interface TbTransportQueueFactory extends TbUsageStatsClientQueueFactory TbQueueProducer> createTbCoreMsgProducer(); + TbQueueProducer> createTbCoreNotificationsMsgProducer(); + TbQueueConsumer> createTransportNotificationsConsumer(); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java index e9177d8b1c..afbcd718a5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java @@ -36,6 +36,7 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider private final TbTransportQueueFactory tbQueueProvider; private TbQueueProducer> toRuleEngine; private TbQueueProducer> toTbCore; + private TbQueueProducer> toTbCoreNotifications; private TbQueueProducer> toUsageStats; public TbTransportQueueProducerProvider(TbTransportQueueFactory tbQueueProvider) { @@ -47,6 +48,7 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider this.toTbCore = tbQueueProvider.createTbCoreMsgProducer(); this.toRuleEngine = tbQueueProvider.createRuleEngineMsgProducer(); this.toUsageStats = tbQueueProvider.createToUsageStatsServiceMsgProducer(); + this.toTbCoreNotifications = tbQueueProvider.createTbCoreNotificationsMsgProducer(); } @Override @@ -71,7 +73,7 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider @Override public TbQueueProducer> getTbCoreNotificationsMsgProducer() { - throw new RuntimeException("Not Implemented! Should not be used by Transport!"); + return toTbCoreNotifications; } @Override diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java index 6539f2d22c..47f7717212 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java @@ -78,11 +78,11 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi return null; } - private boolean checkEntityRateLimit(int dataPoints, EntityTransportRateLimits tenantLimits) { + private boolean checkEntityRateLimit(int dataPoints, EntityTransportRateLimits limits) { if (dataPoints > 0) { - return tenantLimits.getTelemetryMsgRateLimit().tryConsume() && tenantLimits.getTelemetryDataPointsRateLimit().tryConsume(dataPoints); + return limits.getTelemetryMsgRateLimit().tryConsume() && limits.getTelemetryDataPointsRateLimit().tryConsume(dataPoints); } else { - return tenantLimits.getRegularMsgRateLimit().tryConsume(); + return limits.getRegularMsgRateLimit().tryConsume(); } } @@ -241,7 +241,7 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi } else { TransportRateLimit regularMsgRateLimit = newLimit(tenant ? profile.getTransportTenantMsgRateLimit() : profile.getTransportDeviceMsgRateLimit()); TransportRateLimit telemetryMsgRateLimit = newLimit(tenant ? profile.getTransportTenantTelemetryMsgRateLimit() : profile.getTransportDeviceTelemetryMsgRateLimit()); - TransportRateLimit telemetryDpRateLimit = newLimit(tenant ? profile.getTransportTenantTelemetryDataPointsRateLimit() : profile.getTransportTenantTelemetryDataPointsRateLimit()); + TransportRateLimit telemetryDpRateLimit = newLimit(tenant ? profile.getTransportTenantTelemetryDataPointsRateLimit() : profile.getTransportDeviceTelemetryDataPointsRateLimit()); return new EntityTransportRateLimits(regularMsgRateLimit, telemetryMsgRateLimit, telemetryDpRateLimit); } } @@ -251,21 +251,16 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi } private EntityTransportRateLimits getTenantRateLimits(TenantId tenantId) { - EntityTransportRateLimits limits = perTenantLimits.get(tenantId); - if (limits == null) { - limits = createRateLimits(tenantProfileCache.get(tenantId), true); - perTenantLimits.put(tenantId, limits); - } - return limits; + return perTenantLimits.computeIfAbsent(tenantId, k -> { + return createRateLimits(tenantProfileCache.get(tenantId), true); + }); } private EntityTransportRateLimits getDeviceRateLimits(TenantId tenantId, DeviceId deviceId) { - EntityTransportRateLimits limits = perDeviceLimits.get(deviceId); - if (limits == null) { - limits = createRateLimits(tenantProfileCache.get(tenantId), false); - perDeviceLimits.put(deviceId, limits); + return perDeviceLimits.computeIfAbsent(deviceId, k -> { + EntityTransportRateLimits limits = createRateLimits(tenantProfileCache.get(tenantId), false); tenantDevices.computeIfAbsent(tenantId, id -> ConcurrentHashMap.newKeySet()).add(deviceId); - } - return limits; + return limits; + }); } } diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index b495448d90..69e4de7b74 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -48,9 +48,12 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; +import org.thingsboard.server.common.msg.notification.trigger.RateLimitsTrigger; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.session.SessionMsgType; @@ -177,6 +180,7 @@ public class DefaultTransportService implements TransportService { private final SchedulerComponent scheduler; private final ApplicationEventPublisher eventPublisher; private final TransportResourceCache transportResourceCache; + private final NotificationRuleProcessor notificationRuleProcessor; protected TbQueueRequestTemplate, TbProtoQueueMsg> transportApiRequestTemplate; protected TbQueueProducer> ruleEngineMsgProducer; @@ -206,7 +210,7 @@ public class DefaultTransportService implements TransportService { TransportTenantProfileCache tenantProfileCache, TransportRateLimitService rateLimitService, DataDecodingEncodingService dataDecodingEncodingService, SchedulerComponent scheduler, TransportResourceCache transportResourceCache, - ApplicationEventPublisher eventPublisher) { + ApplicationEventPublisher eventPublisher, NotificationRuleProcessor notificationRuleProcessor) { this.partitionService = partitionService; this.serviceInfoProvider = serviceInfoProvider; this.queueProvider = queueProvider; @@ -220,6 +224,7 @@ public class DefaultTransportService implements TransportService { this.scheduler = scheduler; this.transportResourceCache = transportResourceCache; this.eventPublisher = eventPublisher; + this.notificationRuleProcessor = notificationRuleProcessor; } @PostConstruct @@ -877,6 +882,14 @@ public class DefaultTransportService implements TransportService { if (callback != null) { callback.onError(new TbRateLimitsException(rateLimitedEntityType)); } + if (rateLimitedEntityType == EntityType.DEVICE || rateLimitedEntityType == EntityType.TENANT) { + notificationRuleProcessor.process(RateLimitsTrigger.builder() + .tenantId(tenantId) + .api(rateLimitedEntityType == EntityType.DEVICE ? LimitedApi.TRANSPORT_MESSAGES_PER_DEVICE : LimitedApi.TRANSPORT_MESSAGES_PER_TENANT) + .limitLevel(rateLimitedEntityType == EntityType.DEVICE ? deviceId : tenantId) + .limitLevelEntityName(rateLimitedEntityType == EntityType.DEVICE ? sessionInfo.getDeviceName() : null) + .build()); + } return false; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java index 0e25a0cab3..4262decfed 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java @@ -25,6 +25,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.platform.AffectedTenantAdministratorsFilter; @@ -35,9 +36,12 @@ import org.thingsboard.server.common.data.notification.targets.platform.Platform import org.thingsboard.server.common.data.notification.targets.platform.SystemAdministratorsFilter; import org.thingsboard.server.common.data.notification.targets.platform.TenantAdministratorsFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; +import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.settings.AdminSettingsService; import java.util.Collections; +import java.util.List; import java.util.Optional; @Service @@ -46,6 +50,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS private final AdminSettingsService adminSettingsService; private final NotificationTargetService notificationTargetService; + private final NotificationTemplateService notificationTemplateService; private final DefaultNotifications defaultNotifications; private static final String SETTINGS_KEY = "notifications"; @@ -98,6 +103,10 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS defaultNotifications.create(tenantId, DefaultNotifications.apiFeatureDisabledForSysadmin, sysAdmins.getId()); defaultNotifications.create(tenantId, DefaultNotifications.apiFeatureDisabledForTenant, affectedTenantAdmins.getId()); + defaultNotifications.create(tenantId, DefaultNotifications.exceededRateLimits, affectedTenantAdmins.getId()); + defaultNotifications.create(tenantId, DefaultNotifications.exceededPerEntityRateLimits, affectedTenantAdmins.getId()); + defaultNotifications.create(tenantId, DefaultNotifications.exceededRateLimitsForSysadmin, sysAdmins.getId()); + defaultNotifications.create(tenantId, DefaultNotifications.newPlatformVersion, sysAdmins.getId()); return; } @@ -116,6 +125,29 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS defaultNotifications.create(tenantId, DefaultNotifications.ruleEngineComponentLifecycleFailure, tenantAdmins.getId()); } + @Override + public void updateDefaultNotificationConfigs(TenantId tenantId) { + if (tenantId.isSysTenantId()) { + if (notificationTemplateService.findNotificationTemplatesByTenantIdAndNotificationTypes(tenantId, + List.of(NotificationType.RATE_LIMITS), new PageLink(1)).getTotalElements() > 0) { + return; + } + + NotificationTarget sysAdmins = notificationTargetService.findNotificationTargetsByTenantIdAndUsersFilterType(tenantId, UsersFilterType.SYSTEM_ADMINISTRATORS).stream() + .findFirst().orElseGet(() -> { + return createTarget(tenantId, "System administrators", new SystemAdministratorsFilter(), "All system administrators"); + }); + NotificationTarget affectedTenantAdmins = notificationTargetService.findNotificationTargetsByTenantIdAndUsersFilterType(tenantId, UsersFilterType.AFFECTED_TENANT_ADMINISTRATORS).stream() + .findFirst().orElseGet(() -> { + return createTarget(tenantId, "Affected tenant's administrators", new AffectedTenantAdministratorsFilter(), ""); + }); + + defaultNotifications.create(tenantId, DefaultNotifications.exceededRateLimits, affectedTenantAdmins.getId()); + defaultNotifications.create(tenantId, DefaultNotifications.exceededPerEntityRateLimits, affectedTenantAdmins.getId()); + defaultNotifications.create(tenantId, DefaultNotifications.exceededRateLimitsForSysadmin, sysAdmins.getId()); + } + } + private NotificationTarget createTarget(TenantId tenantId, String name, UsersFilter filter, String description) { NotificationTarget target = new NotificationTarget(); target.setTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java index 78d5a4b454..97a7ee0e27 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationTargetService.java @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.notification.targets.platform.Platform import org.thingsboard.server.common.data.notification.targets.platform.TenantAdministratorsFilter; import org.thingsboard.server.common.data.notification.targets.platform.UserListFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; +import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.entity.AbstractEntityService; @@ -93,6 +94,11 @@ public class DefaultNotificationTargetService extends AbstractEntityService impl return notificationTargetDao.findByTenantIdAndIds(tenantId, ids); } + @Override + public List findNotificationTargetsByTenantIdAndUsersFilterType(TenantId tenantId, UsersFilterType filterType) { + return notificationTargetDao.findByTenantIdAndUsersFilterType(tenantId, filterType); + } + @Override public PageData findRecipientsForNotificationTarget(TenantId tenantId, CustomerId customerId, NotificationTargetId targetId, PageLink pageLink) { NotificationTarget notificationTarget = findNotificationTargetById(tenantId, targetId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java index 01f9f68ae4..c8f458b40d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.id.NotificationTargetId; import org.thingsboard.server.common.data.id.NotificationTemplateId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.rule.DefaultNotificationRuleRecipientsConfig; @@ -44,16 +45,20 @@ import org.thingsboard.server.common.data.notification.rule.trigger.EntityAction import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig; import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import static java.util.function.Predicate.not; import static org.thingsboard.common.util.JacksonUtil.newObjectNode; import static org.thingsboard.server.dao.DaoUtil.toUUIDs; @@ -66,6 +71,7 @@ public class DefaultNotifications { .subject("Infrastructure maintenance") .text("Maintenance work is scheduled for tomorrow (7:00 a.m. - 9:00 a.m. UTC)") .build(); + public static final DefaultNotification entitiesLimitForSysadmin = DefaultNotification.builder() .name("Entities count limit notification for sysadmin") .type(NotificationType.ENTITIES_LIMIT) @@ -88,6 +94,7 @@ public class DefaultNotifications { .description("Send notification to tenant admins when count of entities of some type reached 80% threshold of the limit") .build()) .build(); + public static final DefaultNotification apiFeatureWarningForSysadmin = DefaultNotification.builder() .name("API feature warning notification for sysadmin") .type(NotificationType.API_USAGE_LIMIT) @@ -134,6 +141,51 @@ public class DefaultNotifications { .description("Send notification to tenant admins when API feature is disabled") .build()) .build(); + + public static final DefaultNotification exceededRateLimits = DefaultNotification.builder() + .name("Exceeded per-tenant rate limits notification for tenant") + .type(NotificationType.RATE_LIMITS) + .subject("Rate limits exceeded") + .text("Rate limits for ${api} exceeded") + .icon("block").color("#e91a1a") + .rule(DefaultRule.builder() + .name("Per-tenant rate limits exceeded") + .triggerConfig(RateLimitsNotificationRuleTriggerConfig.builder() + .apis(Arrays.stream(LimitedApi.values()) + .filter(LimitedApi::isPerTenant) + .filter(api -> api.getLabel() != null) + .collect(Collectors.toSet())) + .build()) + .description("Send notification to tenant admins when some per-tenant rate limit is exceeded") + .build()) + .build(); + public static final DefaultNotification exceededPerEntityRateLimits = DefaultNotification.builder() + .name("Exceeded per-entity rate limits notification for tenant") + .type(NotificationType.RATE_LIMITS) + .subject("Rate limits exceeded") + .text("Rate limits for ${api} exceeded for '${limitLevelEntityName}'") + .icon("block").color("#e91a1a") + .rule(DefaultRule.builder() + .name("Per-entity rate limits exceeded") + .triggerConfig(RateLimitsNotificationRuleTriggerConfig.builder() + .apis(Arrays.stream(LimitedApi.values()) + .filter(not(LimitedApi::isPerTenant)) + .filter(api -> api.getLabel() != null) + .collect(Collectors.toSet())) + .build()) + .description("Send notification to tenant admins when some per-entity rate limit is exceeded for an entity") + .build()) + .build(); + public static final DefaultNotification exceededRateLimitsForSysadmin = exceededRateLimits.toBuilder() + .name("Exceeded per-tenant rate limits notification for sysadmin") + .subject("Rate limits exceeded for tenant ${tenantName}") + .button("Go to tenant").link("/tenants/${tenantId}") + .rule(exceededRateLimits.getRule().toBuilder() + .name("Per-tenant rate limits exceeded (sysadmin)") + .description("Send notification to system admins when a tenant exceeds some per-tenant rate limit") + .build()) + .build(); + public static final DefaultNotification newPlatformVersion = DefaultNotification.builder() .name("New platform version notification") .type(NotificationType.NEW_PLATFORM_VERSION) diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetDao.java b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetDao.java index 912e873bcc..3e542cc50f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationTargetDao.java @@ -19,6 +19,7 @@ import org.thingsboard.server.common.data.id.NotificationTargetId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; +import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.Dao; @@ -35,6 +36,8 @@ public interface NotificationTargetDao extends Dao, TenantEn List findByTenantIdAndIds(TenantId tenantId, List ids); + List findByTenantIdAndUsersFilterType(TenantId tenantId, UsersFilterType filterType); + void removeByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTargetDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTargetDao.java index d976802fd2..64c679c845 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTargetDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationTargetDao.java @@ -66,6 +66,12 @@ public class JpaNotificationTargetDao extends JpaAbstractDao findByTenantIdAndUsersFilterType(TenantId tenantId, UsersFilterType filterType) { + return DaoUtil.convertDataList(notificationTargetRepository.findByTenantIdAndSearchTextAndUsersFilterTypeIfPresent(tenantId.getId(), "", + List.of(filterType.name()), DaoUtil.toPageable(new PageLink(Integer.MAX_VALUE))).getContent()); + } + @Override public void removeByTenantId(TenantId tenantId) { notificationTargetRepository.deleteByTenantId(tenantId.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java b/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java index 64b4eb3666..4c8d0c5afe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java @@ -37,7 +37,7 @@ import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.common.stats.StatsType; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.nosql.CassandraStatementTask; -import org.thingsboard.server.dao.util.limits.LimitedApi; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import javax.annotation.Nullable; diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java b/dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java index 918f16ef19..ede6855d5e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java @@ -20,11 +20,16 @@ import com.github.benmanes.caffeine.cache.Caffeine; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.exception.TenantProfileNotFoundException; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.limit.LimitedApi; +import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; +import org.thingsboard.server.common.msg.notification.trigger.RateLimitsTrigger; import org.thingsboard.server.common.msg.tools.TbRateLimits; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; @@ -35,11 +40,14 @@ import java.util.concurrent.TimeUnit; public class DefaultRateLimitService implements RateLimitService { private final TbTenantProfileCache tenantProfileCache; + private final NotificationRuleProcessor notificationRuleProcessor; public DefaultRateLimitService(TbTenantProfileCache tenantProfileCache, + @Lazy NotificationRuleProcessor notificationRuleProcessor, @Value("${cache.rateLimits.timeToLiveInMinutes:120}") int rateLimitsTtl, @Value("${cache.rateLimits.maxSize:200000}") int rateLimitsCacheMaxSize) { this.tenantProfileCache = tenantProfileCache; + this.notificationRuleProcessor = notificationRuleProcessor; this.rateLimits = Caffeine.newBuilder() .expireAfterAccess(rateLimitsTtl, TimeUnit.MINUTES) .maximumSize(rateLimitsCacheMaxSize) @@ -64,9 +72,17 @@ public class DefaultRateLimitService implements RateLimitService { } String rateLimitConfig = tenantProfile.getProfileConfiguration() - .map(profileConfiguration -> api.getLimitConfig(profileConfiguration, level)) - .orElse(null); - return checkRateLimit(api, level, rateLimitConfig); + .map(api::getLimitConfig).orElse(null); + boolean success = checkRateLimit(api, level, rateLimitConfig); + if (!success) { + notificationRuleProcessor.process(RateLimitsTrigger.builder() + .tenantId(tenantId) + .api(api) + .limitLevel(level instanceof EntityId ? (EntityId) level : tenantId) + .limitLevelEntityName(null) + .build()); + } + return success; } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/limits/LimitedApi.java b/dao/src/main/java/org/thingsboard/server/dao/util/limits/LimitedApi.java deleted file mode 100644 index ee79230d8a..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/util/limits/LimitedApi.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright © 2016-2023 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.dao.util.limits; - -import lombok.Getter; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; - -import java.util.function.BiFunction; -import java.util.function.Function; - -public enum LimitedApi { - - ENTITY_EXPORT(DefaultTenantProfileConfiguration::getTenantEntityExportRateLimit), - ENTITY_IMPORT(DefaultTenantProfileConfiguration::getTenantEntityImportRateLimit), - NOTIFICATION_REQUESTS(DefaultTenantProfileConfiguration::getTenantNotificationRequestsRateLimit), - NOTIFICATION_REQUESTS_PER_RULE(DefaultTenantProfileConfiguration::getTenantNotificationRequestsPerRuleRateLimit), - REST_REQUESTS((profileConfiguration, level) -> ((EntityId) level).getEntityType() == EntityType.TENANT ? - profileConfiguration.getTenantServerRestLimitsConfiguration() : - profileConfiguration.getCustomerServerRestLimitsConfiguration()), - WS_UPDATES_PER_SESSION(DefaultTenantProfileConfiguration::getWsUpdatesPerSessionRateLimit), - CASSANDRA_QUERIES(DefaultTenantProfileConfiguration::getCassandraQueryTenantRateLimitsConfiguration), - PASSWORD_RESET(true), - TWO_FA_VERIFICATION_CODE_SEND(true), - TWO_FA_VERIFICATION_CODE_CHECK(true); - - private final BiFunction configExtractor; - @Getter - private final boolean refillRateLimitIntervally; - - LimitedApi(Function configExtractor) { - this((profileConfiguration, level) -> configExtractor.apply(profileConfiguration)); - } - - LimitedApi(BiFunction configExtractor) { - this.configExtractor = configExtractor; - this.refillRateLimitIntervally = false; - } - - LimitedApi(boolean refillRateLimitIntervally) { - this.configExtractor = null; - this.refillRateLimitIntervally = refillRateLimitIntervally; - } - - public String getLimitConfig(DefaultTenantProfileConfiguration profileConfiguration, Object level) { - if (configExtractor != null) { - return configExtractor.apply(profileConfiguration, level); - } else { - throw new IllegalArgumentException("No tenant profile config for " + name() + " rate limits"); - } - } - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/limits/RateLimitService.java b/dao/src/main/java/org/thingsboard/server/dao/util/limits/RateLimitService.java index c3f2fd179f..1f6e87111c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/limits/RateLimitService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/limits/RateLimitService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.util.limits; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.limit.LimitedApi; public interface RateLimitService { diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 9d5ad35388..75f9e09d3c 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -203,3 +203,10 @@ service: type: "${TB_SERVICE_TYPE:tb-vc-executor}" # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" + +notification_system: + rules: + trigger_types_configs: + RATE_LIMITS: + # In milliseconds, 4 hours by default + deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 7ea553fe5c..8fe079859a 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -302,3 +302,10 @@ management: exposure: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' + +notification_system: + rules: + trigger_types_configs: + RATE_LIMITS: + # In milliseconds, 4 hours by default + deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 346ec48eae..f05db08643 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -287,3 +287,10 @@ management: exposure: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' + +notification_system: + rules: + trigger_types_configs: + RATE_LIMITS: + # In milliseconds, 4 hours by default + deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 4e8167d89d..745a7d126a 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -369,3 +369,10 @@ management: exposure: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' + +notification_system: + rules: + trigger_types_configs: + RATE_LIMITS: + # In milliseconds, 4 hours by default + deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 1e0b1ebcd4..3795c533a7 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -317,3 +317,10 @@ management: exposure: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' + +notification_system: + rules: + trigger_types_configs: + RATE_LIMITS: + # In milliseconds, 4 hours by default + deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 9f086bcbc5..11dcc96010 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -267,3 +267,10 @@ management: exposure: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' + +notification_system: + rules: + trigger_types_configs: + RATE_LIMITS: + # In milliseconds, 4 hours by default + deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" From d5d087d82616670d549bf48aee02befc6a0d905d Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 2 Jun 2023 15:09:35 +0300 Subject: [PATCH 089/421] UI part and help page for exceeded rate limits notification rule --- .../rule-notification-dialog.component.html | 12 +++++ .../rule-notification-dialog.component.ts | 11 +++- .../template-notification-dialog.component.ts | 1 + .../app/shared/models/notification.models.ts | 13 ++++- .../help/en_US/notification/rate_limits.md | 50 +++++++++++++++++++ .../assets/locale/locale.constant-en_US.json | 5 +- 6 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 ui-ngx/src/assets/help/en_US/notification/rate_limits.md diff --git a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html index fc48392e8c..0cf94e0292 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html @@ -496,6 +496,18 @@ + + {{ 'notification.rate-limits-trigger-settings' | translate }} +
+
+ + notification.description + + +
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts index 93b22911f3..985f121432 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts @@ -95,6 +95,7 @@ export class RuleNotificationDialogComponent extends entitiesLimitTemplateForm: FormGroup; apiUsageLimitTemplateForm: FormGroup; newPlatformVersionTemplateForm: FormGroup; + rateLimitsTemplateForm: FormGroup; triggerType = TriggerType; triggerTypes: TriggerType[]; @@ -302,6 +303,12 @@ export class RuleNotificationDialogComponent extends }) }); + this.rateLimitsTemplateForm = this.fb.group({ + triggerConfig: this.fb.group({ + + }) + }); + this.triggerTypeFormsMap = new Map([ [TriggerType.ALARM, this.alarmTemplateForm], [TriggerType.ALARM_COMMENT, this.alarmCommentTemplateForm], @@ -311,7 +318,8 @@ export class RuleNotificationDialogComponent extends [TriggerType.RULE_ENGINE_COMPONENT_LIFECYCLE_EVENT, this.ruleEngineEventsTemplateForm], [TriggerType.ENTITIES_LIMIT, this.entitiesLimitTemplateForm], [TriggerType.API_USAGE_LIMIT, this.apiUsageLimitTemplateForm], - [TriggerType.NEW_PLATFORM_VERSION, this.newPlatformVersionTemplateForm] + [TriggerType.NEW_PLATFORM_VERSION, this.newPlatformVersionTemplateForm], + [TriggerType.RATE_LIMITS, this.rateLimitsTemplateForm] ]); if (data.isAdd || data.isCopy) { @@ -447,6 +455,7 @@ export class RuleNotificationDialogComponent extends TriggerType.ENTITIES_LIMIT, TriggerType.API_USAGE_LIMIT, TriggerType.NEW_PLATFORM_VERSION, + TriggerType.RATE_LIMITS ]); if (this.isSysAdmin()) { diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts index b4ba480732..983ad4b569 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts @@ -181,6 +181,7 @@ export class TemplateNotificationDialogComponent NotificationType.ENTITIES_LIMIT, NotificationType.API_USAGE_LIMIT, NotificationType.NEW_PLATFORM_VERSION, + NotificationType.RATE_LIMITS ]); if (this.isSysAdmin()) { diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 59af9295e1..48902231ca 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -444,7 +444,8 @@ export enum NotificationType { ENTITIES_LIMIT = 'ENTITIES_LIMIT', API_USAGE_LIMIT = 'API_USAGE_LIMIT', NEW_PLATFORM_VERSION = 'NEW_PLATFORM_VERSION', - RULE_NODE = 'RULE_NODE' + RULE_NODE = 'RULE_NODE', + RATE_LIMITS = 'RATE_LIMITS' } export const NotificationTypeIcons = new Map([ @@ -549,6 +550,12 @@ export const NotificationTemplateTypeTranslateMap = new Map([ @@ -574,4 +582,5 @@ export const TriggerTypeTranslationMap = new Map([ [TriggerType.ENTITIES_LIMIT, 'notification.trigger.entities-limit'], [TriggerType.API_USAGE_LIMIT, 'notification.trigger.api-usage-limit'], [TriggerType.NEW_PLATFORM_VERSION, 'notification.trigger.new-platform-version'], + [TriggerType.RATE_LIMITS, 'notification.trigger.rate-limits'], ]); diff --git a/ui-ngx/src/assets/help/en_US/notification/rate_limits.md b/ui-ngx/src/assets/help/en_US/notification/rate_limits.md new file mode 100644 index 0000000000..8f6319ad80 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/notification/rate_limits.md @@ -0,0 +1,50 @@ +#### Exceeded rate limits notification templatization + +
+
+ +Notification subject and message fields support templatization. +The list of available templatization parameters depends on the template type. +See the available types and parameters below: + +Available template parameters: + +* `api` - rate-limited API label; one of: 'REST API requests', 'REST API requests per customer', 'transport messages', + 'transport messages per device', 'Cassandra queries', 'WS updates per session', 'notification requests', 'notification requests per rule', + 'entity version creation', 'entity version load'; +* `limitLevelEntityType` - entity type of the limit level entity, e.g. 'Tenant', 'Device', 'Notification rule', 'Customer', etc.; +* `limitLevelEntityId` - id of the limit level entity; +* `limitLevelEntityName` - name of the limit level entity; +* `tenantId` - id of the tenant; +* `tenantName` - name of the tenant; +* `recipientTitle` - title of the recipient (first and last name if specified, email otherwise); +* `recipientEmail` - email of the recipient; +* `recipientFirstName` - first name of the recipient; +* `recipientLastName` - last name of the recipient; + +Parameter names must be wrapped using `${...}`. For example: `${recipientFirstName}`. +You may also modify the value of the parameter with one of the suffixes: + +* `upperCase`, for example - `${recipientFirstName:upperCase}` +* `lowerCase`, for example - `${recipientFirstName:lowerCase}` +* `capitalize`, for example - `${recipientFirstName:capitalize}` + +
+ +##### Examples + +Let's assume customer 'Customer A' exceeded rate limit for per-customer REST API requests. The following template: + +```text +Rate limits for ${api} exceeded for ${limitLevelEntityType:lowerCase} '${limitLevelEntityName}' +{:copy-code} +``` + +will be transformed to: + +```text +Rate limits for REST API requests per customer exceeded for customer 'Customer A' +``` + +
+
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 2fab5b1e85..1c20dbe740 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2818,6 +2818,7 @@ "api-feature-hint": "If the field is empty, the trigger will be applied to all api features", "api-usage-trigger-settings": "API usage trigger settings", "new-platform-version-trigger-settings": "New platform version trigger settings", + "rate-limits-trigger-settings": "Exceeded rate limits trigger settings", "at-least-one-should-be-selected": "At least one should be selected", "basic-settings": "Basic settings", "button-text": "Button text", @@ -3013,7 +3014,8 @@ "general": "General", "rule-engine-lifecycle-event": "Rule engine lifecycle event", "rule-node": "Rule node", - "new-platform-version": "New platform version" + "new-platform-version": "New platform version", + "rate-limits": "Exceeded rate limits" }, "templates": "Templates", "notification-templates": "Notifications / Templates", @@ -3032,6 +3034,7 @@ "entity-action": "Entity action", "rule-engine-lifecycle-event": "Rule engine lifecycle event", "new-platform-version": "New platform version", + "rate-limits": "Exceeded rate limits", "trigger": "Trigger", "trigger-required": "Trigger is required" }, From 4dbe1cf0049dde11846ba63a81a59f04129d9c9a Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 5 Jun 2023 11:13:29 +0300 Subject: [PATCH 090/421] UI: Add support new notification rule Rate limits and improve string items list --- ui-ngx/src/app/modules/common/modules-map.ts | 2 + .../rule-notification-dialog.component.html | 10 ++ .../rule-notification-dialog.component.ts | 11 +- .../string-items-list.component.html | 65 ++++--- .../components/string-items-list.component.ts | 167 +++++++++++++++--- .../app/shared/models/limited-api.models.ts | 43 +++++ .../app/shared/models/notification.models.ts | 7 +- ui-ngx/src/app/shared/models/public-api.ts | 1 + .../assets/locale/locale.constant-en_US.json | 17 +- 9 files changed, 271 insertions(+), 52 deletions(-) create mode 100644 ui-ngx/src/app/shared/models/limited-api.models.ts diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 40172e2667..fb6ffb1057 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -177,6 +177,7 @@ import * as CopyButtonComponent from '@shared/components/button/copy-button.comp import * as TogglePasswordComponent from '@shared/components/button/toggle-password.component'; import * as ProtobufContentComponent from '@shared/components/protobuf-content.component'; import * as SlackConversationAutocompleteComponent from '@shared/components/slack-conversation-autocomplete.component'; +import * as StringItemsListComponent from '@shared/components/string-items-list.component'; import * as AddEntityDialogComponent from '@home/components/entity/add-entity-dialog.component'; import * as EntitiesTableComponent from '@home/components/entity/entities-table.component'; @@ -472,6 +473,7 @@ class ModulesMap implements IModulesMap { '@shared/components/button/toggle-password.component': TogglePasswordComponent, '@shared/components/protobuf-content.component': ProtobufContentComponent, '@shared/components/slack-conversation-autocomplete.component': SlackConversationAutocompleteComponent, + '@shared/components/string-items-list.component': StringItemsListComponent, '@home/components/entity/add-entity-dialog.component': AddEntityDialogComponent, '@home/components/entity/entities-table.component': EntitiesTableComponent, diff --git a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html index 0cf94e0292..d8e5f8ce31 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.html @@ -499,6 +499,16 @@ {{ 'notification.rate-limits-trigger-settings' | translate }} +
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts index 985f121432..eb156cd071 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-notification-dialog.component.ts @@ -66,6 +66,8 @@ import { ApiUsageStateValue, ApiUsageStateValueTranslationMap } from '@shared/models/api-usage.models'; +import { LimitedApi, LimitedApiTranslationMap } from '@shared/models/limited-api.models'; +import { StringItemsOption } from '@shared/components/string-items-list.component'; export interface RuleNotificationDialogData { rule?: NotificationRule; @@ -130,6 +132,8 @@ export class RuleNotificationDialogComponent extends apiFeatures: ApiFeature[] = Object.values(ApiFeature); apiFeatureTranslationMap = ApiFeatureTranslationMap; + limitedApis: StringItemsOption[]; + entityType = EntityType; isAdd = true; @@ -172,6 +176,11 @@ export class RuleNotificationDialogComponent extends this.isAdd = data.isAdd; } + this.limitedApis = Object.values(LimitedApi).map(value => ({ + name: this.translate.instant(LimitedApiTranslationMap.get(value)), + value + })); + this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-xs']) .pipe(map(({matches}) => matches ? 'horizontal' : 'vertical')); @@ -305,7 +314,7 @@ export class RuleNotificationDialogComponent extends this.rateLimitsTemplateForm = this.fb.group({ triggerConfig: this.fb.group({ - + apis: [] }) }); diff --git a/ui-ngx/src/app/shared/components/string-items-list.component.html b/ui-ngx/src/app/shared/components/string-items-list.component.html index f1f9f0d118..4677cbc3de 100644 --- a/ui-ngx/src/app/shared/components/string-items-list.component.html +++ b/ui-ngx/src/app/shared/components/string-items-list.component.html @@ -15,24 +15,47 @@ limitations under the License. --> -
- - {{ label }} - - - {{item}} - close - - - - {{ hint }} - {{ requiredText }} - -
+ + {{ label }} + + + {{ item.name }} + close + + + + + + + + + {{ 'common.not-found' | translate }} + + + {{ hint }} + + {{ requiredText }} + + diff --git a/ui-ngx/src/app/shared/components/string-items-list.component.ts b/ui-ngx/src/app/shared/components/string-items-list.component.ts index 0febd3cad4..274f12fd3a 100644 --- a/ui-ngx/src/app/shared/components/string-items-list.component.ts +++ b/ui-ngx/src/app/shared/components/string-items-list.component.ts @@ -14,13 +14,27 @@ /// limitations under the License. /// -import { Component, forwardRef, Input } from '@angular/core'; -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { + AbstractControl, + ControlValueAccessor, + FormBuilder, + FormGroup, + NG_VALUE_ACCESSOR, + Validators +} from '@angular/forms'; import { MatChipInputEvent } from '@angular/material/chips'; import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; import { FloatLabelType, MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field'; -import { coerceBoolean } from '@shared/decorators/coercion'; +import { coerceArray, coerceBoolean } from '@shared/decorators/coercion'; +import { Observable, of } from 'rxjs'; +import { filter, mergeMap, share, tap } from 'rxjs/operators'; +import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; +export interface StringItemsOption { + name: string; + value: any; +} @Component({ selector: 'tb-string-items-list', templateUrl: './string-items-list.component.html', @@ -33,17 +47,29 @@ import { coerceBoolean } from '@shared/decorators/coercion'; } ] }) -export class StringItemsListComponent implements ControlValueAccessor{ +export class StringItemsListComponent implements ControlValueAccessor, OnInit { stringItemsForm: FormGroup; + + filteredValues: Observable>; + + searchText = ''; + + itemList: StringItemsOption[] = []; + private modelValue: Array | null; readonly separatorKeysCodes: number[] = [ENTER, COMMA, SEMICOLON]; + @ViewChild('stringItemInput', {static: true}) stringItemInput: ElementRef; + @ViewChild(MatAutocompleteTrigger) autocomplete: MatAutocompleteTrigger; + private requiredValue: boolean; + get required(): boolean { return this.requiredValue; } + @Input() @coerceBoolean() set required(value: boolean) { @@ -80,19 +106,52 @@ export class StringItemsListComponent implements ControlValueAccessor{ editable = false; @Input() - subscriptSizing: SubscriptSizing = 'fixed' + subscriptSizing: SubscriptSizing = 'fixed'; - private propagateChange = (v: any) => { }; + @Input() + @coerceArray() + predefinedValues: StringItemsOption[]; + + get itemsControl(): AbstractControl { + return this.stringItemsForm.get('items'); + } + + get itemControl(): AbstractControl { + return this.stringItemsForm.get('item'); + } + + private propagateChange = (v: any) => { + }; + private dirty = false; constructor(private fb: FormBuilder) { this.stringItemsForm = this.fb.group({ - items: [null, this.required ? [Validators.required] : []] + item: [null], + items: [null] }); } + ngOnInit() { + if (this.predefinedValues) { + this.filteredValues = this.itemControl.valueChanges + .pipe( + tap((value) => { + if (value && typeof value !== 'string') { + this.add(value); + } else if (value === null) { + this.clear(); + } + }), + filter((value) => typeof value === 'string'), + mergeMap(name => this.fetchValues(name)), + share() + ); + } + } + updateValidators() { - this.stringItemsForm.get('items').setValidators(this.required ? [Validators.required] : []); - this.stringItemsForm.get('items').updateValueAndValidity(); + this.itemsControl.setValidators(this.required ? [Validators.required] : []); + this.itemsControl.updateValueAndValidity(); } registerOnChange(fn: any): void { @@ -112,48 +171,100 @@ export class StringItemsListComponent implements ControlValueAccessor{ } writeValue(value: Array | null): void { + this.searchText = ''; if (value != null && value.length > 0) { this.modelValue = [...value]; - this.stringItemsForm.get('items').setValue(value); + this.itemList = []; + if (this.predefinedValues) { + value.forEach(item => { + const findItem = this.predefinedValues.find(option => option.value === item); + if (findItem) { + this.itemList.push(findItem); + } + }); + } else { + value.forEach(item => this.itemList.push({value: item, name: item})); + } + this.itemsControl.setValue(this.itemList, {emitEvents: false}); } else { - this.stringItemsForm.get('items').setValue(null); + this.itemsControl.setValue(null, {emitEvents: false}); this.modelValue = null; + this.itemList = []; } + this.dirty = true; } addItem(event: MatChipInputEvent): void { - let item = event.value || ''; - const input = event.chipInput.inputElement; - item = item.trim(); + const item = event.value?.trim() ?? ''; if (item) { - if (!this.modelValue || this.modelValue.indexOf(item) === -1) { - if (!this.modelValue) { - this.modelValue = []; + if (this.predefinedValues) { + const findItems = this.predefinedValues + .filter(value => value.name.toLowerCase().includes(item.toLowerCase())); + if (findItems.length === 1) { + this.add(findItems[0]); } - this.modelValue.push(item); - this.stringItemsForm.get('items').setValue(this.modelValue); - } - this.propagateChange(this.modelValue); - if (input) { - input.value = ''; + } else { + this.add({value: item, name: item}); } } } - removeItems(item: string) { - const index = this.modelValue.indexOf(item); + removeItems(item: StringItemsOption) { + const index = this.modelValue.indexOf(item.value); if (index >= 0) { this.modelValue.splice(index, 1); + this.itemList.splice(index, 1); if (!this.modelValue.length) { this.modelValue = null; } - this.stringItemsForm.get('items').setValue(this.modelValue); + this.itemsControl.setValue(this.itemList); this.propagateChange(this.modelValue); + this.autocomplete?.closePanel(); + } + } + + onFocus() { + if (this.dirty) { + this.itemControl.updateValueAndValidity({onlySelf: true, emitEvent: true}); + this.dirty = false; + } + } + + displayValueFn(values?: StringItemsOption): string | undefined { + return values ? values.name : undefined; + } + + private add(item: StringItemsOption) { + if (!this.modelValue || this.modelValue.indexOf(item.value) === -1) { + if (!this.modelValue) { + this.modelValue = []; + } + this.modelValue.push(item.value); + this.itemList.push(item); + this.itemsControl.setValue(this.itemList); } + this.propagateChange(this.modelValue); + this.clear(); } - get stringItemsList(): string[] { - return this.stringItemsForm.get('items').value; + private fetchValues(searchText?: string): Observable> { + if (!this.predefinedValues?.length) { + return of([]); + } + this.searchText = searchText; + let result = this.predefinedValues; + if (searchText && searchText.length) { + result = this.predefinedValues.filter(option => option.name.toLowerCase().includes(searchText.toLowerCase())); + } + return of(result); } + private clear(value: string = '') { + this.stringItemInput.nativeElement.value = value; + this.itemControl.patchValue(value, {emitEvent: true}); + setTimeout(() => { + this.stringItemInput.nativeElement.blur(); + this.stringItemInput.nativeElement.focus(); + }, 0); + } } diff --git a/ui-ngx/src/app/shared/models/limited-api.models.ts b/ui-ngx/src/app/shared/models/limited-api.models.ts new file mode 100644 index 0000000000..3b68800f24 --- /dev/null +++ b/ui-ngx/src/app/shared/models/limited-api.models.ts @@ -0,0 +1,43 @@ +/// +/// Copyright © 2016-2023 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. +/// + +export enum LimitedApi { + ENTITY_EXPORT = 'ENTITY_EXPORT', + ENTITY_IMPORT = 'ENTITY_IMPORT', + NOTIFICATION_REQUESTS = 'NOTIFICATION_REQUESTS', + NOTIFICATION_REQUESTS_PER_RULE = 'NOTIFICATION_REQUESTS_PER_RULE', + REST_REQUESTS_PER_TENANT = 'REST_REQUESTS_PER_TENANT', + REST_REQUESTS_PER_CUSTOMER = 'REST_REQUESTS_PER_CUSTOMER', + WS_UPDATES_PER_SESSION = 'WS_UPDATES_PER_SESSION', + CASSANDRA_QUERIES = 'CASSANDRA_QUERIES', + TRANSPORT_MESSAGES_PER_TENANT = 'TRANSPORT_MESSAGES_PER_TENANT', + TRANSPORT_MESSAGES_PER_DEVICE = 'TRANSPORT_MESSAGES_PER_DEVICE' +} + +export const LimitedApiTranslationMap = new Map( + [ + [LimitedApi.ENTITY_EXPORT, 'api-limit.entity-version-creation'], + [LimitedApi.ENTITY_IMPORT, 'api-limit.entity-version-load'], + [LimitedApi.NOTIFICATION_REQUESTS, 'api-limit.notification-requests'], + [LimitedApi.NOTIFICATION_REQUESTS_PER_RULE, 'api-limit.notification-requests-per-rule'], + [LimitedApi.REST_REQUESTS_PER_TENANT, 'api-limit.rest-api-requests'], + [LimitedApi.REST_REQUESTS_PER_CUSTOMER, 'api-limit.rest-api-requests-per-customer'], + [LimitedApi.WS_UPDATES_PER_SESSION, 'api-limit.ws-updates-per-session'], + [LimitedApi.CASSANDRA_QUERIES, 'api-limit.cassandra-queries'], + [LimitedApi.TRANSPORT_MESSAGES_PER_TENANT, 'api-limit.transport-messages'], + [LimitedApi.TRANSPORT_MESSAGES_PER_DEVICE, 'api-limit.transport-messages-per-device'] + ] +); diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 48902231ca..2cef7c6cc2 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -26,6 +26,7 @@ import { NotificationRuleId } from '@shared/models/id/notification-rule-id'; import { AlarmSearchStatus, AlarmSeverity, AlarmStatus } from '@shared/models/alarm.models'; import { EntityType } from '@shared/models/entity-type.models'; import { ApiFeature, ApiUsageStateValue } from '@shared/models/api-usage.models'; +import { LimitedApi } from '@shared/models/limited-api.models'; export interface Notification { readonly id: NotificationId; @@ -119,7 +120,7 @@ export interface NotificationRule extends Omit, 'la export type NotificationRuleTriggerConfig = Partial; + ApiUsageLimitNotificationRuleTriggerConfig & RateLimitsNotificationRuleTriggerConfig>; export interface AlarmNotificationRuleTriggerConfig { alarmTypes?: Array; @@ -178,6 +179,10 @@ export interface ApiUsageLimitNotificationRuleTriggerConfig { notifyOn: ApiUsageStateValue[]; } +export interface RateLimitsNotificationRuleTriggerConfig { + apis: LimitedApi[]; +} + export enum ComponentLifecycleEvent { STARTED = 'STARTED', UPDATED = 'UPDATED', diff --git a/ui-ngx/src/app/shared/models/public-api.ts b/ui-ngx/src/app/shared/models/public-api.ts index dbc5e11213..aa93bece92 100644 --- a/ui-ngx/src/app/shared/models/public-api.ts +++ b/ui-ngx/src/app/shared/models/public-api.ts @@ -37,6 +37,7 @@ export * from './entity-type.models'; export * from './entity-view.models'; export * from './error.models'; export * from './event.models'; +export * from './limited-api.models'; export * from './login.models'; export * from './material.models'; export * from './notification.models'; 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 1c20dbe740..056cd2c396 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -756,6 +756,18 @@ "view-details": "View details", "view-statistics": "View statistics" }, + "api-limit": { + "cassandra-queries": "Cassandra queries", + "entity-version-creation": "Entity version creation", + "entity-version-load": "Entity version load", + "notification-requests": "Notification requests", + "notification-requests-per-rule": "Notification requests per rule", + "rest-api-requests": "REST API requests", + "rest-api-requests-per-customer": "REST API requests per customer", + "transport-messages": "Transport messages", + "transport-messages-per-device": "Transport messages per device", + "ws-updates-per-session": "WS updates per session" + }, "audit-log": { "audit": "Audit", "audit-logs": "Audit Logs", @@ -839,7 +851,8 @@ "created-time": "Created time", "loading": "Loading...", "proceed": "Proceed", - "open-details-page": "Open details page" + "open-details-page": "Open details page", + "not-found": "Not found" }, "content-type": { "json": "Json", @@ -2936,6 +2949,8 @@ "only-rule-chain-lifecycle-failures": "Only rule chain lifecycle failures", "only-rule-node-lifecycle-failures": "Only rule node lifecycle failures", "platform-users": "Platform users", + "rate-limits": "Rate limits", + "rate-limits-hint": "If the field is empty, the trigger will be applied to all rate limits", "recipient": "Recipient", "recipient-group": "Recipient group", "recipient-type": { From 684e0159e1c1a630dd163e25aba33cf76728c697 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Wed, 7 Jun 2023 08:11:19 +0300 Subject: [PATCH 091/421] Added unassign for alarms on user removal --- .../entitiy/alarm/DefaultTbAlarmService.java | 43 +++++++++++++++++++ .../service/entitiy/alarm/TbAlarmService.java | 3 ++ .../entitiy/user/DefaultUserService.java | 3 ++ 3 files changed, 49 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index caf65d39ec..141917f11f 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmCommentType; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.alarm.AlarmQueryV2; import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; @@ -36,9 +37,13 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; @Service @AllArgsConstructor @@ -210,6 +215,44 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb return alarmInfo; } + @Override + public void unassignUserAlarms(TenantId tenantId, User user, long unassignTs) throws ThingsboardException { + AlarmQueryV2 alarmQuery = AlarmQueryV2.builder().assigneeId(user.getId()).pageLink(new TimePageLink(Integer.MAX_VALUE)).build(); + try { + List alarms = alarmService.findAlarmsV2(tenantId, alarmQuery).get(30, TimeUnit.SECONDS).getData(); + if (alarms.isEmpty()) { + throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND); + } + for (AlarmInfo alarm : alarms) { + AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(tenantId, alarm.getId(), getOrDefault(unassignTs)); + if (!result.isSuccessful()) { + continue; + } + if (result.isModified()) { + AlarmComment alarmComment = AlarmComment.builder() + .alarmId(alarm.getId()) + .type(AlarmCommentType.SYSTEM) + .comment(JacksonUtil.newObjectNode().put("text", String.format("Alarm was unassigned because user %s - was deleted", + (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName())) + .put("userId", user.getId().toString()) + .put("subtype", "ASSIGN")) + .build(); + try { + alarmCommentService.saveAlarmComment(alarm, alarmComment, user); + } catch (ThingsboardException e) { + log.error("Failed to save alarm comment", e); + } + notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user); + } else { + throw new ThingsboardException("Alarm was already unassigned!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } + } + + } catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new RuntimeException(e); + } + } + @Override public Boolean delete(Alarm alarm, User user) { TenantId tenantId = alarm.getTenantId(); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index a2ae9c8cc7..ed4af5d1bd 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -19,6 +19,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; public interface TbAlarmService { @@ -37,5 +38,7 @@ public interface TbAlarmService { AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException; + void unassignUserAlarms(TenantId tenantId, User user, long unassignTs) throws ThingsboardException; + Boolean delete(Alarm alarm, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java index c83c48cc8a..0c04e46ff5 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; +import org.thingsboard.server.service.entitiy.alarm.TbAlarmService; import org.thingsboard.server.service.security.system.SystemSecurityService; import javax.servlet.http.HttpServletRequest; @@ -43,6 +44,7 @@ import static org.thingsboard.server.controller.UserController.ACTIVATE_URL_PATT public class DefaultUserService extends AbstractTbEntityService implements TbUserService { private final UserService userService; + private final TbAlarmService tbAlarmService; private final MailService mailService; private final SystemSecurityService systemSecurityService; @@ -80,6 +82,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse UserId userId = tbUser.getId(); try { + tbAlarmService.unassignUserAlarms(tenantId, tbUser, System.currentTimeMillis()); userService.deleteUser(tenantId, userId); notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, userId, tbUser, user, ActionType.DELETED, true, null, customerId.toString()); From 11f897d9b126e60e4693d1c0615963fadf7c6b26 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Wed, 7 Jun 2023 10:03:17 +0300 Subject: [PATCH 092/421] Added test --- .../controller/AlarmControllerTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index 05030f0091..c6b31ce683 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -32,6 +32,7 @@ import org.springframework.test.context.ContextConfiguration; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmSeverity; @@ -39,6 +40,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.alarm.AlarmDao; import org.thingsboard.server.dao.service.DaoSqlTest; @@ -529,6 +531,41 @@ public class AlarmControllerTest extends AbstractControllerTest { tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ALARM_UNASSIGNED); } + @Test + public void testUnassignAlarmOnUserRemoving() throws Exception { + loginTenantAdmin(); + + + User user = new User(); + user.setAuthority(Authority.TENANT_ADMIN); + user.setTenantId(tenantId); + user.setEmail("tenantForAssign@thingsboard.org"); + User savedUser = createUser(user, "password"); + + Alarm alarm = createAlarm(TEST_ALARM_TYPE); + Mockito.reset(tbClusterService, auditLogService); + long beforeAssignmentTs = System.currentTimeMillis(); + Thread.sleep(2); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); + AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + + beforeAssignmentTs = System.currentTimeMillis(); + + Mockito.reset(tbClusterService, auditLogService); + + doDelete("/api/user/" + savedUser.getId().getId()).andExpect(status().isOk()); + Thread.sleep(2); + + foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + } + @Test public void testFindAlarmsViaCustomerUser() throws Exception { loginCustomerUser(); From 9a37fe7853b77098eccb1f313b6cc13f83e0f933 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 8 Jun 2023 12:27:42 +0300 Subject: [PATCH 093/421] UI: Math function rule node fixed validation --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 58f4b4ecdc..584309bd9f 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1 +1 @@ -System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@angular/material/radio","@angular/material/slide-toggle","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,r,n,a,o,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,F,v,L,k,I,T,N,q,S,M,A,G,E,D,V,P,R,w,O,H,K,B,U,z,j,_,$,J,Q,Y,W,X,Z,ee,te,re,ne,ae,oe,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,Fe,ve,Le,ke,Ie,Te,Ne,qe,Se,Me,Ae,Ge,Ee,De,Ve,Pe,Re,we,Oe,He,Ke;return{setters:[function(e){t=e,r=e.Component,n=e.Pipe,a=e.ViewChild,o=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.MessageType,C=e.messageTypeNames,F=e,v=e.SharedModule,L=e.AggregationType,k=e.aggregationTranslations,I=e.NotificationType,T=e.SlackChanelType,N=e.SlackChanelTypesTranslateMap,q=e.alarmStatusTranslations,S=e.AlarmStatus},function(e){M=e},function(e){A=e,G=e.Validators,E=e.NgControl,D=e.NG_VALUE_ACCESSOR,V=e.NG_VALIDATORS,P=e.UntypedFormControl},function(e){R=e,w=e.CommonModule},function(e){O=e},function(e){H=e},function(e){K=e},function(e){B=e},function(e){U=e},function(e){z=e},function(e){j=e},function(e){_=e},function(e){$=e},function(e){J=e.getCurrentAuthState,Q=e,Y=e.isDefinedAndNotNull,W=e.isObject,X=e.isUndefinedOrNull,Z=e.isNotEmptyStr},function(e){ee=e},function(e){te=e},function(e){re=e},function(e){ne=e.ENTER,ae=e.COMMA,oe=e.SEMICOLON},function(e){ie=e},function(e){le=e},function(e){se=e},function(e){me=e},function(e){ue=e.coerceBooleanProperty},function(e){pe=e},function(e){de=e},function(e){ce=e},function(e){fe=e},function(e){ge=e},function(e){ye=e.tap,xe=e.map,be=e.mergeMap,he=e.takeUntil,Ce=e.startWith,Fe=e.share},function(e){ve=e},function(e){Le=e},function(e){ke=e.of,Ie=e.Subject},function(e){Te=e},function(e){Ne=e.HomeComponentsModule},function(e){qe=e},function(e){Se=e},function(e){Me=e},function(e){Ae=e},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){Pe=e},function(e){Re=e},function(e){we=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e}],execute:function(){class Be extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Be),Be.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Be,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Be.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Be,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Be,decorators:[{type:r,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ue{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Ue),Ue.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ue,deps:[{token:z.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Ue.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Ue,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ue,decorators:[{type:n,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:z.DomSanitizer}]}});class ze extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[G.required,G.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[G.required,G.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",ze),ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ze,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ze,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ze,decorators:[{type:r,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class je extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",je),je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:je,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:je,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:je,decorators:[{type:r,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class _e extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[G.required]]})}}e("CheckPointConfigComponent",_e),_e.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_e,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_e.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_e,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:$.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_e,decorators:[{type:r,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class $e extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[G.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[G.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[G.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.clearAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=e===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",n=this.clearAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.clearAlarmConfigForm.get(t).setValue(e)}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",$e),$e.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$e,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),$e.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$e,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$e,decorators:[{type:r,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Je extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[ne,ae,oe],this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,r=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([G.required]),this.createAlarmConfigForm.get("severity").setValidators([G.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let n=this.createAlarmConfigForm.get("scriptLang").value;n!==d.TBEL||this.tbelEnabled||(n=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(n,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const a=!1===t||!0===r;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(a&&n===d.JS?[G.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(a&&n===d.TBEL?[G.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",n=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Je,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,decorators:[{type:r,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[G.required]],entityType:[e?e.entityType:null,[G.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[G.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[G.required,G.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([G.required,G.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([G.required,G.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",Qe),Qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qe,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qe,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qe,decorators:[{type:r,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[G.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[G.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[G.required,G.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([G.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([G.required,G.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ye,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,decorators:[{type:r,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,G.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,G.required]})}}e("DeviceProfileConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:We,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,decorators:[{type:r,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Xe extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[G.required,G.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[G.required,G.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",n=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var Ze;e("GeneratorConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xe,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:$.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,decorators:[{type:r,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(Ze||(Ze={}));const et=new Map([[Ze.CUSTOMER,"tb.rulenode.originator-customer"],[Ze.TENANT,"tb.rulenode.originator-tenant"],[Ze.RELATED,"tb.rulenode.originator-related"],[Ze.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[Ze.ENTITY,"tb.rulenode.originator-entity"]]);var tt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(tt||(tt={}));const rt=new Map([[tt.CIRCLE,"tb.rulenode.perimeter-circle"],[tt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var nt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(nt||(nt={}));const at=new Map([[nt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[nt.SECONDS,"tb.rulenode.time-unit-seconds"],[nt.MINUTES,"tb.rulenode.time-unit-minutes"],[nt.HOURS,"tb.rulenode.time-unit-hours"],[nt.DAYS,"tb.rulenode.time-unit-days"]]);var ot;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(ot||(ot={}));const it=new Map([[ot.METER,"tb.rulenode.range-unit-meter"],[ot.KILOMETER,"tb.rulenode.range-unit-kilometer"],[ot.FOOT,"tb.rulenode.range-unit-foot"],[ot.MILE,"tb.rulenode.range-unit-mile"],[ot.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var lt;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(lt||(lt={}));const st=new Map([[lt.ID,"tb.rulenode.entity-details-id"],[lt.TITLE,"tb.rulenode.entity-details-title"],[lt.COUNTRY,"tb.rulenode.entity-details-country"],[lt.STATE,"tb.rulenode.entity-details-state"],[lt.CITY,"tb.rulenode.entity-details-city"],[lt.ZIP,"tb.rulenode.entity-details-zip"],[lt.ADDRESS,"tb.rulenode.entity-details-address"],[lt.ADDRESS2,"tb.rulenode.entity-details-address2"],[lt.PHONE,"tb.rulenode.entity-details-phone"],[lt.EMAIL,"tb.rulenode.entity-details-email"],[lt.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var mt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(mt||(mt={}));const ut=new Map([[mt.FIRST,"tb.rulenode.first-message"],[mt.LAST,"tb.rulenode.last-message"],[mt.ALL,"tb.rulenode.all-messages"]]);var pt,dt;!function(e){e.ASC="ASC",e.DESC="DESC"}(pt||(pt={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(dt||(dt={}));const ct=new Map([[dt.STANDARD,"tb.rulenode.sqs-queue-standard"],[dt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),ft=["anonymous","basic","cert.PEM"],gt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),yt=["sas","cert.PEM"],xt=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var bt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(bt||(bt={}));const ht=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Ct=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Ft;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Ft||(Ft={}));const vt=new Map([[Ft.CUSTOM,{value:Ft.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Ft.ADD,{value:Ft.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Ft.SUB,{value:Ft.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Ft.MULT,{value:Ft.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Ft.DIV,{value:Ft.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Ft.SIN,{value:Ft.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Ft.SINH,{value:Ft.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Ft.COS,{value:Ft.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Ft.COSH,{value:Ft.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Ft.TAN,{value:Ft.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Ft.TANH,{value:Ft.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Ft.ACOS,{value:Ft.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Ft.ASIN,{value:Ft.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Ft.ATAN,{value:Ft.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Ft.ATAN2,{value:Ft.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Ft.EXP,{value:Ft.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Ft.EXPM1,{value:Ft.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Ft.SQRT,{value:Ft.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Ft.CBRT,{value:Ft.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Ft.GET_EXP,{value:Ft.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Ft.HYPOT,{value:Ft.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Ft.LOG,{value:Ft.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Ft.LOG10,{value:Ft.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Ft.LOG1P,{value:Ft.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Ft.CEIL,{value:Ft.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Ft.FLOOR,{value:Ft.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Ft.FLOOR_DIV,{value:Ft.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Ft.FLOOR_MOD,{value:Ft.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Ft.ABS,{value:Ft.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Ft.MIN,{value:Ft.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Ft.MAX,{value:Ft.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Ft.POW,{value:Ft.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Ft.SIGNUM,{value:Ft.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Ft.RAD,{value:Ft.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Ft.DEG,{value:Ft.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Lt,kt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Lt||(Lt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(kt||(kt={}));const It=new Map([[Lt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Lt.TIME_SERIES,"tb.rulenode.time-series-type"],[Lt.CONSTANT,"tb.rulenode.constant-type"],[Lt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Lt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),Tt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Nt,qt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Nt||(Nt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(qt||(qt={}));const St=new Map([[Nt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Nt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Nt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=tt,this.perimeterTypes=Object.keys(tt),this.perimeterTypeTranslationMap=rt,this.rangeUnits=Object.keys(ot),this.rangeUnitTranslationMap=it,this.timeUnits=Object.keys(nt),this.timeUnitsTranslationMap=at}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[G.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[G.required]],perimeterType:[e?e.perimeterType:null,[G.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[G.required,G.min(1),G.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[G.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[G.required,G.min(1),G.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[G.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([G.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||r!==tt.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([G.required,G.min(-90),G.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([G.required,G.min(-180),G.max(180)]),this.geoActionConfigForm.get("range").setValidators([G.required,G.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([G.required])),t||r!==tt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([G.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Mt),Mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mt,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mt,decorators:[{type:r,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class At extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",n=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",At),At.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:At,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),At.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:At,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:At,decorators:[{type:r,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[G.required,G.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[G.required]]})}}e("MsgCountConfigComponent",Gt),Gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Gt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gt,decorators:[{type:r,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[G.required,G.min(1),G.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([G.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([G.required,G.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Et),Et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Et,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Et,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Et,decorators:[{type:r,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]]})}}e("PushToCloudConfigComponent",Dt),Dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dt,decorators:[{type:r,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]]})}}e("PushToEdgeConfigComponent",Vt),Vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vt,decorators:[{type:r,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",Pt),Pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pt,decorators:[{type:r,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[G.required,G.min(0)]]})}}e("RpcRequestConfigComponent",Rt),Rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rt,decorators:[{type:r,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class wt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.injector=r,this.fb=n,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(E),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const r of Object.keys(e))Object.prototype.hasOwnProperty.call(e,r)&&t.push(this.fb.group({key:[r,[G.required]],value:[e[r],[G.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[G.required]],value:["",[G.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",wt),wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wt,deps:[{token:M.Store},{token:U.TranslateService},{token:t.Injector},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:D,useExisting:o((()=>wt)),multi:!0},{provide:V,useExisting:o((()=>wt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:de.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ce.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wt,decorators:[{type:r,args:[{selector:"tb-kv-map-config",providers:[{provide:D,useExisting:o((()=>wt)),multi:!0},{provide:V,useExisting:o((()=>wt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:t.Injector},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[G.required,G.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[G.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Ot),Ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ot,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ot,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ot,decorators:[{type:r,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[G.required,G.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ht,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,decorators:[{type:r,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[G.required,G.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[G.required,G.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kt,decorators:[{type:r,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]],keys:[e?e.keys:null,[G.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bt,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bt,decorators:[{type:r,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:a,args:["attributeChipList"]}]}});class Ut extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup())}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.injector=r,this.fb=n,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=vt,this.ArgumentType=Lt,this.attributeScopeMap=St,this.argumentTypeResultMap=It,this.arguments=Object.values(Lt),this.attributeScope=Object.values(Nt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(E),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({}),this.argumentsFormGroup.addControl("arguments",this.fb.array([])),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),r=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,r),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):this.argumentsFormGroup.enable({emitEvent:!1})}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()));const t=[];e&&e.forEach(((e,r)=>{t.push(this.createArgumentControl(e,r))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t)),this.setupArgumentsFormGroup(),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()})))}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(){const e=this.argumentsFormGroup.get("arguments"),t=this.createArgumentControl(null,e.length);e.push(t)}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Ft.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([G.minLength(this.minArgs),G.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(r),r.get("attributeScope").updateValueAndValidity({emitEvent:!0}),r.get("defaultValue").updateValueAndValidity({emitEvent:!0})}))),r}updateArgumentControlValidators(e){const t=e.get("type").value;t===Lt.ATTRIBUTE?e.get("attributeScope").enable():e.get("attributeScope").disable(),t&&t!==Lt.CONSTANT?e.get("defaultValue").enable():e.get("defaultValue").disable()}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Tt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,deps:[{token:M.Store},{token:U.TranslateService},{token:t.Injector},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ut,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:D,useExisting:o((()=>Ut)),multi:!0},{provide:V,useExisting:o((()=>Ut)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:de.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:fe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:fe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:ge.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:ge.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:ge.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ce.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,decorators:[{type:r,args:[{selector:"tb-arguments-map-config",providers:[{provide:D,useExisting:o((()=>Ut)),multi:!0},{provide:V,useExisting:o((()=>Ut)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:t.Injector},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class zt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.injector=r,this.fb=n,this.searchText="",this.dirty=!1,this.mathOperation=[...vt.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(ye((e=>{let t;t="string"==typeof e&&Ft[e]?Ft[e]:null,this.updateView(t)})),xe((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=vt.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:M.Store},{token:U.TranslateService},{token:t.Injector},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:D,useExisting:o((()=>zt)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:r,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:D,useExisting:o((()=>zt)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:t.Injector},{type:A.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:a,args:["operationInput",{static:!0}]}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Ft,this.ArgumentTypeResult=kt,this.argumentTypeResultMap=It,this.attributeScopeMap=St,this.argumentsResult=Object.values(kt),this.attributeScopeResult=Object.values(qt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[G.required]],arguments:[e?e.arguments:null,[G.required]],customFunction:[e?e.customFunction:"",[G.required]],result:this.fb.group({type:[e?e.result.type:null,[G.required]],attributeScope:[e?e.result.attributeScope:null],key:[e?e.result.key:"",[G.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,r=this.mathFunctionConfigForm.get("result").get("type").value;t===Ft.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),r===kt.ATTRIBUTE?this.mathFunctionConfigForm.get("result").get("attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result").get("attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result").get("attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:A.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ut,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:zt,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:r,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class _t{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[G.required,G.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(ye((e=>{this.updateView(e)})),xe((e=>e||"")),be((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,ke(this.messageTypes).pipe(xe((r=>r.filter((r=>t?!!e&&r===e:!e||r.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_t,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:D,useExisting:o((()=>_t)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,decorators:[{type:r,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:D,useExisting:o((()=>_t)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{messageTypeInput:[{type:a,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Ie,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=mt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=ut}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[Y(e?.interval)?e.interval:null,[G.required,G.min(1)]],strategy:[Y(e?.strategy)?e.strategy:null,[G.required]],outMsgType:[Y(e?.outMsgType)?e.outMsgType:null,[G.required]],queueName:[Y(e?.queueName)?e.queueName:null,[G.required]],maxPendingMsgs:[Y(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[G.required,G.min(1),G.max(1e3)]],maxRetries:[Y(e?.maxRetries)?e.maxRetries:null,[G.required,G.min(0),G.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(he(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:$.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Te.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Te.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Te.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:_t,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:r,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Jt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[G.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[G.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:D,useExisting:o((()=>Jt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:qe.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled","subscriptSizing"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:r,args:[{selector:"tb-device-relations-query-config",providers:[{provide:D,useExisting:o((()=>Jt)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class Qt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[G.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:D,useExisting:o((()=>Qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Me.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:r,args:[{selector:"tb-relations-query-config",providers:[{provide:D,useExisting:o((()=>Qt)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class Yt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.truncate=r,this.fb=n,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[ne,ae,oe],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(h))this.messageTypesList.push({name:C.get(h[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Ce(""),xe((e=>e||"")),be((e=>this.fetchMessageTypes(e))),Fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return ke(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return ke(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const r=e.trim(),n=this.messageTypesList.find((e=>e.name===r));t=n?{name:n.name,value:n.value}:{name:r,value:r},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:M.Store},{token:U.TranslateService},{token:F.TruncatePipe},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:D,useExisting:o((()=>Yt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ve.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:r,args:[{selector:"tb-message-types-config",providers:[{provide:D,useExisting:o((()=>Yt)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:F.TruncatePipe},{type:A.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:a,args:["chipList",{static:!1}]}],matAutocomplete:[{type:a,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:a,args:["messageTypeInput",{static:!1}]}]}});class Wt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=ft,this.credentialsTypeTranslationsMap=gt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[G.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const r=e[t];if(!r.firstChange&&r.currentValue!==r.previousValue&&r.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){Y(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([G.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[G.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(G.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return r=>{t||(t=[Object.keys(r.controls)]);return r?.controls&&t.some((t=>t.every((t=>!e(r.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:M.Store},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:D,useExisting:o((()=>Wt)),multi:!0},{provide:V,useExisting:o((()=>Wt)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Te.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Te.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Te.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Te.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ae.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:r,args:[{selector:"tb-credentials-config",providers:[{provide:D,useExisting:o((()=>Wt)),multi:!0},{provide:V,useExisting:o((()=>Wt)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class Xt{}e("RulenodeCoreConfigCommonModule",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Xt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Xt,declarations:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t],imports:[w,v,Ne],exports:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t]}),Xt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,imports:[w,v,Ne]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:l,args:[{declarations:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t],imports:[w,v,Ne],exports:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t]}]}]});class Zt{}e("RuleNodeCoreConfigActionModule",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Zt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Zt,declarations:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t],imports:[w,v,Ne,Xt],exports:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t]}),Zt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,imports:[w,v,Ne,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:l,args:[{declarations:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t],imports:[w,v,Ne,Xt],exports:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t]}]}]});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[G.required]],outputValueKey:[e?e.outputValueKey:null,[G.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[G.min(0),G.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([G.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:er,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:r,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[G.required]]})}}e("CustomerAttributesConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[G.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],fetchToData:[!!e&&e.fetchToData,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}prepareInputConfig(e){return W(e)&&X(e?.fetchToData)&&(e.fetchToData=!1),e}}e("DeviceAttributesConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Jt,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class nr extends s{constructor(e,t,r){super(e),this.store=e,this.translate=t,this.fb=r,this.entityDetailsTranslationsMap=st,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(lt))this.entityDetailsList.push(lt[e]);this.detailsFormControl=new P(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(Ce(""),xe((e=>e||"")),be((e=>this.fetchEntityDetails(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],e}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[G.required]],addToMetadata:[!!e&&e.addToMetadata,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(st.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return ke(this.entityDetailsList.filter((t=>this.translate.instant(st.get(lt[t])).toUpperCase().includes(e))))}return ke(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:M.Store},{token:U.TranslateService},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ve.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:A.UntypedFormBuilder}]},propDecorators:{detailsInput:[{type:a,args:["detailsInput",{static:!1}]}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe],this.aggregationTypes=L,this.aggregations=Object.keys(L),this.aggregationTypesTranslations=k,this.fetchMode=mt,this.fetchModes=Object.keys(mt),this.samplingOrders=Object.keys(pt),this.timeUnits=Object.values(nt),this.timeUnitsTranslationMap=at}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[G.required]],fetchMode:[e?e.fetchMode:null,[G.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===mt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([G.required,G.min(2),G.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([G.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([G.required,G.min(1),G.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([G.required,G.min(1),G.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}}e("GetTelemetryFromDatabaseConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeseries-key\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:r,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n tb.rulenode.timeseries-key\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],fetchToData:[!!Y(e?.fetchToData)&&e.fetchToData,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}prepareInputConfig(e){return W(e)&&X(e?.fetchToData)&&(e.fetchToData=!1),e}}e("OriginatorAttributesConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:r,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[G.required]],ignoreNullStrings:[e?e.ignoreNullStrings:null]})}}e("OriginatorFieldsConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n {{ "tb.rulenode.ignore-null-strings" | translate }}\n
{{ "tb.rulenode.ignore-null-strings-hint" | translate }}
\n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:r,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n {{ "tb.rulenode.ignore-null-strings" | translate }}\n
{{ "tb.rulenode.ignore-null-strings-hint" | translate }}
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[G.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[G.required]]})}}e("RelatedAttributesConfigComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:lr,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"component",type:Qt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class sr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[G.required]]})}}e("TenantAttributesConfigComponent",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sr,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class mr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchToMetadata:[e?e.fetchToMetadata:null,[]]})}}e("FetchDeviceCredentialsConfigComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n {{ \'tb.rulenode.fetch-credentials-to-metadata\' | translate }}\n
\n',dependencies:[{kind:"component",type:De.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:r,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n {{ \'tb.rulenode.fetch-credentials-to-metadata\' | translate }}\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class ur{}e("RulenodeCoreConfigEnrichmentModule",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ur.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:ur,declarations:[tr,nr,rr,or,ir,ar,lr,sr,er,mr],imports:[w,v,Xt],exports:[tr,nr,rr,or,ir,ar,lr,sr,er,mr]}),ur.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:l,args:[{declarations:[tr,nr,rr,or,ir,ar,lr,sr,er,mr],imports:[w,v,Xt],exports:[tr,nr,rr,or,ir,ar,lr,sr,er,mr]}]}]});class pr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=yt,this.azureIotHubCredentialsTypeTranslationsMap=xt}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[G.required]],host:[e?e.host:null,[G.required]],port:[e?e.port:null,[G.required,G.min(1),G.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[G.required,G.min(1),G.max(200)]],clientId:[e?e.clientId:null,[G.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[G.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([G.required]);break;case"cert.PEM":t.get("privateKey").setValidators([G.required]),t.get("privateKeyFileName").setValidators([G.required]),t.get("cert").setValidators([G.required]),t.get("certFileName").setValidators([G.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pr,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Te.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Te.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Te.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Te.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Te.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:A.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Ae.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:r,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class dr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=ht,this.ToByteStandartCharsetTypeTranslationMap=Ct}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[G.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[G.required]],retries:[e?e.retries:null,[G.min(0)]],batchSize:[e?e.batchSize:null,[G.min(0)]],linger:[e?e.linger:null,[G.min(0)]],bufferMemory:[e?e.bufferMemory:null,[G.min(0)]],acks:[e?e.acks:null,[G.required]],keySerializer:[e?e.keySerializer:null,[G.required]],valueSerializer:[e?e.valueSerializer:null,[G.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([G.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),dr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dr,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,decorators:[{type:r,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class cr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[G.required]],host:[e?e.host:null,[G.required]],port:[e?e.port:null,[G.required,G.min(1),G.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[G.required,G.min(1),G.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&Z(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{Z(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",cr),cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),cr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cr,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cr,decorators:[{type:r,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class fr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=I,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[G.required]],targets:[e?e.targets:[],[G.required]]})}}e("NotificationConfigComponent",fr),fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fr,deps:[{token:M.Store},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fr,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Ve.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","disabled","notificationTypes"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fr,decorators:[{type:r,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.FormBuilder}]}});class gr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[G.required]],topicName:[e?e.topicName:null,[G.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[G.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[G.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",gr),gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),gr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gr,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ae.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gr,decorators:[{type:r,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class yr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[G.required]],port:[e?e.port:null,[G.required,G.min(1),G.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[G.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[G.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",yr),yr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),yr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yr,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yr,decorators:[{type:r,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class xr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(bt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[G.required]],requestMethod:[e?e.requestMethod:null,[G.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[G.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[G.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[G.required,G.min(1),G.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([G.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([G.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",xr),xr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),xr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xr,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"component",type:Wt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xr,decorators:[{type:r,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class br extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([G.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([G.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([G.required,G.min(1),G.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([G.required,G.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[G.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[G.required,G.min(1),G.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",br),br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:br,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:br,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Re.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:br,decorators:[{type:r,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class hr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[G.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[G.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([G.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",hr),hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),hr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:hr,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hr,decorators:[{type:r,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Cr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(T),this.slackChanelTypesTranslateMap=N}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[G.required]],conversationType:[e?e.conversationType:null,[G.required]],conversation:[e?e.conversation:null,[G.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([G.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Cr),Cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cr,deps:[{token:M.Store},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Cr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Cr,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cr,decorators:[{type:r,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.FormBuilder}]}});class Fr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[G.required]],accessKeyId:[e?e.accessKeyId:null,[G.required]],secretAccessKey:[e?e.secretAccessKey:null,[G.required]],region:[e?e.region:null,[G.required]]})}}e("SnsConfigComponent",Fr),Fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fr,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fr,decorators:[{type:r,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class vr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=dt,this.sqsQueueTypes=Object.keys(dt),this.sqsQueueTypeTranslationsMap=ct}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[G.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[G.required]],delaySeconds:[e?e.delaySeconds:null,[G.min(0),G.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[G.required]],secretAccessKey:[e?e.secretAccessKey:null,[G.required]],region:[e?e.region:null,[G.required]]})}}e("SqsConfigComponent",vr),vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),vr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:vr,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vr,decorators:[{type:r,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Lr{}e("RulenodeCoreConfigExternalModule",Lr),Lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Lr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Lr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Lr,declarations:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr],imports:[w,v,Ne,Xt],exports:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr]}),Lr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Lr,imports:[w,v,Ne,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Lr,decorators:[{type:l,args:[{declarations:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr],imports:[w,v,Ne,Xt],exports:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr]}]}]});class kr extends s{constructor(e,t,r){super(e),this.store=e,this.translate=t,this.fb=r,this.alarmStatusTranslationsMap=q,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(S))this.alarmStatusList.push(S[e]);this.statusFormControl=new P(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(Ce(""),xe((e=>e||"")),be((e=>this.fetchAlarmStatus(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[G.required]]})}displayStatus(e){return e?this.translate.instant(q.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return ke(t.filter((t=>this.translate.instant(q.get(S[t])).toUpperCase().includes(e))))}return ke(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",kr),kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kr,deps:[{token:M.Store},{token:U.TranslateService},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kr,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ve.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kr,decorators:[{type:r,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:A.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:a,args:["alarmStatusInput",{static:!1}]}]}});class Ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",Ir),Ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ir,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ir,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ir,decorators:[{type:r,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[G.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[G.required]:[]],relationType:[e?e.relationType:null,[G.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[G.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[G.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",Tr),Tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tr,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:He.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled","subscriptSizing"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tr,decorators:[{type:r,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=tt,this.perimeterTypes=Object.keys(tt),this.perimeterTypeTranslationMap=rt,this.rangeUnits=Object.keys(ot),this.rangeUnitTranslationMap=it}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[G.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[G.required]],perimeterType:[e?e.perimeterType:null,[G.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([G.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||r!==tt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([G.required,G.min(-90),G.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([G.required,G.min(-180),G.max(180)]),this.geoFilterConfigForm.get("range").setValidators([G.required,G.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([G.required])),t||r!==tt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([G.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",Nr),Nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nr,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nr,decorators:[{type:r,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class qr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[G.required]]})}}e("MessageTypeConfigComponent",qr),qr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),qr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qr,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Yt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qr,decorators:[{type:r,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Sr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[G.required]]})}}e("OriginatorTypeConfigComponent",Sr),Sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sr,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:Ke.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sr,decorators:[{type:r,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Mr extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",n=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Mr),Mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mr,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mr,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mr,decorators:[{type:r,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Ar extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",n=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Ar),Ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ar,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ar,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ar,decorators:[{type:r,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Gr{}e("RuleNodeCoreConfigFilterModule",Gr),Gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Gr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Gr,declarations:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr],imports:[w,v,Xt],exports:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr]}),Gr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gr,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gr,decorators:[{type:l,args:[{declarations:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr],imports:[w,v,Xt],exports:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr]}]}]});class Er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=Ze,this.originatorSources=Object.keys(Ze),this.originatorSourceTranslationMap=et,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[G.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===Ze.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([G.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===Ze.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([G.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([G.required,G.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Er),Er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Er,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Er,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Er,decorators:[{type:r,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Dr extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[G.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",n=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Dr),Dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dr,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Dr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dr,decorators:[{type:r,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Vr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[G.required]],toTemplate:[e?e.toTemplate:null,[G.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[G.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[G.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(Ce([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(G.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",Vr),Vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vr,decorators:[{type:r,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Pr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[G.required]],keys:[e?e.keys:null,[G.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",Pr),Pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pr,decorators:[{type:r,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[G.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[G.required]]})}}e("RenameKeysConfigComponent",Rr),Rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rr,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rr,decorators:[{type:r,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class wr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[G.required]]})}}e("NodeJsonPathConfigComponent",wr),wr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wr,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wr,decorators:[{type:r,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[G.required]],keys:[e?e.keys:null,[G.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",Or),Or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Or,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Or,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Or,decorators:[{type:r,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Hr{}e("RulenodeCoreConfigTransformModule",Hr),Hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Hr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Hr,declarations:[Er,Dr,Vr,Pr,Rr,wr,Or],imports:[w,v,Xt],exports:[Er,Dr,Vr,Pr,Rr,wr,Or]}),Hr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hr,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hr,decorators:[{type:l,args:[{declarations:[Er,Dr,Vr,Pr,Rr,wr,Or],imports:[w,v,Xt],exports:[Er,Dr,Vr,Pr,Rr,wr,Or]}]}]});class Kr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[G.required]]})}}e("RuleChainInputComponent",Kr),Kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:He.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kr,decorators:[{type:r,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Br extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",Br),Br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Br,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Br,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Br,decorators:[{type:r,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ur{}e("RuleNodeCoreConfigFlowModule",Ur),Ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ur,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Ur.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Ur,declarations:[Kr,Br],imports:[w,v,Xt],exports:[Kr,Br]}),Ur.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ur,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ur,decorators:[{type:l,args:[{declarations:[Kr,Br],imports:[w,v,Xt],exports:[Kr,Br]}]}]});class zr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attribute keys","shared-attributes":"Shared attribute keys","server-attributes":"Server attribute keys","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-key":"Time-series key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.","first-message":"First Message","last-message":"Last Message","all-messages":"All Messages","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required.","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body to substitute "Source" and "Target" key names',"shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",zr),zr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zr,deps:[{token:U.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),zr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:zr,declarations:[Be],imports:[w,v],exports:[Zt,Gr,ur,Lr,Hr,Ur,Be]}),zr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zr,imports:[w,v,Zt,Gr,ur,Lr,Hr,Ur]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zr,decorators:[{type:l,args:[{declarations:[Be],imports:[w,v],exports:[Zt,Gr,ur,Lr,Hr,Ur,Be]}]}],ctorParameters:function(){return[{type:U.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@angular/material/radio","@angular/material/slide-toggle","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,r,n,a,o,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,F,v,L,k,I,T,N,q,S,M,A,G,E,D,V,P,R,w,O,H,K,B,U,z,j,_,$,J,Q,Y,W,X,Z,ee,te,re,ne,ae,oe,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,Fe,ve,Le,ke,Ie,Te,Ne,qe,Se,Me,Ae,Ge,Ee,De,Ve,Pe,Re,we,Oe,He,Ke;return{setters:[function(e){t=e,r=e.Component,n=e.Pipe,a=e.ViewChild,o=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.MessageType,C=e.messageTypeNames,F=e,v=e.SharedModule,L=e.AggregationType,k=e.aggregationTranslations,I=e.NotificationType,T=e.SlackChanelType,N=e.SlackChanelTypesTranslateMap,q=e.alarmStatusTranslations,S=e.AlarmStatus},function(e){M=e},function(e){A=e,G=e.Validators,E=e.NgControl,D=e.NG_VALUE_ACCESSOR,V=e.NG_VALIDATORS,P=e.UntypedFormControl},function(e){R=e,w=e.CommonModule},function(e){O=e},function(e){H=e},function(e){K=e},function(e){B=e},function(e){U=e},function(e){z=e},function(e){j=e},function(e){_=e},function(e){$=e},function(e){J=e.getCurrentAuthState,Q=e,Y=e.isDefinedAndNotNull,W=e.isObject,X=e.isUndefinedOrNull,Z=e.isNotEmptyStr},function(e){ee=e},function(e){te=e},function(e){re=e},function(e){ne=e.ENTER,ae=e.COMMA,oe=e.SEMICOLON},function(e){ie=e},function(e){le=e},function(e){se=e},function(e){me=e},function(e){ue=e.coerceBooleanProperty},function(e){pe=e},function(e){de=e},function(e){ce=e},function(e){fe=e},function(e){ge=e},function(e){ye=e.tap,xe=e.map,be=e.mergeMap,he=e.takeUntil,Ce=e.startWith,Fe=e.share},function(e){ve=e},function(e){Le=e},function(e){ke=e.of,Ie=e.Subject},function(e){Te=e},function(e){Ne=e.HomeComponentsModule},function(e){qe=e},function(e){Se=e},function(e){Me=e},function(e){Ae=e},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){Pe=e},function(e){Re=e},function(e){we=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e}],execute:function(){class Be extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Be),Be.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Be,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Be.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Be,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Be,decorators:[{type:r,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ue{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Ue),Ue.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ue,deps:[{token:z.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Ue.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Ue,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ue,decorators:[{type:n,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:z.DomSanitizer}]}});class ze extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[G.required,G.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[G.required,G.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",ze),ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ze,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ze,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ze,decorators:[{type:r,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class je extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",je),je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:je,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:je,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:je,decorators:[{type:r,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class _e extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[G.required]]})}}e("CheckPointConfigComponent",_e),_e.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_e,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_e.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_e,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:$.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_e,decorators:[{type:r,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class $e extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[G.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[G.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[G.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.clearAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=e===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",n=this.clearAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.clearAlarmConfigForm.get(t).setValue(e)}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",$e),$e.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$e,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),$e.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$e,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$e,decorators:[{type:r,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Je extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[ne,ae,oe],this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,r=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([G.required]),this.createAlarmConfigForm.get("severity").setValidators([G.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let n=this.createAlarmConfigForm.get("scriptLang").value;n!==d.TBEL||this.tbelEnabled||(n=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(n,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const a=!1===t||!0===r;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(a&&n===d.JS?[G.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(a&&n===d.TBEL?[G.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",n=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const r=this.createAlarmConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.createAlarmConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Je,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,decorators:[{type:r,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[G.required]],entityType:[e?e.entityType:null,[G.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[G.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[G.required,G.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([G.required,G.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([G.required,G.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",Qe),Qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qe,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qe,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qe,decorators:[{type:r,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[G.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[G.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[G.required,G.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,r=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([G.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&r?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([G.required,G.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ye,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,decorators:[{type:r,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,G.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,G.required]})}}e("DeviceProfileConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:We,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,decorators:[{type:r,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Xe extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[G.required,G.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[G.required,G.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",n=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var Ze;e("GeneratorConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xe,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:$.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,decorators:[{type:r,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(Ze||(Ze={}));const et=new Map([[Ze.CUSTOMER,"tb.rulenode.originator-customer"],[Ze.TENANT,"tb.rulenode.originator-tenant"],[Ze.RELATED,"tb.rulenode.originator-related"],[Ze.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[Ze.ENTITY,"tb.rulenode.originator-entity"]]);var tt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(tt||(tt={}));const rt=new Map([[tt.CIRCLE,"tb.rulenode.perimeter-circle"],[tt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var nt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(nt||(nt={}));const at=new Map([[nt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[nt.SECONDS,"tb.rulenode.time-unit-seconds"],[nt.MINUTES,"tb.rulenode.time-unit-minutes"],[nt.HOURS,"tb.rulenode.time-unit-hours"],[nt.DAYS,"tb.rulenode.time-unit-days"]]);var ot;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(ot||(ot={}));const it=new Map([[ot.METER,"tb.rulenode.range-unit-meter"],[ot.KILOMETER,"tb.rulenode.range-unit-kilometer"],[ot.FOOT,"tb.rulenode.range-unit-foot"],[ot.MILE,"tb.rulenode.range-unit-mile"],[ot.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var lt;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(lt||(lt={}));const st=new Map([[lt.ID,"tb.rulenode.entity-details-id"],[lt.TITLE,"tb.rulenode.entity-details-title"],[lt.COUNTRY,"tb.rulenode.entity-details-country"],[lt.STATE,"tb.rulenode.entity-details-state"],[lt.CITY,"tb.rulenode.entity-details-city"],[lt.ZIP,"tb.rulenode.entity-details-zip"],[lt.ADDRESS,"tb.rulenode.entity-details-address"],[lt.ADDRESS2,"tb.rulenode.entity-details-address2"],[lt.PHONE,"tb.rulenode.entity-details-phone"],[lt.EMAIL,"tb.rulenode.entity-details-email"],[lt.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var mt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(mt||(mt={}));const ut=new Map([[mt.FIRST,"tb.rulenode.first-message"],[mt.LAST,"tb.rulenode.last-message"],[mt.ALL,"tb.rulenode.all-messages"]]);var pt,dt;!function(e){e.ASC="ASC",e.DESC="DESC"}(pt||(pt={})),function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(dt||(dt={}));const ct=new Map([[dt.STANDARD,"tb.rulenode.sqs-queue-standard"],[dt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),ft=["anonymous","basic","cert.PEM"],gt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),yt=["sas","cert.PEM"],xt=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var bt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(bt||(bt={}));const ht=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Ct=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Ft;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Ft||(Ft={}));const vt=new Map([[Ft.CUSTOM,{value:Ft.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Ft.ADD,{value:Ft.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Ft.SUB,{value:Ft.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Ft.MULT,{value:Ft.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Ft.DIV,{value:Ft.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Ft.SIN,{value:Ft.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Ft.SINH,{value:Ft.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Ft.COS,{value:Ft.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Ft.COSH,{value:Ft.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Ft.TAN,{value:Ft.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Ft.TANH,{value:Ft.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Ft.ACOS,{value:Ft.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Ft.ASIN,{value:Ft.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Ft.ATAN,{value:Ft.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Ft.ATAN2,{value:Ft.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Ft.EXP,{value:Ft.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Ft.EXPM1,{value:Ft.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Ft.SQRT,{value:Ft.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Ft.CBRT,{value:Ft.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Ft.GET_EXP,{value:Ft.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Ft.HYPOT,{value:Ft.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Ft.LOG,{value:Ft.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Ft.LOG10,{value:Ft.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Ft.LOG1P,{value:Ft.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Ft.CEIL,{value:Ft.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Ft.FLOOR,{value:Ft.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Ft.FLOOR_DIV,{value:Ft.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Ft.FLOOR_MOD,{value:Ft.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Ft.ABS,{value:Ft.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Ft.MIN,{value:Ft.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Ft.MAX,{value:Ft.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Ft.POW,{value:Ft.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Ft.SIGNUM,{value:Ft.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Ft.RAD,{value:Ft.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Ft.DEG,{value:Ft.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Lt,kt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Lt||(Lt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(kt||(kt={}));const It=new Map([[Lt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Lt.TIME_SERIES,"tb.rulenode.time-series-type"],[Lt.CONSTANT,"tb.rulenode.constant-type"],[Lt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Lt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),Tt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Nt,qt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Nt||(Nt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(qt||(qt={}));const St=new Map([[Nt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Nt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Nt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Mt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=tt,this.perimeterTypes=Object.keys(tt),this.perimeterTypeTranslationMap=rt,this.rangeUnits=Object.keys(ot),this.rangeUnitTranslationMap=it,this.timeUnits=Object.keys(nt),this.timeUnitsTranslationMap=at}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[G.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[G.required]],perimeterType:[e?e.perimeterType:null,[G.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[G.required,G.min(1),G.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[G.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[G.required,G.min(1),G.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[G.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([G.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||r!==tt.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([G.required,G.min(-90),G.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([G.required,G.min(-180),G.max(180)]),this.geoActionConfigForm.get("range").setValidators([G.required,G.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([G.required])),t||r!==tt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([G.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Mt),Mt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mt,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mt,decorators:[{type:r,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class At extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",n=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",At),At.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:At,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),At.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:At,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:At,decorators:[{type:r,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Gt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[G.required,G.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[G.required]]})}}e("MsgCountConfigComponent",Gt),Gt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Gt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gt,decorators:[{type:r,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Et extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[G.required,G.min(1),G.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([G.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([G.required,G.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Et),Et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Et,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Et,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Et,decorators:[{type:r,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Dt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]]})}}e("PushToCloudConfigComponent",Dt),Dt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dt,decorators:[{type:r,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Vt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]]})}}e("PushToEdgeConfigComponent",Vt),Vt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vt,decorators:[{type:r,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Pt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",Pt),Pt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pt,decorators:[{type:r,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[G.required,G.min(0)]]})}}e("RpcRequestConfigComponent",Rt),Rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rt,decorators:[{type:r,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class wt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.injector=r,this.fb=n,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(E),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const r of Object.keys(e))Object.prototype.hasOwnProperty.call(e,r)&&t.push(this.fb.group({key:[r,[G.required]],value:[e[r],[G.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[G.required]],value:["",[G.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",wt),wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wt,deps:[{token:M.Store},{token:U.TranslateService},{token:t.Injector},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wt,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:D,useExisting:o((()=>wt)),multi:!0},{provide:V,useExisting:o((()=>wt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:de.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ce.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wt,decorators:[{type:r,args:[{selector:"tb-kv-map-config",providers:[{provide:D,useExisting:o((()=>wt)),multi:!0},{provide:V,useExisting:o((()=>wt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#0000008a;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:t.Injector},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Ot extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[G.required,G.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[G.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Ot),Ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ot,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ot,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ot,decorators:[{type:r,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[G.required,G.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ht,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,decorators:[{type:r,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Kt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[G.required,G.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[G.required,G.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kt,decorators:[{type:r,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[G.required]],keys:[e?e.keys:null,[G.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bt,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bt,decorators:[{type:r,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:a,args:["attributeChipList"]}]}});class Ut extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.injector=r,this.fb=n,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=vt,this.ArgumentType=Lt,this.attributeScopeMap=St,this.argumentTypeResultMap=It,this.arguments=Object.values(Lt),this.attributeScope=Object.values(Nt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(E),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),r=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,r),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,r)=>{t.push(this.createArgumentControl(e,r))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),r=this.createArgumentControl(null,t.length);t.push(r,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Ft.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([G.minLength(this.minArgs),G.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(r),r.get("attributeScope").updateValueAndValidity({emitEvent:!1}),r.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),r}updateArgumentControlValidators(e){const t=e.get("type").value;t===Lt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Lt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Tt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,deps:[{token:M.Store},{token:U.TranslateService},{token:t.Injector},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ut,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:D,useExisting:o((()=>Ut)),multi:!0},{provide:V,useExisting:o((()=>Ut)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:de.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:fe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:fe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:ge.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:ge.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:ge.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ce.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,decorators:[{type:r,args:[{selector:"tb-arguments-map-config",providers:[{provide:D,useExisting:o((()=>Ut)),multi:!0},{provide:V,useExisting:o((()=>Ut)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:t.Injector},{type:A.FormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class zt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.injector=r,this.fb=n,this.searchText="",this.dirty=!1,this.mathOperation=[...vt.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(ye((e=>{let t;t="string"==typeof e&&Ft[e]?Ft[e]:null,this.updateView(t)})),xe((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=vt.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:M.Store},{token:U.TranslateService},{token:t.Injector},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:D,useExisting:o((()=>zt)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:r,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:D,useExisting:o((()=>zt)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:t.Injector},{type:A.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:a,args:["operationInput",{static:!0}]}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Ft,this.ArgumentTypeResult=kt,this.argumentTypeResultMap=It,this.attributeScopeMap=St,this.argumentsResult=Object.values(kt),this.attributeScopeResult=Object.values(qt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[G.required]],arguments:[e?e.arguments:null,[G.required]],customFunction:[e?e.customFunction:"",[G.required]],result:this.fb.group({type:[e?e.result.type:null,[G.required]],attributeScope:[e?e.result.attributeScope:null,[G.required]],key:[e?e.result.key:"",[G.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,r=this.mathFunctionConfigForm.get("result.type").value;t===Ft.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),r===kt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:A.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ut,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:zt,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:r,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class _t{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[G.required,G.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(ye((e=>{this.updateView(e)})),xe((e=>e||"")),be((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,ke(this.messageTypes).pipe(xe((r=>r.filter((r=>t?!!e&&r===e:!e||r.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_t,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:D,useExisting:o((()=>_t)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,decorators:[{type:r,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:D,useExisting:o((()=>_t)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{messageTypeInput:[{type:a,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Ie,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=mt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=ut}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[Y(e?.interval)?e.interval:null,[G.required,G.min(1)]],strategy:[Y(e?.strategy)?e.strategy:null,[G.required]],outMsgType:[Y(e?.outMsgType)?e.outMsgType:null,[G.required]],queueName:[Y(e?.queueName)?e.queueName:null,[G.required]],maxPendingMsgs:[Y(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[G.required,G.min(1),G.max(1e3)]],maxRetries:[Y(e?.maxRetries)?e.maxRetries:null,[G.required,G.min(0),G.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(he(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:$.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Te.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Te.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Te.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:_t,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:r,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Jt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[G.required]],maxLevel:[null,[]],relationType:[null],deviceTypes:[null,[G.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:D,useExisting:o((()=>Jt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:qe.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","disabled","entityType"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled","subscriptSizing"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:r,args:[{selector:"tb-device-relations-query-config",providers:[{provide:D,useExisting:o((()=>Jt)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-type
\n \n \n
device.device-types
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class Qt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[G.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:D,useExisting:o((()=>Qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Me.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:r,args:[{selector:"tb-relations-query-config",providers:[{provide:D,useExisting:o((()=>Qt)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class Yt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t,r,n){super(e),this.store=e,this.translate=t,this.truncate=r,this.fb=n,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[ne,ae,oe],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(h))this.messageTypesList.push({name:C.get(h[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Ce(""),xe((e=>e||"")),be((e=>this.fetchMessageTypes(e))),Fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return ke(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return ke(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const r=e.trim(),n=this.messageTypesList.find((e=>e.name===r));t=n?{name:n.name,value:n.value}:{name:r,value:r},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:M.Store},{token:U.TranslateService},{token:F.TruncatePipe},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:D,useExisting:o((()=>Yt)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ve.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:r,args:[{selector:"tb-message-types-config",providers:[{provide:D,useExisting:o((()=>Yt)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) | async }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:F.TruncatePipe},{type:A.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:a,args:["chipList",{static:!1}]}],matAutocomplete:[{type:a,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:a,args:["messageTypeInput",{static:!1}]}]}});class Wt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ue(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=ft,this.credentialsTypeTranslationsMap=gt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[G.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const r=e[t];if(!r.firstChange&&r.currentValue!==r.previousValue&&r.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){Y(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([G.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[G.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(G.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return r=>{t||(t=[Object.keys(r.controls)]);return r?.controls&&t.some((t=>t.every((t=>!e(r.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:M.Store},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:D,useExisting:o((()=>Wt)),multi:!0},{provide:V,useExisting:o((()=>Wt)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Te.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Te.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Te.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Te.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ae.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:r,args:[{selector:"tb-credentials-config",providers:[{provide:D,useExisting:o((()=>Wt)),multi:!0},{provide:V,useExisting:o((()=>Wt)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class Xt{}e("RulenodeCoreConfigCommonModule",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Xt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Xt,declarations:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t],imports:[w,v,Ne],exports:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t]}),Xt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,imports:[w,v,Ne]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:l,args:[{declarations:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t],imports:[w,v,Ne],exports:[wt,Jt,Qt,Yt,Wt,Ue,Ut,zt,_t]}]}]});class Zt{}e("RuleNodeCoreConfigActionModule",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Zt.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Zt,declarations:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t],imports:[w,v,Ne,Xt],exports:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t]}),Zt.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,imports:[w,v,Ne,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:l,args:[{declarations:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t],imports:[w,v,Ne,Xt],exports:[Bt,je,Ht,Rt,At,ze,$e,Je,Qe,Et,Ye,Xe,Mt,Gt,Pt,Ot,Kt,_e,We,Vt,Dt,jt,$t]}]}]});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e?e.inputValueKey:null,[G.required]],outputValueKey:[e?e.outputValueKey:null,[G.required]],useCache:[e?e.useCache:null,[]],addPeriodBetweenMsgs:[!!e&&e.addPeriodBetweenMsgs,[]],periodValueKey:[e?e.periodValueKey:null,[]],round:[e?e.round:null,[G.min(0),G.max(15)]],tellFailureIfDeltaIsNegative:[e?e.tellFailureIfDeltaIsNegative:null,[]]})}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([G.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:er,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:r,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:'
\n
\n \n tb.rulenode.input-value-key\n \n \n {{ \'tb.rulenode.input-value-key-required\' | translate }}\n \n \n \n tb.rulenode.output-value-key\n \n \n {{ \'tb.rulenode.output-value-key-required\' | translate }}\n \n \n \n tb.rulenode.round\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n {{ \'tb.rulenode.round-range\' | translate }}\n \n \n
\n \n {{ \'tb.rulenode.use-cache\' | translate }}\n \n \n {{ \'tb.rulenode.tell-failure-if-delta-is-negative\' | translate }}\n \n \n {{ \'tb.rulenode.add-period-between-msgs\' | translate }}\n \n \n tb.rulenode.period-value-key\n \n \n {{ \'tb.rulenode.period-value-key-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.customerAttributesConfigForm}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[G.required]]})}}e("CustomerAttributesConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e?e.deviceRelationsQuery:null,[G.required]],tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],fetchToData:[!!e&&e.fetchToData,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const r=this.deviceAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.deviceAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deviceAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deviceAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}prepareInputConfig(e){return W(e)&&X(e?.fetchToData)&&(e.fetchToData=!1),e}}e("DeviceAttributesConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Jt,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class nr extends s{constructor(e,t,r){super(e),this.store=e,this.translate=t,this.fb=r,this.entityDetailsTranslationsMap=st,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(lt))this.entityDetailsList.push(lt[e]);this.detailsFormControl=new P(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(Ce(""),xe((e=>e||"")),be((e=>this.fetchEntityDetails(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],e}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e?e.detailsList:null,[G.required]],addToMetadata:[!!e&&e.addToMetadata,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(st.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return ke(this.entityDetailsList.filter((t=>this.translate.instant(st.get(lt[t])).toUpperCase().includes(e))))}return ke(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:M.Store},{token:U.TranslateService},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ve.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n tb.rulenode.entity-details\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-entity-details-matching\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n {{ \'tb.rulenode.add-to-metadata\' | translate }}\n \n
tb.rulenode.add-to-metadata-hint
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:A.UntypedFormBuilder}]},propDecorators:{detailsInput:[{type:a,args:["detailsInput",{static:!1}]}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe],this.aggregationTypes=L,this.aggregations=Object.keys(L),this.aggregationTypesTranslations=k,this.fetchMode=mt,this.fetchModes=Object.keys(mt),this.samplingOrders=Object.keys(pt),this.timeUnits=Object.values(nt),this.timeUnitsTranslationMap=at}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],aggregation:[e?e.aggregation:null,[G.required]],fetchMode:[e?e.fetchMode:null,[G.required]],orderBy:[e?e.orderBy:null,[]],limit:[e?e.limit:null,[]],useMetadataIntervalPatterns:[!!e&&e.useMetadataIntervalPatterns,[]],startInterval:[e?e.startInterval:null,[]],startIntervalTimeUnit:[e?e.startIntervalTimeUnit:null,[]],endInterval:[e?e.endInterval:null,[]],endIntervalTimeUnit:[e?e.endIntervalTimeUnit:null,[]],startIntervalPattern:[e?e.startIntervalPattern:null,[]],endIntervalPattern:[e?e.endIntervalPattern:null,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,r=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===mt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([G.required,G.min(2),G.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),r?(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([G.required])):(this.getTelemetryFromDatabaseConfigForm.get("startInterval").setValidators([G.required,G.min(1),G.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("endInterval").setValidators([G.required,G.min(1),G.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").setValidators([G.required]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const r=this.getTelemetryFromDatabaseConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}}e("GetTelemetryFromDatabaseConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeseries-key\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:r,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n tb.rulenode.timeseries-key\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.fetch-mode\n \n \n {{ mode }}\n \n \n tb.rulenode.fetch-mode-hint\n \n
\n \n aggregation.function\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n \n tb.rulenode.order-by\n \n \n {{ order }}\n \n \n tb.rulenode.order-by-hint\n \n \n tb.rulenode.limit\n \n tb.rulenode.limit-hint\n \n
\n \n {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-interval-patterns-hint
\n
\n
\n \n tb.rulenode.start-interval\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.start-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.end-interval\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.end-interval-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n \n tb.rulenode.start-interval-pattern\n \n \n {{ \'tb.rulenode.start-interval-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.end-interval-pattern\n \n \n {{ \'tb.rulenode.end-interval-pattern-required\' | translate }}\n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[!!e&&e.tellFailureIfAbsent,[]],fetchToData:[!!Y(e?.fetchToData)&&e.fetchToData,[]],clientAttributeNames:[e?e.clientAttributeNames:null,[]],sharedAttributeNames:[e?e.sharedAttributeNames:null,[]],serverAttributeNames:[e?e.serverAttributeNames:null,[]],latestTsKeyNames:[e?e.latestTsKeyNames:null,[]],getLatestValueWithTs:[!!e&&e.getLatestValueWithTs,[]]})}removeKey(e,t){const r=this.originatorAttributesConfigForm.get(t).value,n=r.indexOf(e);n>=0&&(r.splice(n,1),this.originatorAttributesConfigForm.get(t).setValue(r,{emitEvent:!0}))}addKey(e,t){const r=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.originatorAttributesConfigForm.get(t).value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.originatorAttributesConfigForm.get(t).setValue(e,{emitEvent:!0}))}r&&(r.value="")}prepareInputConfig(e){return W(e)&&X(e?.fetchToData)&&(e.fetchToData=!1),e}}e("OriginatorAttributesConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:r,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n {{ \'tb.rulenode.tell-failure-if-absent\' | translate }}\n \n
tb.rulenode.tell-failure-if-absent-hint
\n
{{ \'tb.rulenode.fetch-into\' | translate }}
\n \n \n {{ \'tb.rulenode.data\' | translate }}\n \n \n {{ \'tb.rulenode.metadata\' | translate }}\n \n \n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-timeseries\n \n \n {{key}}\n close\n \n \n \n \n \n \n {{ \'tb.rulenode.get-latest-value-with-ts\' | translate }}\n \n
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.originatorFieldsConfigForm}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({fieldsMapping:[e?e.fieldsMapping:null,[G.required]],ignoreNullStrings:[e?e.ignoreNullStrings:null]})}}e("OriginatorFieldsConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n {{ "tb.rulenode.ignore-null-strings" | translate }}\n
{{ "tb.rulenode.ignore-null-strings-hint" | translate }}
\n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:r,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n {{ "tb.rulenode.ignore-null-strings" | translate }}\n
{{ "tb.rulenode.ignore-null-strings-hint" | translate }}
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.relatedAttributesConfigForm}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e?e.relationsQuery:null,[G.required]],telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[G.required]]})}}e("RelatedAttributesConfigComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:lr,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"component",type:Qt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class sr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.tenantAttributesConfigForm}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({telemetry:[!!e&&e.telemetry,[]],attrMapping:[e?e.attrMapping:null,[G.required]]})}}e("TenantAttributesConfigComponent",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sr,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:r,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class mr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchToMetadata:[e?e.fetchToMetadata:null,[]]})}}e("FetchDeviceCredentialsConfigComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n {{ \'tb.rulenode.fetch-credentials-to-metadata\' | translate }}\n
\n',dependencies:[{kind:"component",type:De.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:r,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n {{ \'tb.rulenode.fetch-credentials-to-metadata\' | translate }}\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class ur{}e("RulenodeCoreConfigEnrichmentModule",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ur.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:ur,declarations:[tr,nr,rr,or,ir,ar,lr,sr,er,mr],imports:[w,v,Xt],exports:[tr,nr,rr,or,ir,ar,lr,sr,er,mr]}),ur.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:l,args:[{declarations:[tr,nr,rr,or,ir,ar,lr,sr,er,mr],imports:[w,v,Xt],exports:[tr,nr,rr,or,ir,ar,lr,sr,er,mr]}]}]});class pr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=yt,this.azureIotHubCredentialsTypeTranslationsMap=xt}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[G.required]],host:[e?e.host:null,[G.required]],port:[e?e.port:null,[G.required,G.min(1),G.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[G.required,G.min(1),G.max(200)]],clientId:[e?e.clientId:null,[G.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[G.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),r=t.get("type").value;switch(e&&t.reset({type:r},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),r){case"sas":t.get("sasKey").setValidators([G.required]);break;case"cert.PEM":t.get("privateKey").setValidators([G.required]),t.get("privateKeyFileName").setValidators([G.required]),t.get("cert").setValidators([G.required]),t.get("certFileName").setValidators([G.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pr,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Te.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Te.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Te.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Te.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Te.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:A.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Ae.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:r,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class dr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=ht,this.ToByteStandartCharsetTypeTranslationMap=Ct}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[G.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[G.required]],retries:[e?e.retries:null,[G.min(0)]],batchSize:[e?e.batchSize:null,[G.min(0)]],linger:[e?e.linger:null,[G.min(0)]],bufferMemory:[e?e.bufferMemory:null,[G.min(0)]],acks:[e?e.acks:null,[G.required]],keySerializer:[e?e.keySerializer:null,[G.required]],valueSerializer:[e?e.valueSerializer:null,[G.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([G.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),dr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dr,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,decorators:[{type:r,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class cr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[G.required]],host:[e?e.host:null,[G.required]],port:[e?e.port:null,[G.required,G.min(1),G.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[G.required,G.min(1),G.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&Z(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{Z(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",cr),cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),cr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cr,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cr,decorators:[{type:r,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class fr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=I,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[G.required]],targets:[e?e.targets:[],[G.required]]})}}e("NotificationConfigComponent",fr),fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fr,deps:[{token:M.Store},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fr,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Ve.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","disabled","notificationTypes"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fr,decorators:[{type:r,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.FormBuilder}]}});class gr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[G.required]],topicName:[e?e.topicName:null,[G.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[G.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[G.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",gr),gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),gr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gr,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ae.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gr,decorators:[{type:r,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class yr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[G.required]],port:[e?e.port:null,[G.required,G.min(1),G.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[G.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[G.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",yr),yr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),yr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yr,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yr,decorators:[{type:r,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class xr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(bt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[G.required]],requestMethod:[e?e.requestMethod:null,[G.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[G.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,r=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,n=this.restApiCallConfigForm.get("enableProxy").value,a=this.restApiCallConfigForm.get("useSystemProxyProperties").value;n&&!a?(this.restApiCallConfigForm.get("proxyHost").setValidators(n?[G.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(n?[G.required,G.min(1),G.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([G.min(0)])),r?this.restApiCallConfigForm.get("maxQueueSize").setValidators([G.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",xr),xr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),xr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xr,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"component",type:Wt,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xr,decorators:[{type:r,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class br extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,r=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([G.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([G.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([G.required,G.min(1),G.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([G.required,G.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(r?[G.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(r?[G.required,G.min(1),G.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",br),br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:br,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:br,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Re.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:K.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ge.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:br,decorators:[{type:r,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class hr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[G.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[G.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([G.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",hr),hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),hr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:hr,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hr,decorators:[{type:r,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Cr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(T),this.slackChanelTypesTranslateMap=N}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[G.required]],conversationType:[e?e.conversationType:null,[G.required]],conversation:[e?e.conversation:null,[G.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([G.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Cr),Cr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cr,deps:[{token:M.Store},{token:A.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Cr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Cr,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cr,decorators:[{type:r,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.FormBuilder}]}});class Fr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[G.required]],accessKeyId:[e?e.accessKeyId:null,[G.required]],secretAccessKey:[e?e.secretAccessKey:null,[G.required]],region:[e?e.region:null,[G.required]]})}}e("SnsConfigComponent",Fr),Fr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fr,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fr,decorators:[{type:r,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class vr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=dt,this.sqsQueueTypes=Object.keys(dt),this.sqsQueueTypeTranslationsMap=ct}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[G.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[G.required]],delaySeconds:[e?e.delaySeconds:null,[G.min(0),G.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[G.required]],secretAccessKey:[e?e.secretAccessKey:null,[G.required]],region:[e?e.region:null,[G.required]]})}}e("SqsConfigComponent",vr),vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),vr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:vr,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vr,decorators:[{type:r,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Lr{}e("RulenodeCoreConfigExternalModule",Lr),Lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Lr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Lr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Lr,declarations:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr],imports:[w,v,Ne,Xt],exports:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr]}),Lr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Lr,imports:[w,v,Ne,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Lr,decorators:[{type:l,args:[{declarations:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr],imports:[w,v,Ne,Xt],exports:[Fr,vr,gr,dr,cr,fr,yr,xr,br,pr,hr,Cr]}]}]});class kr extends s{constructor(e,t,r){super(e),this.store=e,this.translate=t,this.fb=r,this.alarmStatusTranslationsMap=q,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(S))this.alarmStatusList.push(S[e]);this.statusFormControl=new P(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(Ce(""),xe((e=>e||"")),be((e=>this.fetchAlarmStatus(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[G.required]]})}displayStatus(e){return e?this.translate.instant(q.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return ke(t.filter((t=>this.translate.instant(q.get(S[t])).toUpperCase().includes(e))))}return ke(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const r=t.indexOf(e);r>=0&&(t.splice(r,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",kr),kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kr,deps:[{token:M.Store},{token:U.TranslateService},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kr,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ve.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ve.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ve.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Le.HighlightPipe,name:"highlight"},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kr,decorators:[{type:r,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:U.TranslateService},{type:A.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:a,args:["alarmStatusInput",{static:!1}]}]}});class Ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",Ir),Ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ir,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ir,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ir,decorators:[{type:r,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[G.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[G.required]:[]],relationType:[e?e.relationType:null,[G.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[G.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[G.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",Tr),Tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tr,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:He.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Se.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["required","disabled","subscriptSizing"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tr,decorators:[{type:r,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=tt,this.perimeterTypes=Object.keys(tt),this.perimeterTypeTranslationMap=rt,this.rangeUnits=Object.keys(ot),this.rangeUnitTranslationMap=it}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[G.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[G.required]],perimeterType:[e?e.perimeterType:null,[G.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,r=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([G.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||r!==tt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([G.required,G.min(-90),G.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([G.required,G.min(-180),G.max(180)]),this.geoFilterConfigForm.get("range").setValidators([G.required,G.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([G.required])),t||r!==tt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([G.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",Nr),Nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nr,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:O.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:A.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nr,decorators:[{type:r,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class qr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[G.required]]})}}e("MessageTypeConfigComponent",qr),qr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),qr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qr,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Yt,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qr,decorators:[{type:r,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Sr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[G.required]]})}}e("OriginatorTypeConfigComponent",Sr),Sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sr,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:Ke.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sr,decorators:[{type:r,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Mr extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",n=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Mr),Mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mr,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mr,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mr,decorators:[{type:r,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Ar extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",n=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Ar),Ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ar,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ar,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ar,decorators:[{type:r,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Gr{}e("RuleNodeCoreConfigFilterModule",Gr),Gr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Gr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Gr,declarations:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr],imports:[w,v,Xt],exports:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr]}),Gr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gr,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gr,decorators:[{type:l,args:[{declarations:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr],imports:[w,v,Xt],exports:[Ir,Tr,Nr,qr,Sr,Mr,Ar,kr]}]}]});class Er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=Ze,this.originatorSources=Object.keys(Ze),this.originatorSourceTranslationMap=et,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[G.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===Ze.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([G.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===Ze.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([G.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([G.required,G.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Er),Er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Er,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Er,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:se.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:B.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Er,decorators:[{type:r,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Dr extends s{constructor(e,t,r,n){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=r,this.translate=n,this.tbelEnabled=J(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[G.required]],jsScript:[e?e.jsScript:null,[G.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[G.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[G.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",r=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",n=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(n,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,r,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Dr),Dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dr,deps:[{token:M.Store},{token:A.UntypedFormBuilder},{token:Q.NodeScriptTestService},{token:U.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Dr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ee.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:te.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dr,decorators:[{type:r,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder},{type:Q.NodeScriptTestService},{type:U.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Vr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[G.required]],toTemplate:[e?e.toTemplate:null,[G.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[G.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[G.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(Ce([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(G.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",Vr),Vr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:j.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:_.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:U.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vr,decorators:[{type:r,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Pr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[G.required]],keys:[e?e.keys:null,[G.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",Pr),Pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pr,decorators:[{type:r,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[G.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[G.required]]})}}e("RenameKeysConfigComponent",Rr),Rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rr,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:wt,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rr,decorators:[{type:r,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class wr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[G.required]]})}}e("NodeJsonPathConfigComponent",wr),wr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wr,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatLabel,selector:"mat-label"},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wr,decorators:[{type:r,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ne,ae,oe]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[G.required]],keys:[e?e.keys:null,[G.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,r=t.indexOf(e);r>=0&&(t.splice(r,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",Or),Or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Or,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Or,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ie.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:H.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:K.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:K.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:K.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ee.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ee.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:le.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:le.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:le.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:le.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:B.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"},{kind:"pipe",type:Ue,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Or,decorators:[{type:r,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Hr{}e("RulenodeCoreConfigTransformModule",Hr),Hr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Hr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Hr,declarations:[Er,Dr,Vr,Pr,Rr,wr,Or],imports:[w,v,Xt],exports:[Er,Dr,Vr,Pr,Rr,wr,Or]}),Hr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hr,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hr,decorators:[{type:l,args:[{declarations:[Er,Dr,Vr,Pr,Rr,wr,Or],imports:[w,v,Xt],exports:[Er,Dr,Vr,Pr,Rr,wr,Or]}]}]});class Kr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[G.required]]})}}e("RuleChainInputComponent",Kr),Kr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kr,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:He.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:A.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kr,decorators:[{type:r,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Br extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",Br),Br.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Br,deps:[{token:M.Store},{token:A.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Br.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Br,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:B.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:A.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:A.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:U.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Br,decorators:[{type:r,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:M.Store},{type:A.UntypedFormBuilder}]}});class Ur{}e("RuleNodeCoreConfigFlowModule",Ur),Ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ur,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Ur.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Ur,declarations:[Kr,Br],imports:[w,v,Xt],exports:[Kr,Br]}),Ur.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ur,imports:[w,v,Xt]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ur,decorators:[{type:l,args:[{declarations:[Kr,Br],imports:[w,v,Xt],exports:[Kr,Br]}]}]});class zr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","fetch-mode-hint":"If selected fetch mode 'ALL' you able to choose telemetry sampling order.","order-by":"Order by","order-by-hint":"Select to choose telemetry sampling order.",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'FIRST' or 'LAST'.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attribute keys","shared-attributes":"Shared attribute keys","server-attributes":"Server attribute keys","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-key":"Time-series key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.","first-message":"First Message","last-message":"Last Message","all-messages":"All Messages","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required.","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use interval patterns","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","add-to-metadata":"Add selected details to message metadata","add-to-metadata-hint":"If selected, adds the selected details keys to the message metadata instead of message data.","entity-details-list-empty":"No entity details selected.","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required.","output-value-key":"Output value key","output-value-key-required":"Output value key is required.",round:"Decimals","round-range":"Decimals should be in a range from 0 to 15.","use-cache":"Use cache for latest value","tell-failure-if-delta-is-negative":"Tell Failure if delta is negative","add-period-between-msgs":"Add period between messages","period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body to substitute "Source" and "Target" key names',"shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",zr),zr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zr,deps:[{token:U.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),zr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:zr,declarations:[Be],imports:[w,v],exports:[Zt,Gr,ur,Lr,Hr,Ur,Be]}),zr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zr,imports:[w,v,Zt,Gr,ur,Lr,Hr,Ur]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zr,decorators:[{type:l,args:[{declarations:[Be],imports:[w,v],exports:[Zt,Gr,ur,Lr,Hr,Ur,Be]}]}],ctorParameters:function(){return[{type:U.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map From 23d204e4d693e507c96b7c4d6e64b1b9bc60b64d Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 8 Jun 2023 11:53:00 +0200 Subject: [PATCH 094/421] added new default root cert for azure iot --- .../azure/BaltimoreCyberTrustRoot.crt.pem | 22 ------------- .../certs/azure/DigiCertGlobalRootG2.crt.pem | 22 +++++++++++++ .../common/util/AzureIotHubUtil.java | 31 +++++++++++++++---- 3 files changed, 47 insertions(+), 28 deletions(-) delete mode 100644 application/src/main/data/certs/azure/BaltimoreCyberTrustRoot.crt.pem create mode 100644 application/src/main/data/certs/azure/DigiCertGlobalRootG2.crt.pem diff --git a/application/src/main/data/certs/azure/BaltimoreCyberTrustRoot.crt.pem b/application/src/main/data/certs/azure/BaltimoreCyberTrustRoot.crt.pem deleted file mode 100644 index 2bd16ebd47..0000000000 --- a/application/src/main/data/certs/azure/BaltimoreCyberTrustRoot.crt.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- - diff --git a/application/src/main/data/certs/azure/DigiCertGlobalRootG2.crt.pem b/application/src/main/data/certs/azure/DigiCertGlobalRootG2.crt.pem new file mode 100644 index 0000000000..798e002751 --- /dev/null +++ b/application/src/main/data/certs/azure/DigiCertGlobalRootG2.crt.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- diff --git a/common/util/src/main/java/org/thingsboard/common/util/AzureIotHubUtil.java b/common/util/src/main/java/org/thingsboard/common/util/AzureIotHubUtil.java index ca9cc2660f..5beed77baf 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/AzureIotHubUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/AzureIotHubUtil.java @@ -22,6 +22,7 @@ import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -36,7 +37,7 @@ public final class AzureIotHubUtil { private static final String DATA_DIR = "data"; private static final String CERTS_DIR = "certs"; private static final String AZURE_DIR = "azure"; - private static final String FILE_NAME = "BaltimoreCyberTrustRoot.crt.pem"; + private static final String FILE_NAME = "DigiCertGlobalRootG2.crt.pem"; private static final Path FULL_FILE_PATH; @@ -88,12 +89,30 @@ public final class AzureIotHubUtil { } public static String getDefaultCaCert() { - try { - return new String(Files.readAllBytes(FULL_FILE_PATH)); - } catch (IOException e) { - log.error("Failed to load Default CaCert file!!! [{}]", FULL_FILE_PATH.toString()); - throw new RuntimeException("Failed to load Default CaCert file!!!"); + byte[] fileBytes; + if (Files.exists(FULL_FILE_PATH)) { + try { + fileBytes = Files.readAllBytes(FULL_FILE_PATH); + } catch (IOException e) { + log.error("Failed to load Default CaCert file!!! [{}]", FULL_FILE_PATH, e); + throw new RuntimeException("Failed to load Default CaCert file!!!"); + } + } else { + Path azureDirectory = FULL_FILE_PATH.getParent(); + try (DirectoryStream stream = Files.newDirectoryStream(azureDirectory)) { + if (stream.iterator().hasNext()) { + Path firstFile = stream.iterator().next(); + fileBytes = Files.readAllBytes(firstFile); + } else { + log.error("Default CaCert file not found in the directory [{}]!!!", azureDirectory); + throw new RuntimeException("Default CaCert file not found in the directory!!!"); + } + } catch (IOException e) { + log.error("Failed to load Default CaCert file from the directory [{}]!!!", azureDirectory, e); + throw new RuntimeException("Failed to load Default CaCert file from the directory!!!"); + } } + return new String(fileBytes); } } From 6be3cda55ef23a5aed45cc2f8bad9d53a53861b0 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 8 Jun 2023 13:25:00 +0300 Subject: [PATCH 095/421] math node arguments/result key fields templatization --- .../rule/engine/math/TbMathArgumentValue.java | 20 +++--- .../rule/engine/math/TbMathNode.java | 46 +++++++------- .../engine/math/TbMathArgumentValueTest.java | 18 +++--- .../rule/engine/math/TbMathNodeTest.java | 61 +++++++++++++++---- 4 files changed, 92 insertions(+), 53 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentValue.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentValue.java index 9985446dd3..f740aebf4a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentValue.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathArgumentValue.java @@ -43,19 +43,18 @@ public class TbMathArgumentValue { throw new RuntimeException(error); } - public static TbMathArgumentValue fromMessageBody(TbMathArgument arg, Optional jsonNodeOpt) { - String key = arg.getKey(); + public static TbMathArgumentValue fromMessageBody(TbMathArgument arg, String argKey, Optional jsonNodeOpt) { Double defaultValue = arg.getDefaultValue(); if (jsonNodeOpt.isEmpty()) { return defaultOrThrow(defaultValue, "Message body is empty!"); } var json = jsonNodeOpt.get(); - if (!json.has(key)) { - return defaultOrThrow(defaultValue, "Message body has no '" + key + "'!"); + if (!json.has(argKey)) { + return defaultOrThrow(defaultValue, "Message body has no '" + argKey + "'!"); } - JsonNode valueNode = json.get(key); + JsonNode valueNode = json.get(argKey); if (valueNode.isNull()) { - return defaultOrThrow(defaultValue, "Message body has null '" + key + "'!"); + return defaultOrThrow(defaultValue, "Message body has null '" + argKey + "'!"); } double value; if (valueNode.isNumber()) { @@ -69,7 +68,7 @@ public class TbMathArgumentValue { throw new RuntimeException("Can't convert value '" + valueNode.asText() + "' to double!"); } } else { - return defaultOrThrow(defaultValue, "Message value is empty for '" + key + "'!"); + return defaultOrThrow(defaultValue, "Message value is empty for '" + argKey + "'!"); } } else { throw new RuntimeException("Can't convert value '" + valueNode.toString() + "' to double!"); @@ -77,15 +76,14 @@ public class TbMathArgumentValue { return new TbMathArgumentValue(value); } - public static TbMathArgumentValue fromMessageMetadata(TbMathArgument arg, TbMsgMetaData metaData) { - String key = arg.getKey(); + public static TbMathArgumentValue fromMessageMetadata(TbMathArgument arg, String argKey, TbMsgMetaData metaData) { Double defaultValue = arg.getDefaultValue(); if (metaData == null) { return defaultOrThrow(defaultValue, "Message metadata is empty!"); } - var value = metaData.getValue(key); + var value = metaData.getValue(argKey); if (StringUtils.isEmpty(value)) { - return defaultOrThrow(defaultValue, "Message metadata has no '" + key + "'!"); + return defaultOrThrow(defaultValue, "Message metadata has no '" + argKey + "'!"); } return fromString(value); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java index eff3917c14..26ec656443 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java @@ -51,6 +51,8 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; +import static org.thingsboard.rule.engine.math.TbMathArgumentType.CONSTANT; + @SuppressWarnings("UnstableApiUsage") @Slf4j @RuleNode( @@ -121,7 +123,7 @@ public class TbMathNode implements TbNode { var argumentValues = Futures.allAsList(arguments.stream() .map(arg -> resolveArguments(ctx, msg, msgBodyOpt, arg)).collect(Collectors.toList())); ListenableFuture resultMsgFuture = Futures.transformAsync(argumentValues, args -> - updateMsgAndDb(ctx, msg, msgBodyOpt, calculateResult(ctx, msg, args)), ctx.getDbCallbackExecutor()); + updateMsgAndDb(ctx, msg, msgBodyOpt, calculateResult(args)), ctx.getDbCallbackExecutor()); DonAsynchron.withCallback(resultMsgFuture, resultMsg -> { try { ctx.tellSuccess(resultMsg); @@ -155,17 +157,18 @@ public class TbMathNode implements TbNode { private ListenableFuture updateMsgAndDb(TbContext ctx, TbMsg msg, Optional msgBodyOpt, double result) { TbMathResult mathResultDef = config.getResult(); + String mathResultKey = !mathResultDef.getType().equals(CONSTANT) ? TbNodeUtils.processPattern(mathResultDef.getKey(), msg) : mathResultDef.getKey(); switch (mathResultDef.getType()) { case MESSAGE_BODY: - return Futures.immediateFuture(addToBody(msg, mathResultDef, msgBodyOpt, result)); + return Futures.immediateFuture(addToBody(msg, mathResultDef, mathResultKey, msgBodyOpt, result)); case MESSAGE_METADATA: - return Futures.immediateFuture(addToMeta(msg, mathResultDef, result)); + return Futures.immediateFuture(addToMeta(msg, mathResultDef, mathResultKey, result)); case ATTRIBUTE: ListenableFuture attrSave = saveAttribute(ctx, msg, result, mathResultDef); - return Futures.transform(attrSave, attr -> addToBodyAndMeta(msg, msgBodyOpt, result, mathResultDef), ctx.getDbCallbackExecutor()); + return Futures.transform(attrSave, attr -> addToBodyAndMeta(msg, msgBodyOpt, result, mathResultDef, mathResultKey), ctx.getDbCallbackExecutor()); case TIME_SERIES: ListenableFuture tsSave = saveTimeSeries(ctx, msg, result, mathResultDef); - return Futures.transform(tsSave, ts -> addToBodyAndMeta(msg, msgBodyOpt, result, mathResultDef), ctx.getDbCallbackExecutor()); + return Futures.transform(tsSave, ts -> addToBodyAndMeta(msg, msgBodyOpt, result, mathResultDef, mathResultKey), ctx.getDbCallbackExecutor()); default: throw new RuntimeException("Result type is not supported: " + mathResultDef.getType() + "!"); } @@ -217,38 +220,38 @@ public class TbMathNode implements TbNode { return msgBodyOpt; } - private TbMsg addToBodyAndMeta(TbMsg msg, Optional msgBodyOpt, double result, TbMathResult mathResultDef) { + private TbMsg addToBodyAndMeta(TbMsg msg, Optional msgBodyOpt, double result, TbMathResult mathResultDef, String mathResultKey) { TbMsg tmpMsg = msg; if (mathResultDef.isAddToBody()) { - tmpMsg = addToBody(tmpMsg, mathResultDef, msgBodyOpt, result); + tmpMsg = addToBody(tmpMsg, mathResultDef, mathResultKey, msgBodyOpt, result); } if (mathResultDef.isAddToMetadata()) { - tmpMsg = addToMeta(tmpMsg, mathResultDef, result); + tmpMsg = addToMeta(tmpMsg, mathResultDef, mathResultKey, result); } return tmpMsg; } - private TbMsg addToBody(TbMsg msg, TbMathResult mathResultDef, Optional msgBodyOpt, double result) { + private TbMsg addToBody(TbMsg msg, TbMathResult mathResultDef, String mathResultKey, Optional msgBodyOpt, double result) { ObjectNode body = msgBodyOpt.get(); if (isIntegerResult(mathResultDef, config.getOperation())) { - body.put(mathResultDef.getKey(), toIntValue(mathResultDef, result)); + body.put(mathResultKey, toIntValue(mathResultDef, result)); } else { - body.put(mathResultDef.getKey(), toDoubleValue(mathResultDef, result)); + body.put(mathResultKey, toDoubleValue(mathResultDef, result)); } return TbMsg.transformMsgData(msg, JacksonUtil.toString(body)); } - private TbMsg addToMeta(TbMsg msg, TbMathResult mathResultDef, double result) { + private TbMsg addToMeta(TbMsg msg, TbMathResult mathResultDef, String mathResultKey, double result) { var md = msg.getMetaData(); if (isIntegerResult(mathResultDef, config.getOperation())) { - md.putValue(mathResultDef.getKey(), Long.toString(toIntValue(mathResultDef, result))); + md.putValue(mathResultKey, Long.toString(toIntValue(mathResultDef, result))); } else { - md.putValue(mathResultDef.getKey(), Double.toString(toDoubleValue(mathResultDef, result))); + md.putValue(mathResultKey, Double.toString(toDoubleValue(mathResultDef, result))); } return TbMsg.transformMsg(msg, md); } - private double calculateResult(TbContext ctx, TbMsg msg, List args) { + private double calculateResult(List args) { switch (config.getOperation()) { case ADD: return apply(args.get(0), args.get(1), Double::sum); @@ -345,21 +348,22 @@ public class TbMathNode implements TbNode { } private ListenableFuture resolveArguments(TbContext ctx, TbMsg msg, Optional msgBodyOpt, TbMathArgument arg) { + String argKey = !arg.getType().equals(CONSTANT) ? TbNodeUtils.processPattern(arg.getKey(), msg) : arg.getKey(); switch (arg.getType()) { case CONSTANT: return Futures.immediateFuture(TbMathArgumentValue.constant(arg)); case MESSAGE_BODY: - return Futures.immediateFuture(TbMathArgumentValue.fromMessageBody(arg, msgBodyOpt)); + return Futures.immediateFuture(TbMathArgumentValue.fromMessageBody(arg, argKey, msgBodyOpt)); case MESSAGE_METADATA: - return Futures.immediateFuture(TbMathArgumentValue.fromMessageMetadata(arg, msg.getMetaData())); + return Futures.immediateFuture(TbMathArgumentValue.fromMessageMetadata(arg, argKey, msg.getMetaData())); case ATTRIBUTE: String scope = getAttributeScope(arg.getAttributeScope()); - return Futures.transform(ctx.getAttributesService().find(ctx.getTenantId(), msg.getOriginator(), scope, arg.getKey()), - opt -> getTbMathArgumentValue(arg, opt, "Attribute: " + arg.getKey() + " with scope: " + scope + " not found for entity: " + msg.getOriginator()) + return Futures.transform(ctx.getAttributesService().find(ctx.getTenantId(), msg.getOriginator(), scope, argKey), + opt -> getTbMathArgumentValue(arg, opt, "Attribute: " + argKey + " with scope: " + scope + " not found for entity: " + msg.getOriginator()) , MoreExecutors.directExecutor()); case TIME_SERIES: - return Futures.transform(ctx.getTimeseriesService().findLatest(ctx.getTenantId(), msg.getOriginator(), arg.getKey()), - opt -> getTbMathArgumentValue(arg, opt, "Time-series: " + arg.getKey() + " not found for entity: " + msg.getOriginator()) + return Futures.transform(ctx.getTimeseriesService().findLatest(ctx.getTenantId(), msg.getOriginator(), argKey), + opt -> getTbMathArgumentValue(arg, opt, "Time-series: " + argKey + " not found for entity: " + msg.getOriginator()) , MoreExecutors.directExecutor()); default: throw new RuntimeException("Unsupported argument type: " + arg.getType() + "!"); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathArgumentValueTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathArgumentValueTest.java index 984d9bfb72..eccc9bb932 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathArgumentValueTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathArgumentValueTest.java @@ -31,7 +31,7 @@ public class TbMathArgumentValueTest { public void test_fromMessageBody_then_defaultValue() { TbMathArgument tbMathArgument = new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "TestKey"); tbMathArgument.setDefaultValue(5.0); - TbMathArgumentValue result = TbMathArgumentValue.fromMessageBody(tbMathArgument, Optional.ofNullable(JacksonUtil.newObjectNode())); + TbMathArgumentValue result = TbMathArgumentValue.fromMessageBody(tbMathArgument, tbMathArgument.getKey(), Optional.ofNullable(JacksonUtil.newObjectNode())); Assert.assertEquals(5.0, result.getValue(), 0d); } @@ -39,7 +39,7 @@ public class TbMathArgumentValueTest { public void test_fromMessageBody_then_emptyBody() { TbMathArgument tbMathArgument = new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "TestKey"); Throwable thrown = assertThrows(RuntimeException.class, () -> { - TbMathArgumentValue result = TbMathArgumentValue.fromMessageBody(tbMathArgument, Optional.empty()); + TbMathArgumentValue result = TbMathArgumentValue.fromMessageBody(tbMathArgument, tbMathArgument.getKey(), Optional.empty()); }); Assert.assertNotNull(thrown.getMessage()); } @@ -47,7 +47,7 @@ public class TbMathArgumentValueTest { @Test public void test_fromMessageBody_then_noKey() { TbMathArgument tbMathArgument = new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "TestKey"); - Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, Optional.ofNullable(JacksonUtil.newObjectNode()))); + Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, tbMathArgument.getKey(), Optional.ofNullable(JacksonUtil.newObjectNode()))); Assert.assertNotNull(thrown.getMessage()); } @@ -58,12 +58,12 @@ public class TbMathArgumentValueTest { msgData.putNull("TestKey"); //null value - Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, Optional.of(msgData))); + Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, tbMathArgument.getKey(), Optional.of(msgData))); Assert.assertNotNull(thrown.getMessage()); //empty value msgData.put("TestKey", ""); - thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, Optional.of(msgData))); + thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, tbMathArgument.getKey(), Optional.of(msgData))); Assert.assertNotNull(thrown.getMessage()); } @@ -74,26 +74,26 @@ public class TbMathArgumentValueTest { msgData.put("TestKey", "Test"); //string value - Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, Optional.of(msgData))); + Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, tbMathArgument.getKey(), Optional.of(msgData))); Assert.assertNotNull(thrown.getMessage()); //object value msgData.set("TestKey", JacksonUtil.newObjectNode()); - thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, Optional.of(msgData))); + thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageBody(tbMathArgument, tbMathArgument.getKey(), Optional.of(msgData))); Assert.assertNotNull(thrown.getMessage()); } @Test public void test_fromMessageMetadata_then_noKey() { TbMathArgument tbMathArgument = new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "TestKey"); - Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageMetadata(tbMathArgument, new TbMsgMetaData())); + Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageMetadata(tbMathArgument, tbMathArgument.getKey(), new TbMsgMetaData())); Assert.assertNotNull(thrown.getMessage()); } @Test public void test_fromMessageMetadata_then_valueEmpty() { TbMathArgument tbMathArgument = new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "TestKey"); - Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageMetadata(tbMathArgument, null)); + Throwable thrown = assertThrows(RuntimeException.class, () -> TbMathArgumentValue.fromMessageMetadata(tbMathArgument, tbMathArgument.getKey(), null)); Assert.assertNotNull(thrown.getMessage()); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java index 69d1b46dbe..2efc438f8f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java @@ -16,7 +16,10 @@ package org.thingsboard.rule.engine.math; import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; +import lombok.extern.slf4j.Slf4j; +import org.awaitility.Awaitility; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -26,6 +29,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.common.util.AbstractListeningExecutor; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; @@ -47,7 +51,11 @@ import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import java.util.Arrays; +import java.util.List; import java.util.Optional; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; @@ -57,6 +65,7 @@ import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +@Slf4j @RunWith(MockitoJUnitRunner.class) public class TbMathNodeTest { @@ -130,24 +139,52 @@ public class TbMathNodeTest { @Test public void testExp4j() { var node = initNodeWithCustomFunction("2a+3b", - new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "result", 2, false, false, null), - new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a"), - new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") + new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "${key1}", 2, false, false, null), + new TbMathArgument("a", TbMathArgumentType.MESSAGE_BODY, "${key2}"), + new TbMathArgument("b", TbMathArgumentType.MESSAGE_BODY, "$[key3]") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + TbMsgMetaData metaData = new TbMsgMetaData(); + metaData.putValue("key1", "firstMsgResult"); + metaData.putValue("key2", "argumentA"); + ObjectNode msgNode = JacksonUtil.newObjectNode() + .put("key3", "argumentB").put("argumentA", 2).put("argumentB", 2); + TbMsg msg = TbMsg.newMsg("TEST", originator, metaData, msgNode.toString()); node.onMsg(ctx, msg); - ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - Mockito.verify(ctx, Mockito.timeout(5000)).tellSuccess(msgCaptor.capture()); + ConcurrentMap semaphores = (ConcurrentMap) ReflectionTestUtils.getField(node, "semaphores"); + Assert.assertNotNull(semaphores); + Semaphore originatorSemaphore = semaphores.get(originator); + Assert.assertNotNull(originatorSemaphore); - TbMsg resultMsg = msgCaptor.getValue(); - Assert.assertNotNull(resultMsg); - Assert.assertNotNull(resultMsg.getData()); - var resultJson = JacksonUtil.toJsonNode(resultMsg.getData()); - Assert.assertTrue(resultJson.has("result")); - Assert.assertEquals(10, resultJson.get("result").asInt()); + metaData.putValue("key1", "secondMsgResult"); + metaData.putValue("key2", "argumentC"); + msgNode = JacksonUtil.newObjectNode() + .put("key3", "argumentD").put("argumentC", 4).put("argumentD", 3); + msg = TbMsg.newMsg("TEST", originator, metaData, msgNode.toString()); + + node.onMsg(ctx, msg); + + Awaitility.await("Semaphore released").atMost(5, TimeUnit.SECONDS).until(semaphores.get(originator)::tryAcquire); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + Mockito.verify(ctx, Mockito.times(2)).tellSuccess(msgCaptor.capture()); + + List resultMsgs = msgCaptor.getAllValues(); + Assert.assertFalse(resultMsgs.isEmpty()); + Assert.assertEquals(2, resultMsgs.size()); + + for (int i = 0; i < resultMsgs.size(); i++) { + TbMsg outMsg = resultMsgs.get(i); + Assert.assertNotNull(outMsg); + Assert.assertNotNull(outMsg.getData()); + var resultJson = JacksonUtil.toJsonNode(outMsg.getData()); + String resultKey = i == 0 ? "firstMsgResult" : "secondMsgResult"; + Assert.assertTrue(resultJson.has(resultKey)); + Assert.assertEquals(i == 0 ? 10 : 17, resultJson.get(resultKey).asInt()); + } + semaphores.remove(originator); } @Test From 080a40983964a818b5eb9bd91c4942db252af92d Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 8 Jun 2023 15:52:40 +0300 Subject: [PATCH 096/421] Check edge session before removal to avoid removing live session --- .../service/edge/rpc/EdgeGrpcService.java | 33 +++++++++++-------- .../service/edge/rpc/EdgeGrpcSession.java | 8 ++--- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index 5171a6037f..92a7c27867 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -380,21 +380,26 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i } } - private void onEdgeDisconnect(EdgeId edgeId) { - log.info("[{}] edge disconnected!", edgeId); - EdgeGrpcSession removed = sessions.remove(edgeId); - final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); - newEventLock.lock(); - try { - sessionNewEvents.remove(edgeId); - } finally { - newEventLock.unlock(); + private void onEdgeDisconnect(EdgeId edgeId, UUID sessionId) { + log.info("[{}][{}] edge disconnected!", edgeId, sessionId); + EdgeGrpcSession toRemove = sessions.get(edgeId); + if (toRemove.getSessionId().equals(sessionId)) { + toRemove = sessions.remove(edgeId); + final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); + newEventLock.lock(); + try { + sessionNewEvents.remove(edgeId); + } finally { + newEventLock.unlock(); + } + save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false); + long lastDisconnectTs = System.currentTimeMillis(); + save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs); + pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, DISCONNECT_EVENT); + cancelScheduleEdgeEventsCheck(edgeId); + } else { + log.debug("[{}] edge session [{}] is not available anymore, nothing to remove. most probably this session is already outdated!", edgeId, sessionId); } - save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false); - long lastDisconnectTs = System.currentTimeMillis(); - save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs); - pushRuleEngineMessage(removed.getEdge().getTenantId(), edgeId, lastDisconnectTs, DISCONNECT_EVENT); - cancelScheduleEdgeEventsCheck(edgeId); } private void save(EdgeId edgeId, String key, long value) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java index 33aed92682..1dd0f31c20 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java @@ -92,7 +92,7 @@ public final class EdgeGrpcSession implements Closeable { private final UUID sessionId; private final BiConsumer sessionOpenListener; - private final Consumer sessionCloseListener; + private final BiConsumer sessionCloseListener; private final EdgeSessionState sessionState = new EdgeSessionState(); @@ -111,7 +111,7 @@ public final class EdgeGrpcSession implements Closeable { private ScheduledExecutorService sendDownlinkExecutorService; EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver outputStream, BiConsumer sessionOpenListener, - Consumer sessionCloseListener, ScheduledExecutorService sendDownlinkExecutorService, int maxInboundMessageSize) { + BiConsumer sessionCloseListener, ScheduledExecutorService sendDownlinkExecutorService, int maxInboundMessageSize) { this.sessionId = UUID.randomUUID(); this.ctx = ctx; this.outputStream = outputStream; @@ -180,7 +180,7 @@ public final class EdgeGrpcSession implements Closeable { connected = false; if (edge != null) { try { - sessionCloseListener.accept(edge.getId()); + sessionCloseListener.accept(edge.getId(), sessionId); } catch (Exception ignored) { } } @@ -288,7 +288,7 @@ public final class EdgeGrpcSession implements Closeable { } catch (Exception e) { log.error("[{}] Failed to send downlink message [{}]", this.sessionId, downlinkMsg, e); connected = false; - sessionCloseListener.accept(edge.getId()); + sessionCloseListener.accept(edge.getId(), sessionId); } finally { downlinkMsgLock.unlock(); } From 9dd10b0b75e398af3c95935ce73d239cad809e17 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 8 Jun 2023 15:51:10 +0200 Subject: [PATCH 097/421] fixed Iterator already obtained --- .../java/org/thingsboard/common/util/AzureIotHubUtil.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/util/src/main/java/org/thingsboard/common/util/AzureIotHubUtil.java b/common/util/src/main/java/org/thingsboard/common/util/AzureIotHubUtil.java index 5beed77baf..b80427d0de 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/AzureIotHubUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/AzureIotHubUtil.java @@ -27,6 +27,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Base64; +import java.util.Iterator; @Slf4j public final class AzureIotHubUtil { @@ -100,8 +101,9 @@ public final class AzureIotHubUtil { } else { Path azureDirectory = FULL_FILE_PATH.getParent(); try (DirectoryStream stream = Files.newDirectoryStream(azureDirectory)) { - if (stream.iterator().hasNext()) { - Path firstFile = stream.iterator().next(); + Iterator iterator = stream.iterator(); + if (iterator.hasNext()) { + Path firstFile = iterator.next(); fileBytes = Files.readAllBytes(firstFile); } else { log.error("Default CaCert file not found in the directory [{}]!!!", azureDirectory); From 5102e5fda7e570572c60b485fcf47d591cd3d4f0 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 8 Jun 2023 17:11:31 +0300 Subject: [PATCH 098/421] UI: Refactoring for touch event --- .../widget/lib/flot-widget.models.ts | 4 +-- .../home/components/widget/lib/flot-widget.ts | 28 ++++--------------- .../chart/flot-widget-settings.component.html | 22 +++------------ .../chart/flot-widget-settings.component.ts | 4 +-- .../assets/locale/locale.constant-en_US.json | 5 +--- ui-ngx/src/typings/jquery.flot.typings.d.ts | 1 + 6 files changed, 15 insertions(+), 49 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts index 46bafd69ca..844d7540ff 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts @@ -136,7 +136,7 @@ export interface TbFlotYAxisSettings { export interface TbFlotBaseSettings { stack: boolean; - enableSelection: FlotSelection; + enableSelection: boolean; shadowSize: number; fontColor: string; fontSize: number; @@ -183,8 +183,6 @@ export interface TbFlotGraphSettings extends TbFlotBaseSettings, export declare type BarAlignment = 'left' | 'right' | 'center'; -export declare type FlotSelection = 'enable' | 'disable' | 'mobile' | 'desktop'; - export interface TbFlotBarSettings extends TbFlotBaseSettings, TbFlotThresholdsSettings, TbFlotComparisonSettings, TbFlotCustomLegendSettings { defaultBarWidth: number; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index 4f3db3d91b..1d20068e20 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -37,7 +37,7 @@ import { widgetType } from '@app/shared/models/widget.models'; import { - ChartType, FlotSelection, + ChartType, TbFlotAxisOptions, TbFlotHoverInfo, TbFlotKeySettings, @@ -117,7 +117,7 @@ export class TbFlot { private mouseleaveHandler = this.onFlotMouseLeave.bind(this); private flotClickHandler = this.onFlotClick.bind(this); - private enableSelection: FlotSelection; + private enableSelection: boolean; private selectionMode: 'x' | null; private readonly showTooltip: boolean; @@ -134,8 +134,8 @@ export class TbFlot { this.chartType = this.chartType || 'line'; this.settings = ctx.settings as TbFlotSettings; this.utils = this.ctx.$injector.get(UtilsService); - this.enableSelection = isDefined(this.settings.enableSelection) ? this.settings.enableSelection : 'enable'; - this.checkSelectionMode(); + this.enableSelection = isDefined(this.settings.enableSelection) ? this.settings.enableSelection : true; + this.selectionMode = this.enableSelection ? 'x' : null; this.showTooltip = isDefined(this.settings.showTooltip) ? this.settings.showTooltip : true; this.tooltip = this.showTooltip ? $('#flot-series-tooltip') : null; if (this.tooltip?.length === 0) { @@ -172,7 +172,7 @@ export class TbFlot { }; if (this.chartType === 'line' || this.chartType === 'bar' || this.chartType === 'state') { - this.options.selection = { mode: this.selectionMode }; + this.options.selection = { mode: this.selectionMode, touch: true }; this.options.xaxes = []; this.xaxis = { mode: 'time', @@ -589,22 +589,6 @@ export class TbFlot { this.createPlot(); } - mobileModeChanged() { - this.checkSelectionMode(); - this.options.selection = { mode: this.selectionMode }; - this.redrawPlot(); - } - - private checkSelectionMode() { - if (this.enableSelection === 'enable' || - this.enableSelection === 'mobile' && this.ctx.isMobile || - this.enableSelection === 'desktop' && !this.ctx.isMobile) { - this.selectionMode = 'x'; - } else { - this.selectionMode = null; - } - } - public update() { if (this.updateTimeoutHandle) { clearTimeout(this.updateTimeoutHandle); @@ -1272,7 +1256,7 @@ export class TbFlot { this.$element.css('pointer-events', ''); this.$element.addClass('mouse-events'); if (this.chartType !== 'pie') { - this.options.selection = {mode: this.selectionMode}; + this.options.selection = {mode: this.selectionMode, touch: true}; this.$element.bind('plotselected', this.flotSelectHandler); this.$element.bind('dblclick', this.dblclickHandler); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html index 00173841e6..9baf89cbd4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html @@ -19,26 +19,12 @@
widgets.chart.common-settings
- + {{ 'widgets.chart.enable-stacking-mode' | translate }} - - widgets.chart.selection - - - {{ 'widgets.chart.selection-enable' | translate }} - - - {{ 'widgets.chart.selection-disable' | translate }} - - - {{ 'widgets.chart.selection-mobile' | translate }} - - - {{ 'widgets.chart.selection-desktop' | translate }} - - - + + {{ 'widgets.chart.enable-selection-mode' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts index 92e7309b4b..abcfdeebc3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts @@ -45,7 +45,7 @@ import { defaultLegendConfig, widgetType } from '@shared/models/widget.models'; export const flotDefaultSettings = (chartType: ChartType): Partial => { const settings: Partial = { stack: false, - enableSelection: 'enable', + enableSelection: true, fontColor: '#545454', fontSize: 10, showTooltip: true, @@ -149,7 +149,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit // Common settings stack: [false, []], - enableSelection: ['enable', []], + enableSelection: [true, []], fontSize: [10, [Validators.min(0)]], fontColor: ['#545454', []], 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 4eca6e48d9..724fd11893 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4214,10 +4214,7 @@ "common-settings": "Common settings", "enable-stacking-mode": "Enable stacking mode", "selection": "Time range selection", - "selection-enable": "Enable", - "selection-disable": "Disable", - "selection-mobile": "Only mobile", - "selection-desktop": "Only desktop", + "enable-selection-mode": "Enable stacking mode", "line-shadow-size": "Line shadow size", "display-smooth-lines": "Display smooth (curved) lines", "default-bar-width": "Default bar width for non-aggregated data (milliseconds)", diff --git a/ui-ngx/src/typings/jquery.flot.typings.d.ts b/ui-ngx/src/typings/jquery.flot.typings.d.ts index 5bcc9b9b3e..e832a36e7a 100644 --- a/ui-ngx/src/typings/jquery.flot.typings.d.ts +++ b/ui-ngx/src/typings/jquery.flot.typings.d.ts @@ -119,6 +119,7 @@ interface JQueryPlotSelection { color?: string; shape?: JQueryPlotSelectionShape; minSize?: number; + touch?: boolean; } interface JQueryPlotSelectionRanges { From f5aba152cf164d7e8ac9d3c8ee4b69ef1ec81d33 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 8 Jun 2023 17:30:09 +0300 Subject: [PATCH 099/421] UI: Refactoring locale --- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 724fd11893..a097c16dc3 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4214,7 +4214,7 @@ "common-settings": "Common settings", "enable-stacking-mode": "Enable stacking mode", "selection": "Time range selection", - "enable-selection-mode": "Enable stacking mode", + "enable-selection-mode": "Enable selection mode", "line-shadow-size": "Line shadow size", "display-smooth-lines": "Display smooth (curved) lines", "default-bar-width": "Default bar width for non-aggregated data (milliseconds)", From b77078c24e3b5a01865394826e81cb4ba38e3f49 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 8 Jun 2023 18:15:56 +0300 Subject: [PATCH 100/421] Notifications deduplication improvements --- .../ruleChain/RuleEngineComponentActor.java | 2 +- .../NotificationRuleController.java | 2 +- .../service/action/EntityActionService.java | 8 +- .../DefaultTbApiUsageStateService.java | 2 +- .../DefaultNotificationRuleProcessor.java | 59 +-------- .../cache/DefaultNotificationRulesCache.java | 2 +- .../rule/cache/NotificationRulesCache.java | 2 +- .../AlarmAssignmentTriggerProcessor.java | 8 +- .../trigger/AlarmCommentTriggerProcessor.java | 6 +- .../rule/trigger/AlarmTriggerProcessor.java | 10 +- .../ApiUsageLimitTriggerProcessor.java | 6 +- .../DeviceActivityTriggerProcessor.java | 8 +- .../EntitiesLimitTriggerProcessor.java | 6 +- .../trigger/EntityActionTriggerProcessor.java | 6 +- .../NewPlatformVersionTriggerProcessor.java | 6 +- .../NotificationRuleTriggerProcessor.java | 6 +- ...mponentLifecycleEventTriggerProcessor.java | 6 +- .../queue/DefaultTbCoreConsumerService.java | 2 +- .../state/DefaultDeviceStateService.java | 2 +- .../impl/NotificationRuleExportService.java | 6 +- .../impl/NotificationRuleImportService.java | 8 +- .../DefaultAlarmSubscriptionService.java | 2 +- .../service/update/DefaultUpdateService.java | 2 +- .../src/main/resources/thingsboard.yml | 6 +- .../AbstractNotificationApiTest.java | 2 +- .../notification/NotificationRuleApiTest.java | 28 ++--- .../NotificationTargetApiTest.java | 2 +- .../notification/NotificationRuleService.java | 2 +- .../notification/rule/NotificationRule.java | 4 +- .../NotificationRuleRecipientsConfig.java | 2 +- .../rule}/trigger/AlarmAssignmentTrigger.java | 4 +- .../rule}/trigger/AlarmCommentTrigger.java | 4 +- .../rule}/trigger/AlarmTrigger.java | 4 +- .../rule}/trigger/ApiUsageLimitTrigger.java | 4 +- .../rule}/trigger/DeviceActivityTrigger.java | 4 +- .../rule}/trigger/EntitiesLimitTrigger.java | 4 +- .../rule}/trigger/EntityActionTrigger.java | 4 +- .../trigger/NewPlatformVersionTrigger.java | 4 +- .../trigger/NotificationRuleTrigger.java | 4 +- ...eEngineComponentLifecycleEventTrigger.java | 4 +- ...signmentNotificationRuleTriggerConfig.java | 2 +- ...mCommentNotificationRuleTriggerConfig.java | 2 +- .../AlarmNotificationRuleTriggerConfig.java | 2 +- ...ageLimitNotificationRuleTriggerConfig.java | 2 +- ...ActivityNotificationRuleTriggerConfig.java | 2 +- ...iesLimitNotificationRuleTriggerConfig.java | 2 +- ...tyActionNotificationRuleTriggerConfig.java | 2 +- ...mVersionNotificationRuleTriggerConfig.java | 2 +- .../NotificationRuleTriggerConfig.java | 2 +- .../NotificationRuleTriggerType.java | 2 +- ...cleEventNotificationRuleTriggerConfig.java | 2 +- .../NotificationRuleProcessor.java | 2 +- ...faultNotificationDeduplicationService.java | 114 ++++++++++++++++++ .../NotificationDeduplicationService.java} | 14 ++- .../RemoteNotificationRuleProcessor.java | 67 +--------- .../dao/model/sql/NotificationRuleEntity.java | 4 +- .../DefaultNotificationRuleService.java | 2 +- .../notification/DefaultNotifications.java | 26 ++-- .../dao/notification/NotificationRuleDao.java | 2 +- .../notification/JpaNotificationRuleDao.java | 2 +- .../NotificationRuleRepository.java | 2 +- 61 files changed, 262 insertions(+), 248 deletions(-) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/AlarmAssignmentTrigger.java (93%) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/AlarmCommentTrigger.java (93%) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/AlarmTrigger.java (92%) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/ApiUsageLimitTrigger.java (92%) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/DeviceActivityTrigger.java (93%) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/EntitiesLimitTrigger.java (92%) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/EntityActionTrigger.java (93%) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/NewPlatformVersionTrigger.java (94%) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/NotificationRuleTrigger.java (92%) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/RuleEngineComponentLifecycleEventTrigger.java (93%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/AlarmAssignmentNotificationRuleTriggerConfig.java (99%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/AlarmCommentNotificationRuleTriggerConfig.java (99%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/AlarmNotificationRuleTriggerConfig.java (99%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/ApiUsageLimitNotificationRuleTriggerConfig.java (99%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/DeviceActivityNotificationRuleTriggerConfig.java (99%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/EntitiesLimitNotificationRuleTriggerConfig.java (99%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/EntityActionNotificationRuleTriggerConfig.java (99%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/NewPlatformVersionNotificationRuleTriggerConfig.java (98%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/NotificationRuleTriggerConfig.java (99%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/NotificationRuleTriggerType.java (98%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java (99%) create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java rename common/{data/src/main/java/org/thingsboard/server/common/data/notification/settings/TriggerTypeConfig.java => queue/src/main/java/org/thingsboard/server/queue/notification/NotificationDeduplicationService.java} (59%) diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java index e1918466a8..42a78b7965 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.TbActorStopReason; -import org.thingsboard.server.common.msg.notification.trigger.RuleEngineComponentLifecycleEventTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventTrigger; public abstract class RuleEngineComponentActor> extends ComponentActor { diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java index ccf2124113..2afb67a8bd 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationRuleController.java @@ -34,7 +34,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; diff --git a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java index 99b508a12d..e068cd4d23 100644 --- a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java +++ b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java @@ -43,10 +43,10 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; -import org.thingsboard.server.common.msg.notification.trigger.AlarmAssignmentTrigger; -import org.thingsboard.server.common.msg.notification.trigger.AlarmCommentTrigger; -import org.thingsboard.server.common.msg.notification.trigger.EntitiesLimitTrigger; -import org.thingsboard.server.common.msg.notification.trigger.EntityActionTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionTrigger; import org.thingsboard.server.dao.audit.AuditLogService; import java.util.List; diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index 7e2719598c..ef6e4fa0bf 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -48,7 +48,7 @@ import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.tenant.profile.TenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; -import org.thingsboard.server.common.msg.notification.trigger.ApiUsageLimitTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.ApiUsageLimitTrigger; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java index 71a59026a2..93d89fa0b1 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java @@ -16,17 +16,12 @@ package org.thingsboard.server.service.notification.rule; import lombok.RequiredArgsConstructor; -import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Lazy; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.NotificationCenter; -import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.NotificationRequestId; @@ -37,61 +32,47 @@ import org.thingsboard.server.common.data.notification.NotificationRequestConfig import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.notification.info.NotificationInfo; import org.thingsboard.server.common.data.notification.rule.NotificationRule; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.data.notification.settings.TriggerTypeConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; -import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTrigger; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.dao.notification.NotificationRequestService; import org.thingsboard.server.dao.util.limits.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.notification.NotificationDeduplicationService; import org.thingsboard.server.service.executors.NotificationExecutorService; import org.thingsboard.server.service.notification.rule.cache.NotificationRulesCache; import org.thingsboard.server.service.notification.rule.trigger.NotificationRuleTriggerProcessor; -import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; @Service @RequiredArgsConstructor -@ConfigurationProperties(prefix = "notification-system.rules") @Slf4j @SuppressWarnings({"rawtypes", "unchecked"}) public class DefaultNotificationRuleProcessor implements NotificationRuleProcessor { private final NotificationRulesCache notificationRulesCache; private final NotificationRequestService notificationRequestService; + private final NotificationDeduplicationService deduplicationService; private final PartitionService partitionService; private final RateLimitService rateLimitService; @Autowired @Lazy private NotificationCenter notificationCenter; private final NotificationExecutorService notificationExecutor; - private final CacheManager cacheManager; - private Cache sentNotifications; - @Setter - private Map triggerTypesConfigs; private final Map triggerProcessors = new EnumMap<>(NotificationRuleTriggerType.class); - @PostConstruct - private void init() { - sentNotifications = cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE); - if (sentNotifications == null) { - throw new IllegalStateException("Sent notifications cache is not set up"); - } - } - @Override public void process(NotificationRuleTrigger trigger) { NotificationRuleTriggerType triggerType = trigger.getType(); @@ -104,7 +85,7 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess } if (trigger.deduplicate()) { enabledRules = new ArrayList<>(enabledRules); - enabledRules.removeIf(rule -> alreadySent(rule, trigger)); + enabledRules.removeIf(rule -> deduplicationService.alreadyProcessed(trigger, rule)); } final List rules = enabledRules; notificationExecutor.submit(() -> { @@ -199,34 +180,6 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess return triggerProcessors.get(triggerConfig.getTriggerType()).constructNotificationInfo(trigger); } - private boolean alreadySent(NotificationRule rule, NotificationRuleTrigger trigger) { - String deduplicationKey = getDeduplicationKey(trigger, rule); - - boolean alreadySent = false; - Long lastSentTs = sentNotifications.get(deduplicationKey, Long.class); - if (lastSentTs != null) { - long deduplicationDuration = Optional.ofNullable(triggerTypesConfigs) - .map(triggerTypes -> triggerTypes.get(trigger.getType())) - .map(TriggerTypeConfig::getDeduplicationDuration) - .orElseGet(trigger::getDefaultDeduplicationDuration); - long passed = System.currentTimeMillis() - lastSentTs; - log.trace("Deduplicating trigger {} for rule '{}' by key '{}'. Deduplication duration: {} ms, passed: {} ms", - trigger.getType(), rule.getName(), deduplicationKey, deduplicationDuration, passed); - if (deduplicationDuration == 0 || passed <= deduplicationDuration) { - alreadySent = true; - } - } - if (!alreadySent) { - lastSentTs = System.currentTimeMillis(); - } - sentNotifications.put(deduplicationKey, lastSentTs); - return alreadySent; - } - - public static String getDeduplicationKey(NotificationRuleTrigger trigger, NotificationRule rule) { - return String.join("_", trigger.getDeduplicationKey(), rule.getDeduplicationKey()); - } - @EventListener(ComponentLifecycleMsg.class) public void onNotificationRuleDeleted(ComponentLifecycleMsg componentLifecycleMsg) { if (componentLifecycleMsg.getEvent() != ComponentLifecycleEvent.DELETED || diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java index a43ed59efa..d8ac13364b 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/DefaultNotificationRulesCache.java @@ -24,7 +24,7 @@ import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.rule.NotificationRule; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.dao.notification.NotificationRuleService; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/NotificationRulesCache.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/NotificationRulesCache.java index 2a1054b352..bcfa7d0120 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/NotificationRulesCache.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/cache/NotificationRulesCache.java @@ -17,7 +17,7 @@ package org.thingsboard.server.service.notification.rule.cache; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.rule.NotificationRule; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import java.util.List; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java index eca258aecc..dba5fd8de4 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmAssignmentTriggerProcessor.java @@ -22,10 +22,10 @@ import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.notification.info.AlarmAssignmentNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig.Action; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.msg.notification.trigger.AlarmAssignmentTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmAssignmentNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmAssignmentNotificationRuleTriggerConfig.Action; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentTrigger; import static org.apache.commons.collections.CollectionUtils.isEmpty; import static org.thingsboard.server.common.data.util.CollectionsUtil.emptyOrContains; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java index 70024d6e09..ef742922b3 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmCommentTriggerProcessor.java @@ -24,9 +24,9 @@ import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.notification.info.AlarmCommentNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.msg.notification.trigger.AlarmCommentTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmCommentNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentTrigger; import org.thingsboard.server.dao.entity.EntityService; import static org.apache.commons.collections.CollectionUtils.isEmpty; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java index c32ed26854..d69d502aa2 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/AlarmTriggerProcessor.java @@ -22,11 +22,11 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.notification.info.AlarmNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.AlarmAction; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.ClearRule; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.msg.notification.trigger.AlarmTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig.AlarmAction; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig.ClearRule; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmTrigger; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.thingsboard.server.common.data.util.CollectionsUtil.emptyOrContains; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/ApiUsageLimitTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/ApiUsageLimitTriggerProcessor.java index 4e66a7905c..112fe2af7a 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/ApiUsageLimitTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/ApiUsageLimitTriggerProcessor.java @@ -19,9 +19,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.notification.info.ApiUsageLimitNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.ApiUsageLimitNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.msg.notification.trigger.ApiUsageLimitTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.ApiUsageLimitNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.ApiUsageLimitTrigger; import org.thingsboard.server.dao.tenant.TenantService; import static org.thingsboard.server.common.data.util.CollectionsUtil.emptyOrContains; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java index 3188eeabb1..729ad7f8da 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java @@ -23,10 +23,10 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.info.DeviceActivityNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.msg.notification.trigger.DeviceActivityTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.DeviceActivityNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger; import org.thingsboard.server.service.profile.TbDeviceProfileCache; @Service diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntitiesLimitTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntitiesLimitTriggerProcessor.java index 95ace87653..9539b42a43 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntitiesLimitTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntitiesLimitTriggerProcessor.java @@ -19,10 +19,10 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.notification.info.EntitiesLimitNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.EntitiesLimitNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; -import org.thingsboard.server.common.msg.notification.trigger.EntitiesLimitTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitTrigger; import org.thingsboard.server.dao.entity.EntityCountService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java index ea4902fb05..bc290fa978 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/EntityActionTriggerProcessor.java @@ -20,9 +20,9 @@ import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.notification.info.EntityActionNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.msg.notification.trigger.EntityActionTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.EntityActionNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionTrigger; import static org.thingsboard.server.common.data.util.CollectionsUtil.emptyOrContains; diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java index 639378ad72..aeec1a9b39 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NewPlatformVersionTriggerProcessor.java @@ -20,9 +20,9 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.notification.info.NewPlatformVersionNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.msg.notification.trigger.NewPlatformVersionTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NewPlatformVersionNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionTrigger; @Service @RequiredArgsConstructor diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java index fe7fb82ee5..67a8d3d701 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/NotificationRuleTriggerProcessor.java @@ -16,9 +16,9 @@ package org.thingsboard.server.service.notification.rule.trigger; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; public interface NotificationRuleTriggerProcessor { diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java index 6e37db83ef..8aac7ffd66 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RuleEngineComponentLifecycleEventTriggerProcessor.java @@ -23,10 +23,10 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.notification.info.RuleEngineComponentLifecycleEventNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; -import org.thingsboard.server.common.msg.notification.trigger.RuleEngineComponentLifecycleEventTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventTrigger; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.queue.discovery.PartitionService; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index 182fce1c48..dc24d6df33 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.rpc.RpcError; import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.TbActorMsg; -import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 337d607fac..554359fd6d 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -63,7 +63,7 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; -import org.thingsboard.server.common.msg.notification.trigger.DeviceActivityTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/NotificationRuleExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/NotificationRuleExportService.java index 0906fb83ef..a2b9c54403 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/NotificationRuleExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/NotificationRuleExportService.java @@ -28,9 +28,9 @@ import org.thingsboard.server.common.data.notification.rule.DefaultNotificationR import org.thingsboard.server.common.data.notification.rule.EscalatedNotificationRuleRecipientsConfig; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleRecipientsConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.DeviceActivityNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx; diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/NotificationRuleImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/NotificationRuleImportService.java index a7d7670c8c..9ace036ee6 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/NotificationRuleImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/NotificationRuleImportService.java @@ -32,10 +32,10 @@ import org.thingsboard.server.common.data.notification.rule.DefaultNotificationR import org.thingsboard.server.common.data.notification.rule.EscalatedNotificationRuleRecipientsConfig; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleRecipientsConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.DeviceActivityNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.dao.notification.NotificationRuleService; diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java index e7f2a5a66f..1603d33bfd 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java @@ -47,7 +47,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; -import org.thingsboard.server.common.msg.notification.trigger.AlarmTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmTrigger; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.stats.TbApiUsageReportClient; import org.thingsboard.server.dao.alarm.AlarmOperationResult; diff --git a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java index 587d86af32..f5e3daf05d 100644 --- a/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/update/DefaultUpdateService.java @@ -28,7 +28,7 @@ import org.springframework.web.client.RestTemplate; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.UpdateMessage; -import org.thingsboard.server.common.msg.notification.trigger.NewPlatformVersionTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionTrigger; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbCoreComponent; diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 392587c869..77300b3f2f 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1262,10 +1262,8 @@ vc: notification_system: thread_pool_size: "${TB_NOTIFICATION_SYSTEM_THREAD_POOL_SIZE:10}" rules: - trigger_types_configs: - NEW_PLATFORM_VERSION: - # In milliseconds, infinitely by default - deduplication_duration: "${NEW_PLATFORM_VERSION_NOTIFICATION_RULE_DEDUPLICATION_DURATION:0}" + # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' + deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:NEW_PLATFORM_VERSION:0;}" management: endpoints: diff --git a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java index f45882e416..fb7675bd9e 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java @@ -40,7 +40,7 @@ import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.rule.DefaultNotificationRuleRecipientsConfig; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index 6c4413d1e7..faa1e1e69c 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -61,15 +61,15 @@ import org.thingsboard.server.common.data.notification.rule.DefaultNotificationR import org.thingsboard.server.common.data.notification.rule.EscalatedNotificationRuleRecipientsConfig; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.AlarmAction; -import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmAssignmentNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmCommentNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig.AlarmAction; +import org.thingsboard.server.common.data.notification.rule.trigger.config.DeviceActivityNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.EntitiesLimitNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.EntityActionNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NewPlatformVersionNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.page.PageData; @@ -81,7 +81,7 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; -import org.thingsboard.server.common.msg.notification.trigger.NewPlatformVersionTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionTrigger; import org.thingsboard.server.dao.notification.DefaultNotifications; import org.thingsboard.server.dao.notification.NotificationRequestService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -109,10 +109,10 @@ import static org.assertj.core.api.Assertions.offset; import static org.assertj.core.api.InstanceOfAssertFactories.type; import static org.awaitility.Awaitility.await; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig.Action.ASSIGNED; -import static org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig.Action.UNASSIGNED; -import static org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent.ACTIVE; -import static org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent.INACTIVE; +import static org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmAssignmentNotificationRuleTriggerConfig.Action.ASSIGNED; +import static org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmAssignmentNotificationRuleTriggerConfig.Action.UNASSIGNED; +import static org.thingsboard.server.common.data.notification.rule.trigger.config.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent.ACTIVE; +import static org.thingsboard.server.common.data.notification.rule.trigger.config.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent.INACTIVE; @DaoSqlTest @TestPropertySource(properties = { diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationTargetApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationTargetApiTest.java index 480bbf939b..76b68bb9bf 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationTargetApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationTargetApiTest.java @@ -24,7 +24,7 @@ import org.springframework.test.web.servlet.ResultMatcher; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; -import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.EntityActionNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.platform.AllUsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter; diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleService.java index bd23f1c48d..d1b7513031 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleService.java @@ -19,7 +19,7 @@ import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java index c88ade5bb1..e7cb4f8c4f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRule.java @@ -26,8 +26,8 @@ import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.id.NotificationTemplateId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.validation.Length; import org.thingsboard.server.common.data.validation.NoXss; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRuleRecipientsConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRuleRecipientsConfig.java index d31ec098ca..c5bcf98302 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRuleRecipientsConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/NotificationRuleRecipientsConfig.java @@ -21,7 +21,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonSubTypes.Type; import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Data; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import javax.validation.constraints.NotNull; import java.io.Serializable; diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmAssignmentTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentTrigger.java similarity index 93% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmAssignmentTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentTrigger.java index 98ed43f886..11d24386bc 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmAssignmentTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentTrigger.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; @Data @Builder diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmCommentTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentTrigger.java similarity index 93% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmCommentTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentTrigger.java index d0b3bdd5de..65ad9c9619 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmCommentTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentTrigger.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; @Data @Builder diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmTrigger.java similarity index 92% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmTrigger.java index b395ba9ebe..674355150f 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/AlarmTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmTrigger.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; @Data @Builder diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/ApiUsageLimitTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/ApiUsageLimitTrigger.java similarity index 92% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/ApiUsageLimitTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/ApiUsageLimitTrigger.java index f21d3077ca..323f2b275f 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/ApiUsageLimitTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/ApiUsageLimitTrigger.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.ApiUsageRecordState; import org.thingsboard.server.common.data.ApiUsageStateValue; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; @Data @Builder diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/DeviceActivityTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/DeviceActivityTrigger.java similarity index 93% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/DeviceActivityTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/DeviceActivityTrigger.java index b426b6674b..0c0139410e 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/DeviceActivityTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/DeviceActivityTrigger.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; @Data @Builder diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/EntitiesLimitTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitTrigger.java similarity index 92% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/EntitiesLimitTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitTrigger.java index e6ce143fd0..3222e3fc6d 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/EntitiesLimitTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitTrigger.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; @Data @Builder diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/EntityActionTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntityActionTrigger.java similarity index 93% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/EntityActionTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntityActionTrigger.java index 47d1789fec..aaf61ab0bc 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/EntityActionTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntityActionTrigger.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; @Data @Builder diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NewPlatformVersionTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionTrigger.java similarity index 94% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NewPlatformVersionTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionTrigger.java index 2bb88a708b..9776bfb575 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NewPlatformVersionTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionTrigger.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; import org.thingsboard.server.common.data.UpdateMessage; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; @Data @Builder diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NotificationRuleTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTrigger.java similarity index 92% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NotificationRuleTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTrigger.java index 0cfc87a4df..2aac6fe75e 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/NotificationRuleTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTrigger.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import java.io.Serializable; diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RuleEngineComponentLifecycleEventTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventTrigger.java similarity index 93% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RuleEngineComponentLifecycleEventTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventTrigger.java index 56f4298b29..f1509eb2dc 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RuleEngineComponentLifecycleEventTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventTrigger.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; @Data diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmAssignmentNotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmAssignmentNotificationRuleTriggerConfig.java index 59ad9e5316..ce9ade2e6f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmAssignmentNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmAssignmentNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmCommentNotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmCommentNotificationRuleTriggerConfig.java index c34127b611..f0d8a7ef15 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmCommentNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmCommentNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmNotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmNotificationRuleTriggerConfig.java index 6118e9da00..318a99ffdd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/AlarmNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/AlarmNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/ApiUsageLimitNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/ApiUsageLimitNotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/ApiUsageLimitNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/ApiUsageLimitNotificationRuleTriggerConfig.java index d5ce9dff68..ec49e3828a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/ApiUsageLimitNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/ApiUsageLimitNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/DeviceActivityNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/DeviceActivityNotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/DeviceActivityNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/DeviceActivityNotificationRuleTriggerConfig.java index 8deeada7c0..7777955912 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/DeviceActivityNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/DeviceActivityNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/EntitiesLimitNotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/EntitiesLimitNotificationRuleTriggerConfig.java index a40ddfb081..0dfd8d0cc4 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntitiesLimitNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/EntitiesLimitNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntityActionNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/EntityActionNotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntityActionNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/EntityActionNotificationRuleTriggerConfig.java index 3a627a9e56..ed61d5eb94 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/EntityActionNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/EntityActionNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NewPlatformVersionNotificationRuleTriggerConfig.java similarity index 98% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NewPlatformVersionNotificationRuleTriggerConfig.java index 230be3b9d5..ebec3967d0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NewPlatformVersionNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NewPlatformVersionNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.Data; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerConfig.java index b0eec28858..9e6e757afd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerType.java similarity index 98% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerType.java index dff86f4ba1..3166c337e8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/NotificationRuleTriggerType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/NotificationRuleTriggerType.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.Getter; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java index c28e190cc9..005d86ac6f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/NotificationRuleProcessor.java b/common/message/src/main/java/org/thingsboard/server/common/msg/notification/NotificationRuleProcessor.java index 380773c1b0..8516a50b2f 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/NotificationRuleProcessor.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/notification/NotificationRuleProcessor.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.common.msg.notification; -import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; public interface NotificationRuleProcessor { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java b/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java new file mode 100644 index 0000000000..a233accf71 --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java @@ -0,0 +1,114 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.queue.notification; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Service; +import org.springframework.util.ConcurrentReferenceHashMap; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.notification.rule.NotificationRule; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.queue.util.PropertyUtils; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; + +import static org.springframework.util.ConcurrentReferenceHashMap.ReferenceType.SOFT; + +@Service +@RequiredArgsConstructor +@Slf4j +public class DefaultNotificationDeduplicationService implements NotificationDeduplicationService { + + private Map deduplicationDurations; + + private final CacheManager cacheManager; + private final ConcurrentMap localCache = new ConcurrentReferenceHashMap<>(16, SOFT); + + @Override + public boolean alreadyProcessed(NotificationRuleTrigger trigger) { + String deduplicationKey = trigger.getDeduplicationKey(); + return alreadyProcessed(trigger, deduplicationKey, true); + } + + @Override + public boolean alreadyProcessed(NotificationRuleTrigger trigger, NotificationRule rule) { + String deduplicationKey = getDeduplicationKey(trigger, rule); + return alreadyProcessed(trigger, deduplicationKey, false); + } + + private boolean alreadyProcessed(NotificationRuleTrigger trigger, String deduplicationKey, boolean onlyLocalCache) { + Long lastProcessedTs = localCache.get(deduplicationKey); + if (lastProcessedTs == null && !onlyLocalCache) { + Cache externalCache = cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE); + if (externalCache != null) { + lastProcessedTs = externalCache.get(deduplicationKey, Long.class); + } else { + log.warn("Sent notifications cache is not set up"); + } + } + + boolean alreadyProcessed = false; + if (lastProcessedTs != null) { + long deduplicationDuration = getDeduplicationDuration(trigger); + long passed = System.currentTimeMillis() - lastProcessedTs; + log.trace("Deduplicating trigger {} by key '{}'. Deduplication duration: {} ms, passed: {} ms", + trigger.getType(), deduplicationKey, deduplicationDuration, passed); + if (deduplicationDuration == 0 || passed <= deduplicationDuration) { + alreadyProcessed = true; + } + } + + if (!alreadyProcessed) { + lastProcessedTs = System.currentTimeMillis(); + } + localCache.put(deduplicationKey, lastProcessedTs); + if (!onlyLocalCache) { + Cache externalCache = cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE); + if (externalCache != null) { + externalCache.put(deduplicationKey, lastProcessedTs); + } + } + return alreadyProcessed; + } + + public static String getDeduplicationKey(NotificationRuleTrigger trigger, NotificationRule rule) { + return String.join("_", trigger.getDeduplicationKey(), rule.getDeduplicationKey()); + } + + private long getDeduplicationDuration(NotificationRuleTrigger trigger) { + return deduplicationDurations.computeIfAbsent(trigger.getType(), triggerType -> { + return trigger.getDefaultDeduplicationDuration(); + }); + } + + @Autowired + public void setDeduplicationDurations(@Value("${notification_system.rules.deduplication_durations:}") + String deduplicationDurationsStr) { + this.deduplicationDurations = new HashMap<>(); + PropertyUtils.getProps(deduplicationDurationsStr).forEach((triggerType, duration) -> { + this.deduplicationDurations.put(NotificationRuleTriggerType.valueOf(triggerType), Long.parseLong(duration)); + }); + } + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/TriggerTypeConfig.java b/common/queue/src/main/java/org/thingsboard/server/queue/notification/NotificationDeduplicationService.java similarity index 59% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/TriggerTypeConfig.java rename to common/queue/src/main/java/org/thingsboard/server/queue/notification/NotificationDeduplicationService.java index 6991bb1277..3ccc98ecb6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/TriggerTypeConfig.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/notification/NotificationDeduplicationService.java @@ -13,11 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.settings; +package org.thingsboard.server.queue.notification; -import lombok.Data; +import org.thingsboard.server.common.data.notification.rule.NotificationRule; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; + +public interface NotificationDeduplicationService { + + boolean alreadyProcessed(NotificationRuleTrigger trigger); + + boolean alreadyProcessed(NotificationRuleTrigger trigger, NotificationRule rule); -@Data -public class TriggerTypeConfig { - private long deduplicationDuration; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/notification/RemoteNotificationRuleProcessor.java b/common/queue/src/main/java/org/thingsboard/server/queue/notification/RemoteNotificationRuleProcessor.java index 617fdbb50e..5304056a88 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/notification/RemoteNotificationRuleProcessor.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/notification/RemoteNotificationRuleProcessor.java @@ -19,13 +19,9 @@ import com.google.protobuf.ByteString; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Service; -import org.springframework.util.ConcurrentReferenceHashMap; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.data.notification.settings.TriggerTypeConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; -import org.thingsboard.server.common.msg.notification.trigger.NotificationRuleTrigger; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.gen.transport.TransportProtos; @@ -35,35 +31,27 @@ import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.queue.util.DataDecodingEncodingService; -import java.util.EnumMap; -import java.util.Map; import java.util.UUID; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicBoolean; - -import static org.springframework.util.ConcurrentReferenceHashMap.ReferenceType.SOFT; @Service @ConditionalOnMissingBean(value = NotificationRuleProcessor.class, ignored = RemoteNotificationRuleProcessor.class) -@ConfigurationProperties(prefix = "notification-system.rules") @RequiredArgsConstructor @Slf4j public class RemoteNotificationRuleProcessor implements NotificationRuleProcessor { + private final NotificationDeduplicationService deduplicationService; private final TbQueueProducerProvider producerProvider; private final NotificationsTopicService notificationsTopicService; private final PartitionService partitionService; private final DataDecodingEncodingService encodingService; - private Map triggerTypesConfigs; - private final ConcurrentMap submittedTriggers = new ConcurrentReferenceHashMap<>(16, SOFT); - @Override public void process(NotificationRuleTrigger trigger) { - if (trigger.deduplicate() && alreadySubmitted(trigger)) { - return; - } try { + if (trigger.deduplicate() && deduplicationService.alreadyProcessed(trigger)) { + return; + } + log.debug("Submitting notification rule trigger: {}", trigger); TransportProtos.NotificationRuleProcessorMsg.Builder msg = TransportProtos.NotificationRuleProcessorMsg.newBuilder() .setTrigger(ByteString.copyFrom(encodingService.encode(trigger))); @@ -80,47 +68,4 @@ public class RemoteNotificationRuleProcessor implements NotificationRuleProcesso } } - private boolean alreadySubmitted(NotificationRuleTrigger trigger) { - String deduplicationKey = trigger.getDeduplicationKey(); - - AtomicBoolean alreadySubmitted = new AtomicBoolean(false); - submittedTriggers.compute(deduplicationKey, (key, lastSubmittedTs) -> { - long currentTs = System.currentTimeMillis(); - if (lastSubmittedTs == null) { - return currentTs; - } else { - long deduplicationDuration = getDeduplicationDuration(trigger); - long passed = currentTs - lastSubmittedTs; - if (deduplicationDuration == 0 || passed <= deduplicationDuration) { - log.trace("Notification rule trigger {} was already submitted {} ms ago, deduplication duration is {} ms. Key: '{}'", - trigger.getType(), passed, deduplicationDuration, deduplicationKey); - alreadySubmitted.set(true); - return lastSubmittedTs; - } else { - return currentTs; - } - } - }); - return alreadySubmitted.get(); - } - - private long getDeduplicationDuration(NotificationRuleTrigger trigger) { - if (triggerTypesConfigs == null) { - triggerTypesConfigs = new EnumMap<>(NotificationRuleTriggerType.class); - } - TriggerTypeConfig triggerTypeConfig = triggerTypesConfigs.computeIfAbsent(trigger.getType(), triggerType -> { - TriggerTypeConfig config = new TriggerTypeConfig(); - config.setDeduplicationDuration(trigger.getDefaultDeduplicationDuration()); - return config; - }); - return triggerTypeConfig.getDeduplicationDuration(); - } - - // set from ConfigurationProperties - public void setTriggerTypesConfigs(Map triggerTypesConfigs) { - if (triggerTypesConfigs != null) { - this.triggerTypesConfigs = new EnumMap<>(triggerTypesConfigs); - } - } - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationRuleEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationRuleEntity.java index 15283c9fc1..e7a4b6a571 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationRuleEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/NotificationRuleEntity.java @@ -25,8 +25,8 @@ import org.thingsboard.server.common.data.id.NotificationTemplateId; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleConfig; import org.thingsboard.server.common.data.notification.rule.NotificationRuleRecipientsConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.util.mapping.JsonStringType; diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRuleService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRuleService.java index 3cb92bd6ff..41cea42875 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRuleService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRuleService.java @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.entity.AbstractEntityService; diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java index 01f9f68ae4..4d4a1a63b8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java @@ -32,19 +32,19 @@ import org.thingsboard.server.common.data.notification.rule.DefaultNotificationR import org.thingsboard.server.common.data.notification.rule.EscalatedNotificationRuleRecipientsConfig; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmAssignmentNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmCommentNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmNotificationRuleTriggerConfig.AlarmAction; -import org.thingsboard.server.common.data.notification.rule.trigger.ApiUsageLimitNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent; -import org.thingsboard.server.common.data.notification.rule.trigger.EntitiesLimitNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.EntityActionNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionNotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmAssignmentNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmCommentNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig.AlarmAction; +import org.thingsboard.server.common.data.notification.rule.trigger.config.ApiUsageLimitNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.DeviceActivityNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.DeviceActivityNotificationRuleTriggerConfig.DeviceEvent; +import org.thingsboard.server.common.data.notification.rule.trigger.config.EntitiesLimitNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.EntityActionNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NewPlatformVersionNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig; import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleDao.java b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleDao.java index 90eee4ba63..17d09c4404 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationRuleDao.java @@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.id.NotificationTargetId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.Dao; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRuleDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRuleDao.java index aa3258287e..af9b8198e8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRuleDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationRuleDao.java @@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.id.NotificationTargetId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.DaoUtil; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRuleRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRuleRepository.java index 1bdfe57bba..9dfb34c18d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRuleRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRuleRepository.java @@ -22,7 +22,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import org.thingsboard.server.dao.ExportableEntityRepository; import org.thingsboard.server.dao.model.sql.NotificationRuleEntity; import org.thingsboard.server.dao.model.sql.NotificationRuleInfoEntity; From 93e8770023a759a951d3f29f8b4e850c6474e3e4 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 8 Jun 2023 18:28:57 +0300 Subject: [PATCH 101/421] Don't write to cache on each deduplication --- .../DefaultNotificationDeduplicationService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java b/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java index a233accf71..5284f1f1b4 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java @@ -69,8 +69,8 @@ public class DefaultNotificationDeduplicationService implements NotificationDedu } boolean alreadyProcessed = false; + long deduplicationDuration = getDeduplicationDuration(trigger); if (lastProcessedTs != null) { - long deduplicationDuration = getDeduplicationDuration(trigger); long passed = System.currentTimeMillis() - lastProcessedTs; log.trace("Deduplicating trigger {} by key '{}'. Deduplication duration: {} ms, passed: {} ms", trigger.getType(), deduplicationKey, deduplicationDuration, passed); @@ -84,9 +84,12 @@ public class DefaultNotificationDeduplicationService implements NotificationDedu } localCache.put(deduplicationKey, lastProcessedTs); if (!onlyLocalCache) { - Cache externalCache = cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE); - if (externalCache != null) { - externalCache.put(deduplicationKey, lastProcessedTs); + if (!alreadyProcessed || deduplicationDuration == 0) { + // if lastProcessedTs is changed or if deduplicating infinitely (so that cache value not removed by ttl) + Cache externalCache = cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE); + if (externalCache != null) { + externalCache.put(deduplicationKey, lastProcessedTs); + } } } return alreadyProcessed; From 505acb560f17beb2f74c7b922c8fa840ea6d5df1 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 9 Jun 2023 10:22:00 +0300 Subject: [PATCH 102/421] Removed exception throw on alarms not found for user on deleting --- .../server/service/entitiy/alarm/DefaultTbAlarmService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 141917f11f..fc3198a736 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -220,9 +220,6 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb AlarmQueryV2 alarmQuery = AlarmQueryV2.builder().assigneeId(user.getId()).pageLink(new TimePageLink(Integer.MAX_VALUE)).build(); try { List alarms = alarmService.findAlarmsV2(tenantId, alarmQuery).get(30, TimeUnit.SECONDS).getData(); - if (alarms.isEmpty()) { - throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND); - } for (AlarmInfo alarm : alarms) { AlarmApiCallResult result = alarmSubscriptionService.unassignAlarm(tenantId, alarm.getId(), getOrDefault(unassignTs)); if (!result.isSuccessful()) { From 5ddb62322ccab6a147d88c8f59d4d5cf68251c78 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 9 Jun 2023 13:47:51 +0300 Subject: [PATCH 103/421] Updated test --- .../thingsboard/server/controller/AlarmControllerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index c6b31ce683..f83deaad2e 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -551,7 +551,7 @@ public class AlarmControllerTest extends AbstractControllerTest { AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); Assert.assertNotNull(foundAlarm); Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs); beforeAssignmentTs = System.currentTimeMillis(); @@ -563,7 +563,7 @@ public class AlarmControllerTest extends AbstractControllerTest { foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); Assert.assertNotNull(foundAlarm); Assert.assertNull(foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs && foundAlarm.getAssignTs() < System.currentTimeMillis()); + Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs); } @Test From f191357b905f55fc7ec57adcdccff80470fa7aa5 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 9 Jun 2023 14:32:58 +0300 Subject: [PATCH 104/421] fixed NPE in Flow output node when it used after split array msg node --- .../thingsboard/server/common/msg/TbMsgProcessingCtx.java | 7 ++++++- .../rule/engine/transform/TbSplitArrayMsgNode.java | 6 ++++-- .../rule/engine/transform/TbSplitArrayMsgNodeTest.java | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java index 9010fc0b54..51cad0976f 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java @@ -64,7 +64,12 @@ public final class TbMsgProcessingCtx implements Serializable { } public TbMsgProcessingStackItem pop() { - return !stack.isEmpty() ? stack.removeLast() : null; + if (stack == null) { + throw new RuntimeException("Stack is null!"); + } else if (stack.isEmpty()) { + return null; + } + return stack.removeLast(); } public static TbMsgProcessingCtx fromProto(MsgProtos.TbMsgProcessingCtxProto ctx) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java index 7723d6028f..ae7ceade97 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java @@ -77,8 +77,10 @@ public class TbSplitArrayMsgNode implements TbNode { ctx.tellFailure(msg, e); } }); - data.forEach(msgNode -> ctx.enqueueForTellNext(TbMsg.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(msgNode)), - TbRelationTypes.SUCCESS, wrapper::onSuccess, wrapper::onFailure)); + data.forEach(msgNode -> { + TbMsg outMsg = TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(msgNode)); + ctx.enqueueForTellNext(outMsg, TbRelationTypes.SUCCESS, wrapper::onSuccess, wrapper::onFailure); + }); } } else { ctx.tellFailure(msg, new RuntimeException("Msg data is not a JSON Array!")); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java index 435ec91aaa..67ebf6f6fc 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java @@ -96,6 +96,7 @@ public class TbSplitArrayMsgNodeTest { ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); ArgumentCaptor exceptionCaptor = ArgumentCaptor.forClass(Exception.class); verify(ctx, never()).tellSuccess(any()); + verify(ctx, never()).enqueueForTellNext(any(), anyString(), any(), any()); verify(ctx, times(1)).tellFailure(newMsgCaptor.capture(), exceptionCaptor.capture()); assertThat(exceptionCaptor.getValue()).isInstanceOf(RuntimeException.class); From a85d0b6129e21219b62deda25f524418fa739a22 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 9 Jun 2023 15:13:33 +0300 Subject: [PATCH 105/421] fix_bug_switch: add validation to tbel --- .../script/api/tbel/DefaultTbelInvokeService.java | 6 ++++++ ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js | 10 +++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java index f98e33b615..5497e6cbbc 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java @@ -25,6 +25,7 @@ import com.google.common.util.concurrent.MoreExecutors; import lombok.Getter; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.mvel2.CompileException; import org.mvel2.ExecutionContext; import org.mvel2.MVEL; import org.mvel2.ParserContext; @@ -65,6 +66,8 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem protected final Map scriptIdToHash = new ConcurrentHashMap<>(); protected final Map scriptMap = new ConcurrentHashMap<>(); + private final String tbelSwitch = "switch"; + private final String tbelSwitchErrorMsg = "TBEL does not support the 'switch'."; protected Cache compiledScriptsCache; private SandboxedParserConfiguration parserConfig; @@ -181,6 +184,9 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem } return scriptId; } catch (Exception e) { + if (((CompileException) e).getExpr() != null && new String(((CompileException) e).getExpr()).contains(tbelSwitch)) { + e = new CompileException(tbelSwitchErrorMsg, ((CompileException) e).getExpr(), ((CompileException) e).getCursor(), e.getCause()); + } throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, e); } }); diff --git a/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js b/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js index bc22e806c3..13ec1d821f 100644 --- a/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js +++ b/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js @@ -5229,6 +5229,10 @@ var JSHINT = (function() { var a = [], p; while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { + if (state.tokens.next.value === "switch") { + warning("E067", state.tokens.next, "switch"); + break; + } if (state.tokens.next.id === ";") { p = peek(); @@ -9215,7 +9219,7 @@ var JSHINT = (function() { statements(0); } - if (state.tokens.next.id !== "(end)") { + if (state.tokens.next.id !== "(end)"&& state.tokens.next.value !== "switch") { quit("E041", state.tokens.curr); } @@ -11266,7 +11270,8 @@ var errors = { E064: "Super call may only be used within class method bodies.", E065: "Functions defined outside of strict mode with non-simple parameter lists may not " + "enable strict mode.", - E066: "Asynchronous iteration is only available with for-of loops." + E066: "Asynchronous iteration is only available with for-of loops.", + E067: "Expected without the 'switch' statement. TBEL does not support the 'switch' statement." }; var warnings = { @@ -11364,7 +11369,6 @@ var warnings = { W086: "Expected a 'break' statement before '{a}'.", W087: "Forgotten 'debugger' statement?", W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.", - // W288: "The syntax of function '{a}' is specific to TBEL, and is not supported by JS executor.", W089: "The body of a for in should be wrapped in an if statement to filter " + "unwanted properties from the prototype.", W090: "'{a}' is not a statement label.", From f534e2db6407ab949ffc013cd97abeb72cd75902 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 12 Jun 2023 13:05:10 +0300 Subject: [PATCH 106/421] fix_bug_switch: add validation to tbel mew msg --- ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js b/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js index 13ec1d821f..3a4b3d90b8 100644 --- a/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js +++ b/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js @@ -11271,7 +11271,7 @@ var errors = { E065: "Functions defined outside of strict mode with non-simple parameter lists may not " + "enable strict mode.", E066: "Asynchronous iteration is only available with for-of loops.", - E067: "Expected without the 'switch' statement. TBEL does not support the 'switch' statement." + E067: "Expected an 'if/else' and instead saw 'switch'. TBEL does not support the 'switch' statement." }; var warnings = { From e5a2712d8947b4b5c60433f5e8728700ed682ebc Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 12 Jun 2023 13:53:10 +0300 Subject: [PATCH 107/421] changed logic to ack msg if stack is null --- .../thingsboard/server/common/msg/TbMsgProcessingCtx.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java index 51cad0976f..4e25ae17dc 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java @@ -64,12 +64,7 @@ public final class TbMsgProcessingCtx implements Serializable { } public TbMsgProcessingStackItem pop() { - if (stack == null) { - throw new RuntimeException("Stack is null!"); - } else if (stack.isEmpty()) { - return null; - } - return stack.removeLast(); + return stack == null || stack.isEmpty() ? null : stack.removeLast(); } public static TbMsgProcessingCtx fromProto(MsgProtos.TbMsgProcessingCtxProto ctx) { From 9ff84067037d269e2f116084dbfe124ca36dfec5 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 12 Jun 2023 14:17:55 +0300 Subject: [PATCH 108/421] added code style fixes && moved duplicate code block to method --- .../thingsboard/rule/engine/math/TbMathNode.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java index 26ec656443..33692decc2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java @@ -157,7 +157,7 @@ public class TbMathNode implements TbNode { private ListenableFuture updateMsgAndDb(TbContext ctx, TbMsg msg, Optional msgBodyOpt, double result) { TbMathResult mathResultDef = config.getResult(); - String mathResultKey = !mathResultDef.getType().equals(CONSTANT) ? TbNodeUtils.processPattern(mathResultDef.getKey(), msg) : mathResultDef.getKey(); + String mathResultKey = getKeyFromTemplate(msg, mathResultDef.getType(), mathResultDef.getKey()); switch (mathResultDef.getType()) { case MESSAGE_BODY: return Futures.immediateFuture(addToBody(msg, mathResultDef, mathResultKey, msgBodyOpt, result)); @@ -183,7 +183,7 @@ public class TbMathNode implements TbNode { private ListenableFuture saveAttribute(TbContext ctx, TbMsg msg, double result, TbMathResult mathResultDef) { String attributeScope = getAttributeScope(mathResultDef.getAttributeScope()); if (isIntegerResult(mathResultDef, config.getOperation())) { - var value = toIntValue(mathResultDef, result); + var value = toIntValue(result); return ctx.getTelemetryService().saveAttrAndNotify( ctx.getTenantId(), msg.getOriginator(), attributeScope, mathResultDef.getKey(), value); } else { @@ -197,7 +197,7 @@ public class TbMathNode implements TbNode { return function.isIntegerResult() || mathResultDef.getResultValuePrecision() == 0; } - private long toIntValue(TbMathResult mathResultDef, double value) { + private long toIntValue(double value) { return (long) value; } @@ -234,7 +234,7 @@ public class TbMathNode implements TbNode { private TbMsg addToBody(TbMsg msg, TbMathResult mathResultDef, String mathResultKey, Optional msgBodyOpt, double result) { ObjectNode body = msgBodyOpt.get(); if (isIntegerResult(mathResultDef, config.getOperation())) { - body.put(mathResultKey, toIntValue(mathResultDef, result)); + body.put(mathResultKey, toIntValue(result)); } else { body.put(mathResultKey, toDoubleValue(mathResultDef, result)); } @@ -244,7 +244,7 @@ public class TbMathNode implements TbNode { private TbMsg addToMeta(TbMsg msg, TbMathResult mathResultDef, String mathResultKey, double result) { var md = msg.getMetaData(); if (isIntegerResult(mathResultDef, config.getOperation())) { - md.putValue(mathResultKey, Long.toString(toIntValue(mathResultDef, result))); + md.putValue(mathResultKey, Long.toString(toIntValue(result))); } else { md.putValue(mathResultKey, Double.toString(toDoubleValue(mathResultDef, result))); } @@ -348,7 +348,7 @@ public class TbMathNode implements TbNode { } private ListenableFuture resolveArguments(TbContext ctx, TbMsg msg, Optional msgBodyOpt, TbMathArgument arg) { - String argKey = !arg.getType().equals(CONSTANT) ? TbNodeUtils.processPattern(arg.getKey(), msg) : arg.getKey(); + String argKey = getKeyFromTemplate(msg, arg.getType(), arg.getKey()); switch (arg.getType()) { case CONSTANT: return Futures.immediateFuture(TbMathArgumentValue.constant(arg)); @@ -371,6 +371,10 @@ public class TbMathNode implements TbNode { } + private String getKeyFromTemplate(TbMsg msg, TbMathArgumentType type, String keyPattern) { + return CONSTANT.equals(type) ? keyPattern : TbNodeUtils.processPattern(keyPattern, msg); + } + private String getAttributeScope(String attrScope) { return StringUtils.isEmpty(attrScope) ? DataConstants.SERVER_SCOPE : attrScope; } From a5de29c1f4731762332dd25284b47006cf76b224 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 12 Jun 2023 15:50:49 +0300 Subject: [PATCH 109/421] code readability fix --- .../thingsboard/server/common/msg/TbMsgProcessingCtx.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java index 4e25ae17dc..1b1cbcdf54 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgProcessingCtx.java @@ -64,7 +64,10 @@ public final class TbMsgProcessingCtx implements Serializable { } public TbMsgProcessingStackItem pop() { - return stack == null || stack.isEmpty() ? null : stack.removeLast(); + if (stack == null || stack.isEmpty()) { + return null; + } + return stack.removeLast(); } public static TbMsgProcessingCtx fromProto(MsgProtos.TbMsgProcessingCtxProto ctx) { From 7f0c5f219b5bf7e91a09acd724c3659c736d9f42 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 12 Jun 2023 19:00:59 +0300 Subject: [PATCH 110/421] fix_bug_switch: add CompileException --- .../script/api/tbel/DefaultTbelInvokeService.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java index 5497e6cbbc..0e56612c21 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java @@ -183,11 +183,13 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem lock.unlock(); } return scriptId; - } catch (Exception e) { - if (((CompileException) e).getExpr() != null && new String(((CompileException) e).getExpr()).contains(tbelSwitch)) { - e = new CompileException(tbelSwitchErrorMsg, ((CompileException) e).getExpr(), ((CompileException) e).getCursor(), e.getCause()); + } catch (CompileException ce) { + if ( ce.getExpr() != null && new String(ce.getExpr()).contains(tbelSwitch)) { + ce = new CompileException(tbelSwitchErrorMsg, ce.getExpr(), ce.getCursor(), ce.getCause()); } - throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, e); + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, ce); + } catch (Exception e) { + throw new RuntimeException(e); } }); } From fff879a6cf3c9aae3d1d985012cfd323d651a187 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 12 Jun 2023 19:24:30 +0300 Subject: [PATCH 111/421] UI: Fixed oauth2 form array trackby --- .../home/pages/admin/oauth2-settings.component.html | 8 ++++---- .../modules/home/pages/admin/oauth2-settings.component.ts | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html index bc5ffd3ae5..7cc06bc4af 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html @@ -37,7 +37,7 @@
- + @@ -59,7 +59,7 @@
-
@@ -146,7 +146,7 @@ admin.oauth2.no-mobile-apps
-
@@ -203,7 +203,7 @@
admin.oauth2.providers
- diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts index 34f35611b4..d274f6728e 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts @@ -570,4 +570,8 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha trackByParams(index: number): number { return index; } + + trackByItem(i, item) { + return item; + } } From 6d69c9b2138cdad0b767d63c6cce858957368e22 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 13 Jun 2023 11:39:48 +0300 Subject: [PATCH 112/421] fix_bug_switch: add CompileException2 --- .../thingsboard/script/api/tbel/DefaultTbelInvokeService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java index 0e56612c21..bbf441a659 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java @@ -189,7 +189,7 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem } throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, ce); } catch (Exception e) { - throw new RuntimeException(e); + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, e); } }); } From 7ac6eac802059a303880eb9ed468b927985505f7 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 13 Jun 2023 12:13:51 +0300 Subject: [PATCH 113/421] UI: Fixed oauth2 mail server settings --- .../app/modules/home/pages/admin/mail-server.component.html | 2 +- .../src/app/modules/home/pages/admin/mail-server.component.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.html b/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.html index 2762e0d43a..926ad64644 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.html @@ -331,7 +331,7 @@
diff --git a/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.ts b/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.ts index 6815c81e31..d95c3d6096 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/mail-server.component.ts @@ -416,6 +416,9 @@ export class MailServerComponent extends PageComponent implements OnInit, OnDest private get mailSettingsFormValue(): MailServerSettings { const formValue = this.mailSettings.getRawValue() as Required; delete formValue.changePassword; + if (!isDefinedAndNotNull(formValue.password)) { + delete formValue.password; + } return formValue; } From 0bd7f74c47e3b17a14a30189749d56c74a7771cb Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 13 Jun 2023 14:12:54 +0300 Subject: [PATCH 114/421] Fix issues --- .../rule/trigger/RateLimitsTriggerProcessor.java | 6 +++--- application/src/main/resources/thingsboard.yml | 2 +- .../notification/NotificationRuleApiTest.java | 12 ++++++------ .../rule}/trigger/RateLimitsTrigger.java | 4 ++-- .../RateLimitsNotificationRuleTriggerConfig.java | 2 +- .../DefaultNotificationDeduplicationService.java | 14 +++++++++++--- .../transport/service/DefaultTransportService.java | 2 +- .../dao/notification/DefaultNotifications.java | 2 +- .../dao/util/limits/DefaultRateLimitService.java | 2 +- .../src/main/resources/tb-vc-executor.yml | 6 ++---- .../coap/src/main/resources/tb-coap-transport.yml | 6 ++---- .../http/src/main/resources/tb-http-transport.yml | 6 ++---- .../src/main/resources/tb-lwm2m-transport.yml | 6 ++---- .../mqtt/src/main/resources/tb-mqtt-transport.yml | 6 ++---- .../snmp/src/main/resources/tb-snmp-transport.yml | 6 ++---- 15 files changed, 39 insertions(+), 43 deletions(-) rename common/{message/src/main/java/org/thingsboard/server/common/msg/notification => data/src/main/java/org/thingsboard/server/common/data/notification/rule}/trigger/RateLimitsTrigger.java (94%) rename common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/{ => config}/RateLimitsNotificationRuleTriggerConfig.java (99%) diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RateLimitsTriggerProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RateLimitsTriggerProcessor.java index 910ef4866f..bec1502427 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RateLimitsTriggerProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/RateLimitsTriggerProcessor.java @@ -21,10 +21,10 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.info.RateLimitsNotificationInfo; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; -import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.RateLimitsNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.util.CollectionsUtil; -import org.thingsboard.server.common.msg.notification.trigger.RateLimitsTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsTrigger; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.tenant.TenantService; diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 962b1f4cff..e7fbbd2a3d 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1277,7 +1277,7 @@ notification_system: thread_pool_size: "${TB_NOTIFICATION_SYSTEM_THREAD_POOL_SIZE:10}" rules: # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' - deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:NEW_PLATFORM_VERSION:0;}" + deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:NEW_PLATFORM_VERSION:0;RATE_LIMITS:14400000;}" management: endpoints: diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index 7f66dd78df..f89730b689 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -64,6 +64,8 @@ import org.thingsboard.server.common.data.notification.rule.DefaultNotificationR import org.thingsboard.server.common.data.notification.rule.EscalatedNotificationRuleRecipientsConfig; import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.rule.NotificationRuleInfo; +import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsTrigger; import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmAssignmentNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmCommentNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.AlarmNotificationRuleTriggerConfig; @@ -73,7 +75,7 @@ import org.thingsboard.server.common.data.notification.rule.trigger.config.Entit import org.thingsboard.server.common.data.notification.rule.trigger.config.EntityActionNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.NewPlatformVersionNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; -import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.RateLimitsNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.platform.AffectedTenantAdministratorsFilter; import org.thingsboard.server.common.data.notification.targets.platform.SystemAdministratorsFilter; @@ -87,14 +89,12 @@ import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; -import org.thingsboard.server.common.data.notification.rule.trigger.NewPlatformVersionTrigger; -import org.thingsboard.server.common.msg.notification.trigger.RateLimitsTrigger; import org.thingsboard.server.dao.notification.DefaultNotifications; import org.thingsboard.server.dao.notification.NotificationRequestService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.dao.util.limits.RateLimitService; -import org.thingsboard.server.service.notification.rule.DefaultNotificationRuleProcessor; +import org.thingsboard.server.queue.notification.DefaultNotificationDeduplicationService; import org.thingsboard.server.service.notification.rule.cache.DefaultNotificationRulesCache; import org.thingsboard.server.service.state.DeviceStateService; import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; @@ -125,7 +125,7 @@ import static org.thingsboard.server.common.data.notification.rule.trigger.confi @DaoSqlTest @TestPropertySource(properties = { "transport.http.enabled=true", - "notification_system.rules.trigger_types_configs.RATE_LIMITS.deduplication_duration=10000" + "notification_system.rules.deduplication_durations=RATE_LIMITS:10000" }) public class NotificationRuleApiTest extends AbstractNotificationApiTest { @@ -700,7 +700,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { .api(LimitedApi.ENTITY_EXPORT) .limitLevel(tenantId) .build(); - assertThat(DefaultNotificationRuleProcessor.getDeduplicationKey(expectedTrigger, rule)) + assertThat(DefaultNotificationDeduplicationService.getDeduplicationKey(expectedTrigger, rule)) .isEqualTo("RATE_LIMITS:TENANT:" + tenantId + ":ENTITY_EXPORT_" + target.getId() + ":ENTITY_EXPORT,TRANSPORT_MESSAGES_PER_DEVICE"); diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RateLimitsTrigger.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsTrigger.java similarity index 94% rename from common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RateLimitsTrigger.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsTrigger.java index afb06bb8d1..3941ade824 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/notification/trigger/RateLimitsTrigger.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsTrigger.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.msg.notification.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger; import lombok.Builder; import lombok.Data; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.limit.LimitedApi; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType; +import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; import java.util.concurrent.TimeUnit; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsNotificationRuleTriggerConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/RateLimitsNotificationRuleTriggerConfig.java similarity index 99% rename from common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsNotificationRuleTriggerConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/RateLimitsNotificationRuleTriggerConfig.java index f5ea83c47d..6cb447bc8f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/RateLimitsNotificationRuleTriggerConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/rule/trigger/config/RateLimitsNotificationRuleTriggerConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.notification.rule.trigger; +package org.thingsboard.server.common.data.notification.rule.trigger.config; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java b/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java index 5284f1f1b4..871408ac40 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/notification/DefaultNotificationDeduplicationService.java @@ -31,6 +31,7 @@ import org.thingsboard.server.queue.util.PropertyUtils; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentMap; import static org.springframework.util.ConcurrentReferenceHashMap.ReferenceType.SOFT; @@ -42,7 +43,8 @@ public class DefaultNotificationDeduplicationService implements NotificationDedu private Map deduplicationDurations; - private final CacheManager cacheManager; + @Autowired(required = false) + private CacheManager cacheManager; private final ConcurrentMap localCache = new ConcurrentReferenceHashMap<>(16, SOFT); @Override @@ -60,7 +62,7 @@ public class DefaultNotificationDeduplicationService implements NotificationDedu private boolean alreadyProcessed(NotificationRuleTrigger trigger, String deduplicationKey, boolean onlyLocalCache) { Long lastProcessedTs = localCache.get(deduplicationKey); if (lastProcessedTs == null && !onlyLocalCache) { - Cache externalCache = cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE); + Cache externalCache = getExternalCache(); if (externalCache != null) { lastProcessedTs = externalCache.get(deduplicationKey, Long.class); } else { @@ -86,7 +88,7 @@ public class DefaultNotificationDeduplicationService implements NotificationDedu if (!onlyLocalCache) { if (!alreadyProcessed || deduplicationDuration == 0) { // if lastProcessedTs is changed or if deduplicating infinitely (so that cache value not removed by ttl) - Cache externalCache = cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE); + Cache externalCache = getExternalCache(); if (externalCache != null) { externalCache.put(deduplicationKey, lastProcessedTs); } @@ -105,6 +107,12 @@ public class DefaultNotificationDeduplicationService implements NotificationDedu }); } + private Cache getExternalCache() { + return Optional.ofNullable(cacheManager) + .map(cacheManager -> cacheManager.getCache(CacheConstants.SENT_NOTIFICATIONS_CACHE)) + .orElse(null); + } + @Autowired public void setDeduplicationDurations(@Value("${notification_system.rules.deduplication_durations:}") String deduplicationDurationsStr) { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 69e4de7b74..3b827edbae 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -53,7 +53,7 @@ import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; -import org.thingsboard.server.common.msg.notification.trigger.RateLimitsTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsTrigger; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.session.SessionMsgType; diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java index abe20e245d..a6c558a388 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotifications.java @@ -45,7 +45,7 @@ import org.thingsboard.server.common.data.notification.rule.trigger.config.Entit import org.thingsboard.server.common.data.notification.rule.trigger.config.NewPlatformVersionNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.NotificationRuleTriggerType; -import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsNotificationRuleTriggerConfig; +import org.thingsboard.server.common.data.notification.rule.trigger.config.RateLimitsNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.rule.trigger.config.RuleEngineComponentLifecycleEventNotificationRuleTriggerConfig; import org.thingsboard.server.common.data.notification.template.NotificationTemplate; import org.thingsboard.server.common.data.notification.template.NotificationTemplateConfig; diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java b/dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java index ede6855d5e..12201712c1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java @@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; -import org.thingsboard.server.common.msg.notification.trigger.RateLimitsTrigger; +import org.thingsboard.server.common.data.notification.rule.trigger.RateLimitsTrigger; import org.thingsboard.server.common.msg.tools.TbRateLimits; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 75f9e09d3c..094e0e2099 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -206,7 +206,5 @@ service: notification_system: rules: - trigger_types_configs: - RATE_LIMITS: - # In milliseconds, 4 hours by default - deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" + # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' + deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:RATE_LIMITS:14400000;}" diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 0a7635ff40..b9db930657 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -315,7 +315,5 @@ management: notification_system: rules: - trigger_types_configs: - RATE_LIMITS: - # In milliseconds, 4 hours by default - deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" + # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' + deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:RATE_LIMITS:14400000;}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index fa2e033d0c..bff7adb561 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -300,7 +300,5 @@ management: notification_system: rules: - trigger_types_configs: - RATE_LIMITS: - # In milliseconds, 4 hours by default - deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" + # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' + deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:RATE_LIMITS:14400000;}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 6b90d60b3d..ae8f0138a7 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -382,7 +382,5 @@ management: notification_system: rules: - trigger_types_configs: - RATE_LIMITS: - # In milliseconds, 4 hours by default - deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" + # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' + deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:RATE_LIMITS:14400000;}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 031d01e987..076dde0234 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -330,7 +330,5 @@ management: notification_system: rules: - trigger_types_configs: - RATE_LIMITS: - # In milliseconds, 4 hours by default - deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" + # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' + deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:RATE_LIMITS:14400000;}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index b6bffd8d4b..c68c9c56a8 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -280,7 +280,5 @@ management: notification_system: rules: - trigger_types_configs: - RATE_LIMITS: - # In milliseconds, 4 hours by default - deduplication_duration: "${RATE_LIMITS_NOTIFICATION_RULE_DEDUPLICATION_DURATION:14400000}" + # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' + deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:RATE_LIMITS:14400000;}" From 50d3a6d92500ed63ee7f59585c617866e6c1329e Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 14 Jun 2023 13:10:52 +0300 Subject: [PATCH 115/421] tbel: add parseBytesToFloat --- .../thingsboard/script/api/tbel/TbUtils.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index 6c50561363..10d48d582a 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -15,6 +15,7 @@ */ package org.thingsboard.script.api.tbel; +import com.google.common.primitives.Bytes; import org.mvel2.ExecutionContext; import org.mvel2.ParserConfiguration; import org.mvel2.execution.ExecutionArrayList; @@ -81,6 +82,14 @@ public class TbUtils { byte[].class, int.class, int.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", byte[].class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", + byte[].class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", + byte[].class, int.class))); + parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", + List.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", + List.class, int.class))); parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", double.class, int.class))); parserConfig.addImport("hexToBytes", new MethodStub(TbUtils.class.getMethod("hexToBytes", @@ -293,6 +302,33 @@ public class TbUtils { return bb.getInt(); } + public static float parseBytesToFloat(byte[] data, int offset) { + return parseBytesToFloat(data, offset, true); + } + + public static float parseBytesToFloat(byte[] data, int offset, boolean bigEndian) { + if (data != null && data.length > 0) { + int length = 4; + if (offset > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); + } + if ((offset + length) > data.length) { + throw new IllegalArgumentException("Default length is always 4 bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); + } + int i = parseBytesToInt(data, offset, length, bigEndian); + return Float.intBitsToFloat(i); + } else { + throw new IllegalArgumentException("Array is null or array length is 0!"); + } + } + public static float parseBytesToFloat(List data, int offset) { + return parseBytesToFloat(data, offset, true); + } + + public static float parseBytesToFloat(List data, int offset, boolean bigEndian) { + return parseBytesToFloat(Bytes.toArray(data), offset, bigEndian); + } + public static String bytesToHex(ExecutionArrayList bytesList) { byte[] bytes = new byte[bytesList.size()]; for (int i = 0; i < bytesList.size(); i++) { From d7c3f1647a71bd8a466ada3eb9d1d9e996edf24e Mon Sep 17 00:00:00 2001 From: kalytka Date: Wed, 14 Jun 2023 14:57:16 +0300 Subject: [PATCH 116/421] Updated enrichment rule nodes UI --- .../resources/public/static/rulenode/rulenode-core-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js index 414c734227..b143649869 100644 --- a/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js +++ b/rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js @@ -1 +1 @@ -System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","tslib","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@angular/material/slide-toggle","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@angular/material/button-toggle","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,v,F,L,k,T,I,N,S,q,M,A,G,E,D,V,w,P,R,O,H,K,B,U,z,_,j,$,Q,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,ve,Fe,Le,ke,Te,Ie,Ne,Se,qe,Me,Ae,Ge,Ee,De,Ve,we,Pe,Re,Oe,He,Ke,Be,Ue,ze,_e,je;return{setters:[function(e){t=e,n=e.Component,r=e.Pipe,o=e.ViewChild,a=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.coerceBoolean,C=e.MessageType,v=e.messageTypeNames,F=e,L=e.SharedModule,k=e.AggregationType,T=e.aggregationTranslations,I=e.NotificationType,N=e.SlackChanelType,S=e.SlackChanelTypesTranslateMap,q=e.alarmStatusTranslations,M=e.AlarmStatus},function(e){A=e},function(e){G=e,E=e.Validators,D=e.NgControl,V=e.NG_VALUE_ACCESSOR,w=e.NG_VALIDATORS,P=e.FormControl,R=e.UntypedFormControl},function(e){O=e,H=e.CommonModule},function(e){K=e},function(e){B=e},function(e){U=e},function(e){z=e},function(e){_=e},function(e){j=e},function(e){$=e},function(e){Q=e},function(e){J=e},function(e){Y=e.getCurrentAuthState,W=e,X=e.isDefinedAndNotNull,Z=e.isObject,ee=e.isNotEmptyStr},function(e){te=e},function(e){ne=e},function(e){re=e},function(e){oe=e.ENTER,ae=e.COMMA,ie=e.SEMICOLON},function(e){le=e},function(e){se=e},function(e){me=e},function(e){ue=e},function(e){pe=e.coerceBooleanProperty},function(e){de=e},function(e){ce=e},function(e){fe=e},function(e){ge=e},function(e){ye=e},function(e){xe=e.tap,be=e.map,he=e.mergeMap,Ce=e.takeUntil,ve=e.startWith,Fe=e.share,Le=e.distinctUntilChanged},function(e){ke=e},function(e){Te=e},function(e){Ie=e.of,Ne=e.Subject},function(e){Se=e},function(e){qe=e.HomeComponentsModule},function(e){Me=e.__decorate},function(e){Ae=e},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){we=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e},function(e){Be=e},function(e){Ue=e},function(e){ze=e},function(e){_e=e},function(e){je=e}],execute:function(){class $e extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",$e),$e.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$e,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$e.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$e,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$e,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qe{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Qe),Qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,deps:[{token:j.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Qe.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Qe,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qe,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:j.DomSanitizer}]}});class Je extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[E.required,E.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[E.required,E.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Je,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Je,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ye,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ye,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[E.required]]})}}e("CheckPointConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:We,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:We,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Xe extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[E.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[E.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[E.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.clearAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",r=this.clearAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.clearAlarmConfigForm.get(t).setValue(e)}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xe,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Ze extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[oe,ae,ie],this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([E.required]),this.createAlarmConfigForm.get("severity").setValidators([E.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[E.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[E.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",r=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ze,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ze,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[E.required]],entityType:[e?e.entityType:null,[E.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[E.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[E.required,E.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([E.required,E.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:et,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:et,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[E.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[E.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[E.required,E.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([E.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,E.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,E.required]})}}e("DeviceProfileConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nt,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class rt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[E.required,E.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[E.required,E.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",r=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var ot;e("GeneratorConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rt,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rt,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rt,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(ot||(ot={}));const at=new Map([[ot.CUSTOMER,"tb.rulenode.originator-customer"],[ot.TENANT,"tb.rulenode.originator-tenant"],[ot.RELATED,"tb.rulenode.originator-related"],[ot.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[ot.ENTITY,"tb.rulenode.originator-entity"]]);var it;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(it||(it={}));const lt=new Map([[it.CIRCLE,"tb.rulenode.perimeter-circle"],[it.POLYGON,"tb.rulenode.perimeter-polygon"]]);var st;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(st||(st={}));const mt=new Map([[st.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[st.SECONDS,"tb.rulenode.time-unit-seconds"],[st.MINUTES,"tb.rulenode.time-unit-minutes"],[st.HOURS,"tb.rulenode.time-unit-hours"],[st.DAYS,"tb.rulenode.time-unit-days"]]);var ut;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(ut||(ut={}));const pt=new Map([[ut.METER,"tb.rulenode.range-unit-meter"],[ut.KILOMETER,"tb.rulenode.range-unit-kilometer"],[ut.FOOT,"tb.rulenode.range-unit-foot"],[ut.MILE,"tb.rulenode.range-unit-mile"],[ut.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var dt,ct;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(dt||(dt={})),function(e){e.NAME="name",e.CREATED_TIME="createdTime",e.TYPE="type",e.FIRST_NAME="firstName",e.LAST_NAME="lastName",e.EMAIL="email",e.TITLE="title",e.COUNTRY="county",e.STATE="state",e.CITY="city",e.ADDRESS="address",e.ADDRESS2="address2",e.ZIP="zip",e.PHONE="phone",e.LABEL="label"}(ct||(ct={}));const ft=new Map([[ct.NAME,"tb.rulenode.name"],[ct.CREATED_TIME,"tb.rulenode.created-time"],[ct.TYPE,"tb.rulenode.type"],[ct.FIRST_NAME,"tb.rulenode.first-name"],[ct.LAST_NAME,"tb.rulenode.last-name"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.LABEL,"tb.rulenode.label"]]),gt=new Map([[dt.ID,"tb.rulenode.entity-details-id"],[dt.TITLE,"tb.rulenode.entity-details-title"],[dt.COUNTRY,"tb.rulenode.entity-details-country"],[dt.STATE,"tb.rulenode.entity-details-state"],[dt.CITY,"tb.rulenode.entity-details-city"],[dt.ZIP,"tb.rulenode.entity-details-zip"],[dt.ADDRESS,"tb.rulenode.entity-details-address"],[dt.ADDRESS2,"tb.rulenode.entity-details-address2"],[dt.PHONE,"tb.rulenode.entity-details-phone"],[dt.EMAIL,"tb.rulenode.entity-details-email"],[dt.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var yt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(yt||(yt={}));const xt=new Map([[yt.FIRST,"tb.rulenode.first"],[yt.LAST,"tb.rulenode.last"],[yt.ALL,"tb.rulenode.all"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const Ct=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var vt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(vt||(vt={}));const Ft=new Map([[vt.STANDARD,"tb.rulenode.sqs-queue-standard"],[vt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Lt=["anonymous","basic","cert.PEM"],kt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Tt=["sas","cert.PEM"],It=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Nt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Nt||(Nt={}));const St=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],qt=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Mt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Mt||(Mt={}));const At=new Map([[Mt.CUSTOM,{value:Mt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Mt.ADD,{value:Mt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Mt.SUB,{value:Mt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Mt.MULT,{value:Mt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Mt.DIV,{value:Mt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Mt.SIN,{value:Mt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Mt.SINH,{value:Mt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Mt.COS,{value:Mt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Mt.COSH,{value:Mt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Mt.TAN,{value:Mt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Mt.TANH,{value:Mt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Mt.ACOS,{value:Mt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Mt.ASIN,{value:Mt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Mt.ATAN,{value:Mt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Mt.ATAN2,{value:Mt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Mt.EXP,{value:Mt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Mt.EXPM1,{value:Mt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Mt.SQRT,{value:Mt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Mt.CBRT,{value:Mt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Mt.GET_EXP,{value:Mt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Mt.HYPOT,{value:Mt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Mt.LOG,{value:Mt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Mt.LOG10,{value:Mt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Mt.LOG1P,{value:Mt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Mt.CEIL,{value:Mt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Mt.FLOOR,{value:Mt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Mt.FLOOR_DIV,{value:Mt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Mt.FLOOR_MOD,{value:Mt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Mt.ABS,{value:Mt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Mt.MIN,{value:Mt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Mt.MAX,{value:Mt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Mt.POW,{value:Mt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Mt.SIGNUM,{value:Mt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Mt.RAD,{value:Mt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Mt.DEG,{value:Mt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Gt,Et,Dt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Gt||(Gt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Et||(Et={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Dt||(Dt={}));const Vt=new Map([[Gt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Gt.TIME_SERIES,"tb.rulenode.time-series-type"],[Gt.CONSTANT,"tb.rulenode.constant-type"],[Gt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Gt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),wt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Pt,Rt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Pt||(Pt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Rt||(Rt={}));const Ot=new Map([[Pt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Pt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Pt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=it,this.perimeterTypes=Object.keys(it),this.perimeterTypeTranslationMap=lt,this.rangeUnits=Object.keys(ut),this.rangeUnitTranslationMap=pt,this.timeUnits=Object.keys(st),this.timeUnitsTranslationMap=mt}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[E.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[E.required]],perimeterType:[e?e.perimeterType:null,[E.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[E.required,E.min(1),E.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[E.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[E.required,E.min(1),E.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[E.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([E.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==it.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([E.required,E.min(-90),E.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([E.required,E.min(-180),E.max(180)]),this.geoActionConfigForm.get("range").setValidators([E.required,E.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([E.required])),t||n!==it.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([E.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ht,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ht,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Kt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",r=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",Kt),Kt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Kt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Bt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[E.required,E.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[E.required]]})}}e("MsgCountConfigComponent",Bt),Bt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Bt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bt,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[E.required,E.min(1),E.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([E.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([E.required,E.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ut,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ut,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]]})}}e("PushToCloudConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:zt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]]})}}e("PushToEdgeConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:_t,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_t,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:jt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[E.required,E.min(0)]]})}}e("RpcRequestConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$t,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$t,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required]],value:[e[n],[E.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[E.required]],value:["",[E.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigOldComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:V,useExisting:a((()=>Qt)),multi:!0},{provide:w,useExisting:a((()=>Qt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:V,useExisting:a((()=>Qt)),multi:!0},{provide:w,useExisting:a((()=>Qt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[E.required,E.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[E.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Jt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jt,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[E.required,E.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Yt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Wt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[E.required,E.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[E.required,E.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Wt,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wt,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[E.required]],keys:[e?e.keys:null,[E.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xt,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class Zt extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup())}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=At,this.ArgumentType=Gt,this.attributeScopeMap=Ot,this.argumentTypeResultMap=Vt,this.arguments=Object.values(Gt),this.attributeScope=Object.values(Pt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({}),this.argumentsFormGroup.addControl("arguments",this.fb.array([])),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):this.argumentsFormGroup.enable({emitEvent:!1})}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()));const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t)),this.setupArgumentsFormGroup(),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()})))}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(){const e=this.argumentsFormGroup.get("arguments"),t=this.createArgumentControl(null,e.length);e.push(t)}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Mt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([E.minLength(this.minArgs),E.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!0}),n.get("defaultValue").updateValueAndValidity({emitEvent:!0})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Gt.ATTRIBUTE?e.get("attributeScope").enable():e.get("attributeScope").disable(),t&&t!==Gt.CONSTANT?e.get("defaultValue").enable():e.get("defaultValue").disable()}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(wt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Zt,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:V,useExisting:a((()=>Zt)),multi:!0},{provide:w,useExisting:a((()=>Zt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"],dependencies:[{kind:"directive",type:O.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ge.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:ge.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:ye.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:ye.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:ye.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zt,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:V,useExisting:a((()=>Zt)),multi:!0},{provide:w,useExisting:a((()=>Zt)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n
\n \n
\n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:10px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class en extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...At.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(xe((e=>{let t;t="string"==typeof e&&Mt[e]?Mt[e]:null,this.updateView(t)})),be((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=At.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:en,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:en,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:V,useExisting:a((()=>en)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:en,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:V,useExisting:a((()=>en)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Mt,this.ArgumentTypeResult=Et,this.argumentTypeResultMap=Vt,this.attributeScopeMap=Ot,this.argumentsResult=Object.values(Et),this.attributeScopeResult=Object.values(Rt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[E.required]],arguments:[e?e.arguments:null,[E.required]],customFunction:[e?e.customFunction:"",[E.required]],result:this.fb.group({type:[e?e.result.type:null,[E.required]],attributeScope:[e?e.result.attributeScope:null],key:[e?e.result.key:"",[E.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result").get("type").value;t===Mt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Et.ATTRIBUTE?this.mathFunctionConfigForm.get("result").get("attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result").get("attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result").get("attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tn,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Zt,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:en,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tn,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block;margin-top:16px}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nn{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[E.required,E.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(xe((e=>{this.updateView(e)})),be((e=>e||"")),he((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,Ie(this.messageTypes).pipe(be((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nn,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:V,useExisting:a((()=>nn)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:V,useExisting:a((()=>nn)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Ne,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=yt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=xt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[X(e?.interval)?e.interval:null,[E.required,E.min(1)]],strategy:[X(e?.strategy)?e.strategy:null,[E.required]],outMsgType:[X(e?.outMsgType)?e.outMsgType:null,[E.required]],queueName:[X(e?.queueName)?e.queueName:null,[E.required]],maxPendingMsgs:[X(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[E.required,E.min(1),E.max(1e3)]],maxRetries:[X(e?.maxRetries)?e.maxRetries:null,[E.required,E.min(0),E.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:nn,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class on extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:on,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:on,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:V,useExisting:a((()=>on)),multi:!0},{provide:w,useExisting:a((()=>on)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n {{ hintText }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),Me([h()],on.prototype,"disabled",void 0),Me([h()],on.prototype,"uniqueKeyValuePairValidator",void 0),Me([h()],on.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:V,useExisting:a((()=>on)),multi:!0},{provide:w,useExisting:a((()=>on)),multi:!0}],template:'
\n
\n \n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n {{ hintText }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class an{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne}ngOnInit(){this.slideToggleControlGroup=this.fb.group({slideToggleControl:[null,[]]}),this.slideToggleControlGroup.get("slideToggleControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.slideToggleControlGroup.get("slideToggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SlideToggleComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:an,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:an,selector:"tb-slide-toggle",inputs:{slideToggleName:"slideToggleName",slideToggleTooltip:"slideToggleTooltip"},providers:[{provide:V,useExisting:a((()=>an)),multi:!0}],ngImport:t,template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"],dependencies:[{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:De.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-slide-toggle",providers:[{provide:V,useExisting:a((()=>an)),multi:!0}],template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{slideToggleName:[{type:i}],slideToggleTooltip:[{type:i}]}});class ln extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[E.min(1)]],relationType:[null],deviceTypes:[null,[E.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ln,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ln,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>ln)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["label","required","disabled","entityType"]},{kind:"component",type:Ee.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","required","disabled","subscriptSizing"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:V,useExisting:a((()=>ln)),multi:!0}],template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class sn{set required(e){this.requiredValue=pe(e)}get required(){return this.requiredValue}}e("FieldsetComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sn,deps:[],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:sn,selector:"tb-fieldset-component",inputs:{label:"label",required:"required"},ngImport:t,template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-fieldset-component",template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],propDecorators:{label:[{type:i}],required:[{type:i}]}});class mn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[E.min(1)]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:mn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>mn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:V,useExisting:a((()=>mn)),multi:!0}],template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class un extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[oe,ae,ie],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(C))this.messageTypesList.push({name:v.get(C[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchMessageTypes(e))),Fe())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ie(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:un,deps:[{token:A.Store},{token:_.TranslateService},{token:F.TruncatePipe},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:un,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:V,useExisting:a((()=>un)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:V,useExisting:a((()=>un)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ translate.get(\'tb.rulenode.no-message-type-matching\',\n {messageType: truncate.transform(searchText, true, 6, '...')}) }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:F.TruncatePipe},{type:G.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class pn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRquired=!0,this.allCredentialsTypes=Lt,this.credentialsTypeTranslationsMap=kt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[E.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.pipe(Le()).subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){X(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators(!1))}setDisabledState(e){e?this.credentialsConfigFormGroup.disable():(this.credentialsConfigFormGroup.enable(),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([E.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRquired?[E.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(E.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:pn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRquired:"passwordFieldRquired"},providers:[{provide:V,useExisting:a((()=>pn)),multi:!0},{provide:w,useExisting:a((()=>pn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Se.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:V,useExisting:a((()=>pn)),multi:!0},{provide:w,useExisting:a((()=>pn)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRquired:[{type:i}]}});class dn{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne,this.fetchTo=Dt}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:dn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:V,useExisting:a((()=>dn)),multi:!0}],ngImport:t,template:'
\n \n \n {{ \'tb.rulenode.message\' | translate }}\n {{ \'tb.rulenode.metadata\' | translate }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"],dependencies:[{kind:"component",type:se.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:se.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:V,useExisting:a((()=>dn)),multi:!0}],template:'
\n \n \n {{ \'tb.rulenode.message\' | translate }}\n {{ \'tb.rulenode.metadata\' | translate }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{labelText:[{type:i}]}});class cn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Ne,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(D),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[E.required]],value:[e[n],[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.updateModel()}))}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value)t.push(this.selectOptions.find((t=>t===e.key)));const n=[];for(const r of this.selectOptions)X(t.find((e=>e===r)))&&r!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[E.required]],value:["",[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.controls[e.length-1])}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Ce(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cn,deps:[{token:A.Store},{token:_.TranslateService},{token:t.Injector},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:cn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",selectOptionsTranslate:"selectOptionsTranslate",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:V,useExisting:a((()=>cn)),multi:!0},{provide:w,useExisting:a((()=>cn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n \n {{ selectText }}\n \n \n {{selectOptionsTranslate.get(option) | translate}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n {{ hintText }}\n \n
\n
\n
\n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:fe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),Me([h()],cn.prototype,"disabled",void 0),Me([h()],cn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:V,useExisting:a((()=>cn)),multi:!0},{provide:w,useExisting:a((()=>cn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n \n {{ selectText }}\n \n \n {{selectOptionsTranslate.get(option) | translate}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n {{ hintText }}\n \n
\n
\n
\n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:t.Injector},{type:G.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],selectOptionsTranslate:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=pe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[E.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigOldComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:fn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:V,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:V,useExisting:a((()=>fn)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class gn{set enableFieldToggle(e){this._enableFieldToggle=pe(e)}get enableFieldToggle(){return this._enableFieldToggle}constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Ne,this.DataToFetch=ht}ngOnInit(){this.toggleControlGroup=this.fb.group({toggleControl:[null,[]]}),this.toggleControlGroup.get("toggleControl").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.toggleControlGroup.get("toggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("FetchToDataToggleComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:gn,selector:"tb-fetch-to-data-toggle",inputs:{enableFieldToggle:"enableFieldToggle"},providers:[{provide:V,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n \n {{ \'tb.rulenode.attributes\' | translate }}\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n {{ \'tb.rulenode.fields\' | translate }}\n \n
\n',styles:[":host ::ng-deep{margin-bottom:12px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;width:215px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:Re.MatButtonToggleGroup,selector:"mat-button-toggle-group",inputs:["appearance","name","vertical","value","multiple","disabled"],outputs:["valueChange","change"],exportAs:["matButtonToggleGroup"]},{kind:"component",type:Re.MatButtonToggle,selector:"mat-button-toggle",inputs:["disableRipple","aria-label","aria-labelledby","id","name","value","tabIndex","appearance","checked","disabled"],outputs:["change"],exportAs:["matButtonToggle"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-fetch-to-data-toggle",providers:[{provide:V,useExisting:a((()=>gn)),multi:!0}],template:'
\n \n {{ \'tb.rulenode.attributes\' | translate }}\n {{ \'tb.rulenode.latest-telemetry\' | translate }}\n {{ \'tb.rulenode.fields\' | translate }}\n \n
\n',styles:[":host ::ng-deep{margin-bottom:12px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;width:215px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]},propDecorators:{enableFieldToggle:[{type:i}]}});class yn{constructor(e,t,n){this.store=e,this.translate=t,this.fb=n,this.destroy$=new Ne,this.separatorKeysCodes=[oe,ae,ie]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]}),this.attributeControlGroup.valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.attributeControlGroup.patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}removeKey(e,t){const n=this.attributeControlGroup.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.attributeControlGroup.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.attributeControlGroup.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.attributeControlGroup.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}clearChipGrid(e){this.attributeControlGroup.get(e).patchValue([],{emitEvent:!0})}}e("SelectAttributesComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:yn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:V,useExisting:a((()=>yn)),multi:!0}],ngImport:t,template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin:10px 0 12px;display:block}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:V,useExisting:a((()=>yn)),multi:!0}],template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin:10px 0 12px;display:block}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class xn{}e("RulenodeCoreConfigCommonModule",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),xn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:xn,declarations:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn],imports:[H,L,qe],exports:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn]}),xn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,imports:[H,L,qe]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:xn,decorators:[{type:l,args:[{declarations:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn],imports:[H,L,qe],exports:[on,ln,mn,un,pn,Qe,Zt,en,nn,Qt,dn,an,cn,sn,fn,gn,yn]}]}]});class bn{}e("RuleNodeCoreConfigActionModule",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),bn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:bn,declarations:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn],imports:[H,L,qe,xn],exports:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn]}),bn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,imports:[H,L,qe,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:bn,decorators:[{type:l,args:[{declarations:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn],imports:[H,L,qe,xn],exports:[Xt,Ye,Yt,$t,Kt,Je,Xe,Ze,et,Ut,tt,rt,Ht,Bt,jt,Jt,Wt,We,nt,_t,zt,tn,rn]}]}]});class hn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[E.min(0),E.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:X(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:X(e?.outputValueKey)?e.outputValueKey:null,useCache:!X(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!X(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:X(e?.periodValueKey)?e.periodValueKey:null,round:X(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!X(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return e.inputValueKey=e.inputValueKey.trim(),e.outputValueKey=e.outputValueKey.trim(),e}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([E.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:hn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Cn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n].trim();return e.dataMapping=t,e}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Cn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Cn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class vn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[E.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return Z(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:X(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!X(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:vn,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:yn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:vn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.entityDetailsTranslationsMap=gt,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(dt))this.entityDetailsList.push(dt[e]);this.detailsFormControl=new P(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchEntityDetails(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],t=X(e?.addToMetadata)?e.addToMetadata?Dt.METADATA:Dt.DATA:e?.fetchTo?e.fetchTo:Dt.DATA,{detailsList:X(e?.detailsList)?e.detailsList:null,fetchTo:t}}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[E.required]],fetchTo:[e.fetchTo,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(gt.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(this.entityDetailsList.filter((t=>this.translate.instant(gt.get(dt[t])).toUpperCase().includes(e))))}return Ie(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clearChipGrid(){this.detailsList=[],this.entityDetailsConfigForm.get("detailsList").patchValue([],{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Fn,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]},propDecorators:{detailsInput:[{type:o,args:["detailsInput",{static:!1}]}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[oe,ae,ie],this.aggregationTypes=k,this.aggregations=Object.keys(k),this.aggregationTypesTranslations=T,this.fetchMode=yt,this.fetchModes=Object.keys(yt),this.deduplicationStrategiesTranslations=xt,this.samplingOrders=Object.keys(bt),this.samplingOrdersTranslate=Ct,this.timeUnits=Object.values(st),this.timeUnitsTranslationMap=mt,this.timeUnitMap={[st.MILLISECONDS]:1,[st.SECONDS]:1e3,[st.MINUTES]:6e4,[st.HOURS]:36e5,[st.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[]],aggregation:[e.aggregation,[E.required]],fetchMode:[e.fetchMode,[E.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,e.startIntervalPattern=e.startIntervalPattern.trim(),e.endIntervalPattern=e.endIntervalPattern.trim(),delete e.interval,e}prepareInputConfig(e){return Z(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:X(e?.aggregation)?e.aggregation:k.NONE,fetchMode:X(e?.fetchMode)?e.fetchMode:yt.FIRST,orderBy:X(e?.orderBy)?e.orderBy:bt.ASC,limit:X(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!X(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:X(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:X(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:st.MINUTES,endInterval:X(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:X(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:st.MINUTES},startIntervalPattern:X(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:X(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===yt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([E.required,E.min(2),E.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([E.required,E.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([E.required,E.min(1),E.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([E.required,E.min(1),E.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([E.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}fetchModeHintSelector(){let e;switch(this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value){case yt.ALL:e="tb.rulenode.all-mode-hint";break;case yt.LAST:e="tb.rulenode.last-mode-hint";break;case yt.FIRST:e="tb.rulenode.first-mode-hint"}return e}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ln,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Ln,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n {{ deduplicationStrategiesTranslations.get(fetchMode) | translate}}\n \n
\n {{ fetchModeHintSelector() | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle mat-button-toggle{width:215px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .additional-inputs{margin-bottom:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ae.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ne.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:Re.MatButtonToggleGroup,selector:"mat-button-toggle-group",inputs:["appearance","name","vertical","value","multiple","disabled"],outputs:["valueChange","change"],exportAs:["matButtonToggleGroup"]},{kind:"component",type:Re.MatButtonToggle,selector:"mat-button-toggle",inputs:["disableRipple","aria-label","aria-labelledby","id","name","value","tabIndex","appearance","checked","disabled"],outputs:["change"],exportAs:["matButtonToggle"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ce.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n {{ deduplicationStrategiesTranslations.get(fetchMode) | translate}}\n \n
\n {{ fetchModeHintSelector() | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle mat-button-toggle{width:215px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .additional-inputs{margin-bottom:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard{border:none;border-radius:18px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group.mat-button-toggle-group-appearance-standard .mat-button-toggle+.mat-button-toggle{border-left:none}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle{background:#f0f0f0;height:32px;align-items:center;display:flex}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle .mat-button-toggle-ripple{inset:2px;border-radius:16px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-button{height:32px;color:#959595}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-focus-overlay{border-radius:16px;margin:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked .mat-button-toggle-button{background-color:#305680;color:#fff;border-radius:16px;margin-left:2px;margin-right:2px}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-appearance-standard .mat-button-toggle-label-content{line-height:20px;font-size:14px;font-weight:500}:host ::ng-deep .mat-button-toggle-group.tb-script-lang-toggle-group .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay{opacity:.01}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return Z(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA,tellFailureIfAbsent:!!X(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:X(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kn,deps:[{token:A.Store},{token:_.TranslateService},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:kn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:yn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.FormBuilder}]}});class Tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorFields=[],this.originatorFieldsTranslations=ft;for(const e of Object.keys(ct))this.originatorFields.push(ct[e])}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){for(const t of Object.keys(e.dataMapping))e.dataMapping[t]=e.dataMapping[t].trim();return e}prepareInputConfig(e){return{dataMapping:X(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:X(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[E.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Tn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"],dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:an,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:cn,selector:"tb-sv-map-config",inputs:["selectOptions","selectOptionsTranslate","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class In extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht,this.originatorFieldsTranslations=ft,this.originatorFields=[],this.destroy$=new Ne,this.defaultKvMap={serialNumber:"sn"},this.defaultSvMap={name:"relatedEntityName"},this.dataToFetchPrevValue="";for(const e of Object.keys(ct))this.originatorFields.push(ct[e])}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n].trim();return e.dataMapping=t,e}prepareInputConfig(e){let t;return X(e?.telemetry)?this.dataToFetchPrevValue=e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:this.dataToFetchPrevValue=X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,t=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{relationsQuery:X(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:this.dataToFetchPrevValue,dataMapping:t,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[E.required]],dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Ce(this.destroy$)).subscribe((e=>{e===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultSvMap,{emitEvent:!1}),e!==ht.FIELDS&&this.dataToFetchPrevValue===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultKvMap,{emitEvent:!1}),this.dataToFetchPrevValue=e}))}msgMetadataChipLabel(){switch(this.relatedAttributesConfigForm.get("dataToFetch").value){case ht.ATTRIBUTES:return"tb.rulenode.add-mapped-attribute-to";case ht.LATEST_TELEMETRY:return"tb.rulenode.add-mapped-latest-telemetry-to";case ht.FIELDS:return"tb.rulenode.add-mapped-fields-to"}}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:In,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:In,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:mn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:cn,selector:"tb-sv-map-config",inputs:["selectOptions","selectOptionsTranslate","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Nn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.DataToFetch=ht}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[E.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Nn,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:on,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:sn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:gn,selector:"tb-fetch-to-data-toggle",inputs:["enableFieldToggle"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Sn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:X(e?.fetchTo)?e.fetchTo:Dt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sn,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Sn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:dn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class qn{}e("RulenodeCoreConfigEnrichmentModule",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),qn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:qn,declarations:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn],imports:[H,L,xn],exports:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn]}),qn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:qn,decorators:[{type:l,args:[{declarations:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn],imports:[H,L,xn],exports:[Cn,Fn,vn,kn,Tn,Ln,In,Nn,hn,Sn]}]}]});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Tt,this.azureIotHubCredentialsTypeTranslationsMap=It}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[E.required,E.min(1),E.max(200)]],clientId:[e?e.clientId:null,[E.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[E.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([E.required]);break;case"cert.PEM":t.get("privateKey").setValidators([E.required]),t.get("privateKeyFileName").setValidators([E.required]),t.get("cert").setValidators([E.required]),t.get("certFileName").setValidators([E.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Mn,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:O.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:O.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Se.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Se.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Se.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Se.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Se.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:G.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class An extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=St,this.ToByteStandartCharsetTypeTranslationMap=qt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[E.required]],retries:[e?e.retries:null,[E.min(0)]],batchSize:[e?e.batchSize:null,[E.min(0)]],linger:[e?e.linger:null,[E.min(0)]],bufferMemory:[e?e.bufferMemory:null,[E.min(0)]],acks:[e?e.acks:null,[E.required]],keySerializer:[e?e.keySerializer:null,[E.required]],valueSerializer:[e?e.valueSerializer:null,[E.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([E.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:An,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:An,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Gn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[E.required]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[E.required,E.min(1),E.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&ee(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{ee(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Gn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Gn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=I,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[E.required]],targets:[e?e.targets:[],[E.required]]})}}e("NotificationConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:En,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:En,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Oe.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","disabled","notificationTypes"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[E.required]],topicName:[e?e.topicName:null,[E.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[E.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[E.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Dn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:we.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Vn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[E.required]],port:[e?e.port:null,[E.required,E.min(1),E.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[E.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[E.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Vn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class wn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Nt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[E.required]],requestMethod:[e?e.requestMethod:null,[E.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[E.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[E.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[E.required,E.min(1),E.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([E.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([E.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:wn,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:pn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRquired"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,n=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([E.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([E.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([E.required,E.min(1),E.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([E.required,E.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[E.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[E.required,E.min(1),E.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Pn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ke.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[E.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[E.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([E.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Rn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Be.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(N),this.slackChanelTypesTranslateMap=S}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[E.required]],conversationType:[e?e.conversationType:null,[E.required]],conversation:[e?e.conversation:null,[E.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([E.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:On,deps:[{token:A.Store},{token:G.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:On,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ze.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.FormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[E.required]],accessKeyId:[e?e.accessKeyId:null,[E.required]],secretAccessKey:[e?e.secretAccessKey:null,[E.required]],region:[e?e.region:null,[E.required]]})}}e("SnsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Hn,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Kn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=vt,this.sqsQueueTypes=Object.keys(vt),this.sqsQueueTypeTranslationsMap=Ft}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[E.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[E.required]],delaySeconds:[e?e.delaySeconds:null,[E.min(0),E.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[E.required]],secretAccessKey:[e?e.secretAccessKey:null,[E.required]],region:[e?e.region:null,[E.required]]})}}e("SqsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Kn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Bn{}e("RulenodeCoreConfigExternalModule",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Bn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Bn,declarations:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On],imports:[H,L,qe,xn],exports:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On]}),Bn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,imports:[H,L,qe,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Bn,decorators:[{type:l,args:[{declarations:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On],imports:[H,L,qe,xn],exports:[Hn,Kn,Dn,An,Gn,En,Vn,wn,Pn,Mn,Rn,On]}]}]});class Un extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.alarmStatusTranslationsMap=q,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(M))this.alarmStatusList.push(M[e]);this.statusFormControl=new R(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(ve(""),be((e=>e||"")),he((e=>this.fetchAlarmStatus(e))),Fe())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[E.required]]})}displayStatus(e){return e?this.translate.instant(q.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ie(t.filter((t=>this.translate.instant(q.get(M[t])).toUpperCase().includes(e))))}return Ie(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const n=t.indexOf(e);n>=0&&(t.splice(n,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Un,deps:[{token:A.Store},{token:_.TranslateService},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Un,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ke.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:ke.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:ke.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:O.AsyncPipe,name:"async"},{kind:"pipe",type:Te.HighlightPipe,name:"highlight"},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:_.TranslateService},{type:G.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:o,args:["alarmStatusInput",{static:!1}]}]}});class zn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:zn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:zn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class _n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[E.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[E.required]:[]],relationType:[e?e.relationType:null,[E.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[E.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[E.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_n,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:_n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:_e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Ee.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","required","disabled","subscriptSizing"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=it,this.perimeterTypes=Object.keys(it),this.perimeterTypeTranslationMap=lt,this.rangeUnits=Object.keys(ut),this.rangeUnitTranslationMap=pt}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[E.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[E.required]],perimeterType:[e?e.perimeterType:null,[E.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([E.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==it.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([E.required,E.min(-90),E.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([E.required,E.min(-180),E.max(180)]),this.geoFilterConfigForm.get("range").setValidators([E.required,E.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([E.required])),t||n!==it.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([E.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:K.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:G.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[E.required]]})}}e("MessageTypeConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$n,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:$n,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:un,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[E.required]]})}}e("OriginatorTypeConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Qn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:je.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Jn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Yn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",r=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Yn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Wn{}e("RuleNodeCoreConfigFilterModule",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Wn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:Wn,declarations:[zn,_n,jn,$n,Qn,Jn,Yn,Un],imports:[H,L,xn],exports:[zn,_n,jn,$n,Qn,Jn,Yn,Un]}),Wn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Wn,decorators:[{type:l,args:[{declarations:[zn,_n,jn,$n,Qn,Jn,Yn,Un],imports:[H,L,xn],exports:[zn,_n,jn,$n,Qn,Jn,Yn,Un]}]}]});class Xn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=ot,this.originatorSources=Object.keys(ot),this.originatorSourceTranslationMap=at,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[E.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===ot.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([E.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===ot.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([E.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([E.required,E.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xn,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Xn,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:z.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class Zn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[E.required]],jsScript:[e?e.jsScript:null,[E.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[E.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[E.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zn,deps:[{token:A.Store},{token:G.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:_.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:Zn,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:te.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ne.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:re.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:_.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[E.required]],toTemplate:[e?e.toTemplate:null,[E.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[E.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[E.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(ve([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(E.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:er,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:$.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Q.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:_.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:er,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],keys:[e?e.keys:null,[E.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:tr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[E.required]]})}}e("RenameKeysConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:nr,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Qt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[E.required]]})}}e("NodeJsonPathConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:rr,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[oe,ae,ie]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[E.required]],keys:[e?e.keys:null,[E.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:or,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:O.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:O.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:le.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:B.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:Ue.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:Ue.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:se.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:se.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:se.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:se.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:z.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"},{kind:"pipe",type:Qe,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class ar{}e("RulenodeCoreConfigTransformModule",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ar.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:ar,declarations:[Xn,Zn,er,tr,nr,rr,or],imports:[H,L,xn],exports:[Xn,Zn,er,tr,nr,rr,or]}),ar.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ar,decorators:[{type:l,args:[{declarations:[Xn,Zn,er,tr,nr,rr,or],imports:[H,L,xn],exports:[Xn,Zn,er,tr,nr,rr,or]}]}]});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[E.required]]})}}e("RuleChainInputComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:ir,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:_e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:G.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,deps:[{token:A.Store},{token:G.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.5",type:lr,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:z.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:G.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:G.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:_.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:A.Store},{type:G.UntypedFormBuilder}]}});class sr{}e("RuleNodeCoreConfigFlowModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:sr,declarations:[ir,lr],imports:[H,L,xn],exports:[ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,imports:[H,L,xn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:sr,decorators:[{type:l,args:[{declarations:[ir,lr],imports:[H,L,xn],exports:[ir,lr]}]}]});class mr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. In case you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required!","limit-range":"Limit should be in a range from 2 to 1000!","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647!","start-interval-value-required":"Start interval value is required!","end-interval-value-required":"End interval value is required!",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","add-timeseries-key":"Add timeseries key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Max relation level should be greater than 0 or unspecified!","relation-type":"Relation type","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required!","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required!","target-key":"Target key","target-key-required":"Target key is required!","attr-mapping-required":"At least one mapping entry should be specified!","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","source-field":"Source field","source-field-required":"Source field is required!","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required!","end-interval-required":"Interval end is required!","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","entity-details-list-empty":"No entity details selected!","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required!","output-value-key":"Output value key","output-value-key-required":"Output value key is required!","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15!","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-cashing":"Use cashing","use-cashing-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required!","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","attributes-mapping":"Attributes mapping*","latest-telemetry-mapping":"Latest telemetry mapping*","add-mapped-attribute-to":"Add mapped attributes to:","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to:","add-mapped-fields-to":"Add mapped fields to:","add-selected-details-to":"Add selected details to:","clear-selected-details":"Clear selected details","clear-selected-keys":"Clear selected keys","fetch-credentials-to":"Fetch credentials to:","add-originator-attributes-to":"Add originator attributes to:","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell Failure","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to:",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output message metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end")!',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch:","mapping-of-customers":"Mapping of customer's:",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to:","device-profiles":"Device profiles","mapping-of-tenant":"Mapping of tenant's:","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,deps:[{token:_.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),mr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.5",ngImport:t,type:mr,declarations:[$e],imports:[H,L],exports:[bn,Wn,qn,Bn,ar,sr,$e]}),mr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,imports:[H,L,bn,Wn,qn,Bn,ar,sr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.5",ngImport:t,type:mr,decorators:[{type:l,args:[{declarations:[$e],imports:[H,L],exports:[bn,Wn,qn,Bn,ar,sr,$e]}]}],ctorParameters:function(){return[{type:_.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","tslib","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@angular/material/slide-toggle","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@shared/components/toggle-header.component","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,v,F,L,k,T,I,N,S,q,M,A,G,E,D,V,w,P,R,O,H,K,B,U,z,_,j,$,Q,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,ve,Fe,Le,ke,Te,Ie,Ne,Se,qe,Me,Ae,Ge,Ee,De,Ve,we,Pe,Re,Oe,He,Ke,Be,Ue,ze,_e,je,$e;return{setters:[function(e){t=e,n=e.Component,r=e.Pipe,o=e.ViewChild,a=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.coerceBoolean,C=e.MessageType,v=e.messageTypeNames,F=e,L=e.SharedModule,k=e.AggregationType,T=e.aggregationTranslations,I=e.entityFields,N=e.NotificationType,S=e.SlackChanelType,q=e.SlackChanelTypesTranslateMap,M=e.alarmStatusTranslations,A=e.AlarmStatus},function(e){G=e},function(e){E=e,D=e.Validators,V=e.NgControl,w=e.NG_VALUE_ACCESSOR,P=e.NG_VALIDATORS,R=e.FormControl,O=e.UntypedFormControl},function(e){H=e,K=e.CommonModule},function(e){B=e},function(e){U=e},function(e){z=e},function(e){_=e},function(e){j=e},function(e){$=e},function(e){Q=e},function(e){J=e},function(e){Y=e},function(e){W=e.getCurrentAuthState,X=e,Z=e.isDefinedAndNotNull,ee=e.deepTrim,te=e.isObject,ne=e.isNotEmptyStr},function(e){re=e},function(e){oe=e},function(e){ae=e},function(e){ie=e.ENTER,le=e.COMMA,se=e.SEMICOLON},function(e){me=e},function(e){ue=e},function(e){pe=e},function(e){de=e},function(e){ce=e.coerceBooleanProperty},function(e){fe=e},function(e){ge=e},function(e){ye=e},function(e){xe=e},function(e){be=e},function(e){he=e.tap,Ce=e.map,ve=e.mergeMap,Fe=e.takeUntil,Le=e.startWith,ke=e.share},function(e){Te=e},function(e){Ie=e},function(e){Ne=e.of,Se=e.Subject},function(e){qe=e},function(e){Me=e.HomeComponentsModule},function(e){Ae=e.__decorate},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){we=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e},function(e){Be=e},function(e){Ue=e},function(e){ze=e},function(e){_e=e},function(e){je=e},function(e){$e=e}],execute:function(){class Qe extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Qe),Qe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qe,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qe,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qe,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Je{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,deps:[{token:$.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Je.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Je,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:$.DomSanitizer}]}});class Ye extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[D.required,D.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ye,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:We,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xe extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[D.required]]})}}e("CheckPointConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xe,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:Y.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Ze extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[D.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[D.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[D.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.clearAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",r=this.clearAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.clearAlarmConfigForm.get(t).setValue(e)}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ze,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[ie,le,se],this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([D.required]),this.createAlarmConfigForm.get("severity").setValidators([D.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",r=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:et,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[D.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([D.required,D.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([D.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,D.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,D.required]})}}e("DeviceProfileConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ot extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[D.required,D.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[D.required,D.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",r=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var at;e("GeneratorConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ot,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:Y.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(at||(at={}));const it=new Map([[at.CUSTOMER,"tb.rulenode.originator-customer"],[at.TENANT,"tb.rulenode.originator-tenant"],[at.RELATED,"tb.rulenode.originator-related"],[at.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[at.ENTITY,"tb.rulenode.originator-entity"]]);var lt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(lt||(lt={}));const st=new Map([[lt.CIRCLE,"tb.rulenode.perimeter-circle"],[lt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var mt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(mt||(mt={}));const ut=new Map([[mt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[mt.SECONDS,"tb.rulenode.time-unit-seconds"],[mt.MINUTES,"tb.rulenode.time-unit-minutes"],[mt.HOURS,"tb.rulenode.time-unit-hours"],[mt.DAYS,"tb.rulenode.time-unit-days"]]);var pt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(pt||(pt={}));const dt=new Map([[pt.METER,"tb.rulenode.range-unit-meter"],[pt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[pt.FOOT,"tb.rulenode.range-unit-foot"],[pt.MILE,"tb.rulenode.range-unit-mile"],[pt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var ct;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(ct||(ct={}));const ft=new Map([[ct.ID,"tb.rulenode.entity-details-id"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var gt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(gt||(gt={}));const yt=new Map([[gt.FIRST,"tb.rulenode.first"],[gt.LAST,"tb.rulenode.last"],[gt.ALL,"tb.rulenode.all"]]),xt=new Map([[gt.FIRST,"tb.rulenode.first-mode-hint"],[gt.LAST,"tb.rulenode.last-mode-hint"],[gt.ALL,"tb.rulenode.all-mode-hint"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const Ct=new Map([[ht.ATTRIBUTES,"tb.rulenode.attributes"],[ht.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[ht.FIELDS,"tb.rulenode.fields"]]),vt=new Map([[ht.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[ht.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[ht.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),Ft=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var Lt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Lt||(Lt={}));const kt=new Map([[Lt.STANDARD,"tb.rulenode.sqs-queue-standard"],[Lt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Tt=["anonymous","basic","cert.PEM"],It=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Nt=["sas","cert.PEM"],St=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var qt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(qt||(qt={}));const Mt=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],At=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Gt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Gt||(Gt={}));const Et=new Map([[Gt.CUSTOM,{value:Gt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Gt.ADD,{value:Gt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Gt.SUB,{value:Gt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Gt.MULT,{value:Gt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Gt.DIV,{value:Gt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Gt.SIN,{value:Gt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.SINH,{value:Gt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Gt.COS,{value:Gt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.COSH,{value:Gt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Gt.TAN,{value:Gt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Gt.TANH,{value:Gt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ACOS,{value:Gt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Gt.ASIN,{value:Gt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN,{value:Gt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN2,{value:Gt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Gt.EXP,{value:Gt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Gt.EXPM1,{value:Gt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Gt.SQRT,{value:Gt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Gt.CBRT,{value:Gt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Gt.GET_EXP,{value:Gt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Gt.HYPOT,{value:Gt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Gt.LOG,{value:Gt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG10,{value:Gt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG1P,{value:Gt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Gt.CEIL,{value:Gt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR,{value:Gt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR_DIV,{value:Gt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Gt.FLOOR_MOD,{value:Gt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Gt.ABS,{value:Gt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Gt.MIN,{value:Gt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Gt.MAX,{value:Gt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Gt.POW,{value:Gt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Gt.SIGNUM,{value:Gt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Gt.RAD,{value:Gt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Gt.DEG,{value:Gt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Dt,Vt,wt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Dt||(Dt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Vt||(Vt={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(wt||(wt={}));const Pt=new Map([[wt.DATA,"tb.rulenode.message"],[wt.METADATA,"tb.rulenode.metadata"]]),Rt=new Map([[Dt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Dt.TIME_SERIES,"tb.rulenode.time-series-type"],[Dt.CONSTANT,"tb.rulenode.constant-type"],[Dt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Dt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),Ot=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Ht,Kt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Ht||(Ht={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Kt||(Kt={}));const Bt=new Map([[Ht.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Ht.SERVER_SCOPE,"tb.rulenode.server-scope"],[Ht.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt,this.timeUnits=Object.keys(mt),this.timeUnitsTranslationMap=ut}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[D.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[D.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoActionConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ut,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",r=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[D.required,D.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[D.required]]})}}e("MsgCountConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_t,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([D.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([D.required,D.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]]})}}e("PushToCloudConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]]})}}e("PushToEdgeConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[D.required,D.min(0)]]})}}e("RpcRequestConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[D.required]],value:["",[D.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigOldComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:w,useExisting:a((()=>Wt)),multi:!0},{provide:P,useExisting:a((()=>Wt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:w,useExisting:a((()=>Wt)),multi:!0},{provide:P,useExisting:a((()=>Wt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[D.required,D.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[D.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[D.required,D.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class en extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[D.required,D.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:en,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[ie,le,se]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],keys:[e?e.keys:null,[D.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class nn extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=Et,this.ArgumentType=Dt,this.attributeScopeMap=Bt,this.argumentTypeResultMap=Rt,this.arguments=Object.values(Dt),this.attributeScope=Object.values(Ht),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),n=this.createArgumentControl(null,t.length);t.push(n,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Gt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([D.minLength(this.minArgs),D.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!1}),n.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Dt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Dt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Ot[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:w,useExisting:a((()=>nn)),multi:!0},{provide:P,useExisting:a((()=>nn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"],dependencies:[{kind:"directive",type:H.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:xe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:xe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:be.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:be.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:be.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:w,useExisting:a((()=>nn)),multi:!0},{provide:P,useExisting:a((()=>nn)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class rn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...Et.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(he((e=>{let t;t="string"==typeof e&&Gt[e]?Gt[e]:null,this.updateView(t)})),Ce((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=Et.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rn,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:w,useExisting:a((()=>rn)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:w,useExisting:a((()=>rn)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class on extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Gt,this.ArgumentTypeResult=Vt,this.argumentTypeResultMap=Rt,this.attributeScopeMap=Bt,this.argumentsResult=Object.values(Vt),this.attributeScopeResult=Object.values(Kt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[D.required]],arguments:[e?e.arguments:null,[D.required]],customFunction:[e?e.customFunction:"",[D.required]],result:this.fb.group({type:[e?e.result.type:null,[D.required]],attributeScope:[e?e.result.attributeScope:null,[D.required]],key:[e?e.result.key:"",[D.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result.type").value;t===Gt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Vt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:on,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:nn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:rn,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class an{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[D.required,D.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(he((e=>{this.updateView(e)})),Ce((e=>e||"")),ve((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,Ne(this.messageTypes).pipe(Ce((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:an,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:w,useExisting:a((()=>an)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:w,useExisting:a((()=>an)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class ln extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Se,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=gt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=yt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[Z(e?.interval)?e.interval:null,[D.required,D.min(1)]],strategy:[Z(e?.strategy)?e.strategy:null,[D.required]],outMsgType:[Z(e?.outMsgType)?e.outMsgType:null,[D.required]],queueName:[Z(e?.queueName)?e.queueName:null,[D.required]],maxPendingMsgs:[Z(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e3)]],maxRetries:[Z(e?.maxRetries)?e.maxRetries:null,[D.required,D.min(0),D.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ln,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Y.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:qe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:qe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:qe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:qe.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:an,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class sn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sn,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:w,useExisting:a((()=>sn)),multi:!0},{provide:P,useExisting:a((()=>sn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),Ae([h()],sn.prototype,"disabled",void 0),Ae([h()],sn.prototype,"uniqueKeyValuePairValidator",void 0),Ae([h()],sn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:w,useExisting:a((()=>sn)),multi:!0},{provide:P,useExisting:a((()=>sn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class mn{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Se}ngOnInit(){this.slideToggleControlGroup=this.fb.group({slideToggleControl:[null,[]]}),this.slideToggleControlGroup.get("slideToggleControl").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.slideToggleControlGroup.get("slideToggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.slideToggleControlGroup.disable({emitEvent:!1}):this.slideToggleControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SlideToggleComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mn,selector:"tb-slide-toggle",inputs:{slideToggleName:"slideToggleName",slideToggleTooltip:"slideToggleTooltip"},providers:[{provide:w,useExisting:a((()=>mn)),multi:!0}],ngImport:t,template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"],dependencies:[{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Ve.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-slide-toggle",providers:[{provide:w,useExisting:a((()=>mn)),multi:!0}],template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{slideToggleName:[{type:i}],slideToggleTooltip:[{type:i}]}});class un extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],relationType:[null],deviceTypes:[null,[D.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:un,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:w,useExisting:a((()=>un)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["label","required","disabled","entityType"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:w,useExisting:a((()=>un)),multi:!0}],template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class pn{constructor(){this.required=!1}}e("FieldsetComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,deps:[],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pn,selector:"tb-fieldset-component",inputs:{label:"label",required:"required"},ngImport:t,template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]}]}),Ae([h()],pn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-fieldset-component",template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],propDecorators:{label:[{type:i}],required:[{type:i}]}});class dn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:w,useExisting:a((()=>dn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:w,useExisting:a((()=>dn)),multi:!0}],template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class cn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[ie,le,se],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(C))this.messageTypesList.push({name:v.get(C[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Le(""),Ce((e=>e||"")),ve((e=>this.fetchMessageTypes(e))),ke())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ne(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,deps:[{token:G.Store},{token:j.TranslateService},{token:F.TruncatePipe},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:w,useExisting:a((()=>cn)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n { messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:w,useExisting:a((()=>cn)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n { messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:F.TruncatePipe},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=Tt,this.credentialsTypeTranslationsMap=It,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[D.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){Z(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([D.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[D.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(D.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:w,useExisting:a((()=>fn)),multi:!0},{provide:P,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:H.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:qe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:qe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:qe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:qe.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:qe.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:w,useExisting:a((()=>fn)),multi:!0},{provide:P,useExisting:a((()=>fn)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class gn{constructor(e,t,n){this.store=e,this.fb=t,this.translate=n,this.destroy$=new Se,this.selectOptions=[];for(const e of Pt.keys())this.selectOptions.push({value:e,name:this.translate.instant(Pt.get(e))})}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.chipControlGroup.disable({emitEvent:!1}):this.chipControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:w,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:w,useExisting:a((()=>gn)),multi:!0}],template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]},propDecorators:{labelText:[{type:i}]}});class yn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Se,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.updateModel()}))}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value){const n=this.selectOptions.find((t=>t.value===e.key));n&&t.push(n)}const n=[];for(const r of this.selectOptions)Z(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[D.required]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.controls[e.length-1])}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Fe(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:w,useExisting:a((()=>yn)),multi:!0},{provide:P,useExisting:a((()=>yn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),Ae([h()],yn.prototype,"disabled",void 0),Ae([h()],yn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:w,useExisting:a((()=>yn)),multi:!0},{provide:P,useExisting:a((()=>yn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class xn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigOldComponent",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:w,useExisting:a((()=>xn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:w,useExisting:a((()=>xn)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class bn{constructor(e,t,n){this.store=e,this.translate=t,this.fb=n,this.destroy$=new Se,this.separatorKeysCodes=[ie,le,se]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]}),this.attributeControlGroup.valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.attributeControlGroup.patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}removeKey(e,t){const n=this.attributeControlGroup.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.attributeControlGroup.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.attributeControlGroup.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.attributeControlGroup.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}clearChipGrid(e){this.attributeControlGroup.get(e).patchValue([],{emitEvent:!0})}}e("SelectAttributesComponent",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:bn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:w,useExisting:a((()=>bn)),multi:!0}],ngImport:t,template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:w,useExisting:a((()=>bn)),multi:!0}],template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class hn{}e("RulenodeCoreConfigCommonModule",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),hn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:hn,declarations:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn],imports:[K,L,Me],exports:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn]}),hn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,imports:[K,L,Me]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,decorators:[{type:l,args:[{declarations:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn],imports:[K,L,Me],exports:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn]}]}]});class Cn{}e("RuleNodeCoreConfigActionModule",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Cn,declarations:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln],imports:[K,L,Me,hn],exports:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln]}),Cn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,imports:[K,L,Me,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,decorators:[{type:l,args:[{declarations:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln],imports:[K,L,Me,hn],exports:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln]}]}]});class vn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[ie,le,se]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[D.min(0),D.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:Z(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:Z(e?.outputValueKey)?e.outputValueKey:null,useCache:!Z(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!Z(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:Z(e?.periodValueKey)?e.periodValueKey:null,round:Z(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!Z(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return ee(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([D.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:vn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"],dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of Ct.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ct.get(e))})}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,ee(e)}toggleChange(e){this.customerAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=Z(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:Z(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=Z(e?.attrMapping)?e.attrMapping:Z(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:sn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[D.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return te(e)&&(e.attributesControl={clientAttributeNames:Z(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:Z(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:Z(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:Z(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!Z(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:Z(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!Z(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ln,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:un,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.entityDetailsTranslationsMap=ft,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(ct))this.entityDetailsList.push(ct[e]);this.detailsFormControl=new R(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(Le(""),Ce((e=>e||"")),ve((e=>this.fetchEntityDetails(e))),ke())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],t=Z(e?.addToMetadata)?e.addToMetadata?wt.METADATA:wt.DATA:e?.fetchTo?e.fetchTo:wt.DATA,{detailsList:Z(e?.detailsList)?e.detailsList:null,fetchTo:t}}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[D.required]],fetchTo:[e.fetchTo,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(ft.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(this.entityDetailsList.filter((t=>this.translate.instant(ft.get(ct[t])).toUpperCase().includes(e))))}return Ne(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clearChipGrid(){this.detailsList=[],this.entityDetailsConfigForm.get("detailsList").patchValue([],{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kn,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]},propDecorators:{detailsInput:[{type:o,args:["detailsInput",{static:!1}]}]}});class Tn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[ie,le,se],this.aggregationTypes=k,this.aggregations=Object.keys(k),this.aggregationTypesTranslations=T,this.fetchMode=gt,this.samplingOrders=Object.keys(bt),this.samplingOrdersTranslate=Ft,this.timeUnits=Object.values(mt),this.timeUnitsTranslationMap=ut,this.deduplicationStrategiesHintTranslations=xt,this.headerOptions=[],this.timeUnitMap={[mt.MILLISECONDS]:1,[mt.SECONDS]:1e3,[mt.MINUTES]:6e4,[mt.HOURS]:36e5,[mt.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null;for(const e of yt.keys())this.headerOptions.push({value:e,name:this.translate.instant(yt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[]],aggregation:[e.aggregation,[D.required]],fetchMode:[e.fetchMode,[D.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}toggleChange(e){this.getTelemetryFromDatabaseConfigForm.get("fetchMode").patchValue(e,{emitEvent:!0})}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,delete e.interval,ee(e)}prepareInputConfig(e){return te(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:Z(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:Z(e?.aggregation)?e.aggregation:k.NONE,fetchMode:Z(e?.fetchMode)?e.fetchMode:gt.FIRST,orderBy:Z(e?.orderBy)?e.orderBy:bt.ASC,limit:Z(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!Z(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:Z(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:Z(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:mt.MINUTES,endInterval:Z(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:Z(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:mt.MINUTES},startIntervalPattern:Z(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:Z(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===gt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([D.required,D.min(2),D.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tn,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class In extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return te(e)&&(e.attributesControl={clientAttributeNames:Z(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:Z(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:Z(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:Z(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!Z(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA,tellFailureIfAbsent:!!Z(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:Z(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:In,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class Nn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of Object.keys(I))this.originatorFields.push({value:I[e].value,name:this.translate.instant(I[e].name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return ee(e)}prepareInputConfig(e){return{dataMapping:Z(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:Z(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[D.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class Sn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=ht,this.msgMetadataLabelTranslations=vt,this.originatorFields=[],this.fetchToData=[],this.destroy$=new Se,this.defaultKvMap={serialNumber:"sn"},this.defaultSvMap={[I.name.value]:`relatedEntity${this.translate.instant(I.name.name)}`},this.dataToFetchPrevValue="";for(const e of Object.keys(I))this.originatorFields.push({value:I[e].value,name:this.translate.instant(I[e].name)});for(const e of Ct.keys())this.fetchToData.push({value:e,name:this.translate.instant(Ct.get(e))})}toggleChange(e){this.relatedAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,ee(e)}prepareInputConfig(e){let t;return Z(e?.telemetry)?this.dataToFetchPrevValue=e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:this.dataToFetchPrevValue=Z(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,t=Z(e?.attrMapping)?e.attrMapping:Z(e?.dataMapping)?e.dataMapping:null,{relationsQuery:Z(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:this.dataToFetchPrevValue,dataMapping:t,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[D.required]],dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{e===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultSvMap,{emitEvent:!1}),e!==ht.FIELDS&&this.dataToFetchPrevValue===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultKvMap,{emitEvent:!1}),this.dataToFetchPrevValue=e}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sn,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:sn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class qn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of Ct.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ct.get(e))})}configForm(){return this.tenantAttributesConfigForm}toggleChange(e){this.tenantAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=Z(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:Z(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=Z(e?.attrMapping)?e.attrMapping:Z(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qn,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:sn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class An{}e("RulenodeCoreConfigEnrichmentModule",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,deps:[],target:t.ɵɵFactoryTarget.NgModule}),An.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:An,declarations:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn],imports:[K,L,hn],exports:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn]}),An.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,decorators:[{type:l,args:[{declarations:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn],imports:[K,L,hn],exports:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn]}]}]});class Gn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Nt,this.azureIotHubCredentialsTypeTranslationsMap=St}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[D.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[D.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([D.required]);break;case"cert.PEM":t.get("privateKey").setValidators([D.required]),t.get("privateKeyFileName").setValidators([D.required]),t.get("cert").setValidators([D.required]),t.get("certFileName").setValidators([D.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Gn,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:H.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:qe.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:qe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:qe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:qe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:qe.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=Mt,this.ToByteStandartCharsetTypeTranslationMap=At}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[D.required]],retries:[e?e.retries:null,[D.min(0)]],batchSize:[e?e.batchSize:null,[D.min(0)]],linger:[e?e.linger:null,[D.min(0)]],bufferMemory:[e?e.bufferMemory:null,[D.min(0)]],acks:[e?e.acks:null,[D.required]],keySerializer:[e?e.keySerializer:null,[D.required]],valueSerializer:[e?e.valueSerializer:null,[D.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([D.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:En,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&ne(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{ne(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Vn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=N,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[D.required]],targets:[e?e.targets:[],[D.required]]})}}e("NotificationConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vn,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:He.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ke.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class wn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[D.required]],topicName:[e?e.topicName:null,[D.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[D.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[D.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[D.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[D.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(qt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[D.required]],requestMethod:[e?e.requestMethod:null,[D.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[D.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[D.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[D.required,D.min(1),D.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([D.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([D.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rn,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,n=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([D.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([D.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([D.required,D.min(1),D.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([D.required,D.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[D.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[D.required,D.min(1),D.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:On,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Be.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[D.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[D.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([D.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Hn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ue.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Kn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(S),this.slackChanelTypesTranslateMap=q}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[D.required]],conversationType:[e?e.conversationType:null,[D.required]],conversation:[e?e.conversation:null,[D.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([D.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kn,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:_e.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Bn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[D.required]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SnsConfigComponent",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bn,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Un extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Lt,this.sqsQueueTypes=Object.keys(Lt),this.sqsQueueTypeTranslationsMap=kt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[D.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[D.required]],delaySeconds:[e?e.delaySeconds:null,[D.min(0),D.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SqsConfigComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Un,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zn{}e("RulenodeCoreConfigExternalModule",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:zn,declarations:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn],imports:[K,L,Me,hn],exports:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn]}),zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,imports:[K,L,Me,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,decorators:[{type:l,args:[{declarations:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn],imports:[K,L,Me,hn],exports:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn]}]}]});class _n extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.alarmStatusTranslationsMap=M,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(A))this.alarmStatusList.push(A[e]);this.statusFormControl=new O(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(Le(""),Ce((e=>e||"")),ve((e=>this.fetchAlarmStatus(e))),ke())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[D.required]]})}displayStatus(e){return e?this.translate.instant(M.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(t.filter((t=>this.translate.instant(M.get(A[t])).toUpperCase().includes(e))))}return Ne(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const n=t.indexOf(e);n>=0&&(t.splice(n,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,deps:[{token:G.Store},{token:j.TranslateService},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_n,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:o,args:["alarmStatusInput",{static:!1}]}]}});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ie,le,se]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[D.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[D.required]:[]],relationType:[e?e.relationType:null,[D.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:je.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoFilterConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[D.required]]})}}e("MessageTypeConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jn,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:cn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[D.required]]})}}e("OriginatorTypeConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:$e.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["label","floatLabel","required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Xn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",r=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Zn{}e("RuleNodeCoreConfigFilterModule",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Zn,declarations:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n],imports:[K,L,hn],exports:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n]}),Zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,decorators:[{type:l,args:[{declarations:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n],imports:[K,L,hn],exports:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n]}]}]});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=at,this.originatorSources=Object.keys(at),this.originatorSourceTranslationMap=it,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===at.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([D.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===at.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([D.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:er,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tr extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[D.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[D.required]],toTemplate:[e?e.toTemplate:null,[D.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[D.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[D.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(Le([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(D.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ie,le,se]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[D.required]]})}}e("RenameKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[D.required]]})}}e("NodeJsonPathConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ie,le,se]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class lr{}e("RulenodeCoreConfigTransformModule",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),lr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:lr,declarations:[er,tr,nr,rr,or,ar,ir],imports:[K,L,hn],exports:[er,tr,nr,rr,or,ar,ir]}),lr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:l,args:[{declarations:[er,tr,nr,rr,or,ar,ir],imports:[K,L,hn],exports:[er,tr,nr,rr,or,ar,ir]}]}]});class sr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[D.required]]})}}e("RuleChainInputComponent",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:je.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class mr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ur{}e("RuleNodeCoreConfigFlowModule",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ur.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:ur,declarations:[sr,mr],imports:[K,L,hn],exports:[sr,mr]}),ur.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:l,args:[{declarations:[sr,mr],imports:[K,L,hn],exports:[sr,mr]}]}]});class pr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. If you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required!","limit-range":"Limit should be in a range from 2 to 1000!","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647!","start-interval-value-required":"Start interval value is required!","end-interval-value-required":"End interval value is required!",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","add-timeseries-key":"Add timeseries key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Max relation level should be greater than 0 or unspecified!","relation-type":"Relation type","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required!","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required!","target-key":"Target key","target-key-required":"Target key is required!","attr-mapping-required":"At least one mapping entry should be specified!","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","source-field":"Source field","source-field-required":"Source field is required!","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required!","end-interval-required":"Interval end is required!","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","entity-details-list-empty":"No entity details selected!","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required!","output-value-key":"Output value key","output-value-key-required":"Output value key is required!","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15!","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-cashing":"Use cashing","use-cashing-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required!","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","attributes-mapping":"Attributes mapping*","latest-telemetry-mapping":"Latest telemetry mapping*","add-mapped-attribute-to":"Add mapped attributes to:","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to:","add-mapped-fields-to":"Add mapped fields to:","add-selected-details-to":"Add selected details to:","clear-selected-details":"Clear selected details","clear-selected-keys":"Clear selected keys","fetch-credentials-to":"Fetch credentials to:","add-originator-attributes-to":"Add originator attributes to:","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell Failure","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to:",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output message metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end")!',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch:","mapping-of-customers":"Mapping of customer's:",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to:","device-profiles":"Device profiles","mapping-of-tenant":"Mapping of tenant's:","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[{token:j.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:pr,declarations:[Qe],imports:[K,L],exports:[Cn,Zn,An,zn,lr,ur,Qe]}),pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,imports:[K,L,Cn,Zn,An,zn,lr,ur]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:l,args:[{declarations:[Qe],imports:[K,L],exports:[Cn,Zn,An,zn,lr,ur,Qe]}]}],ctorParameters:function(){return[{type:j.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map From 6d0b16e41c06220f325f1b8ebfad30b1f573d00a Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 14 Jun 2023 18:56:36 +0300 Subject: [PATCH 117/421] tbel: add parseBytesToDouble --- .../thingsboard/script/api/tbel/TbUtils.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index 10d48d582a..0708d1c959 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -16,6 +16,7 @@ package org.thingsboard.script.api.tbel; import com.google.common.primitives.Bytes; +import org.apache.commons.lang3.ArrayUtils; import org.mvel2.ExecutionContext; import org.mvel2.ParserConfiguration; import org.mvel2.execution.ExecutionArrayList; @@ -31,6 +32,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Base64; import java.util.Collection; import java.util.List; @@ -90,6 +92,14 @@ public class TbUtils { List.class, int.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", List.class, int.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + byte[].class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + byte[].class, int.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + List.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + List.class, int.class))); parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", double.class, int.class))); parserConfig.addImport("hexToBytes", new MethodStub(TbUtils.class.getMethod("hexToBytes", @@ -329,6 +339,39 @@ public class TbUtils { return parseBytesToFloat(Bytes.toArray(data), offset, bigEndian); } + + public static double parseBytesToDouble(byte[] data, int offset) { + return parseBytesToDouble(data, offset, true); + } + + public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) { + if (data != null && data.length > 0) { + int length = 8; + if (offset > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); + } + if ((offset + length) > data.length) { + throw new IllegalArgumentException("Default length is always 4 bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); + } + + byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset+length)); + if (!bigEndian) { + ArrayUtils.reverse(dataBytesArray); + } + return ByteBuffer.wrap(dataBytesArray).getDouble(); + } else { + throw new IllegalArgumentException("Array is null or array length is 0!"); + } + } + + public static double parseBytesToDouble(List data, int offset) { + return parseBytesToDouble(data, offset, true); + } + + public static double parseBytesToDouble(List data, int offset, boolean bigEndian) { + return parseBytesToDouble(Bytes.toArray(data), offset, bigEndian); + } + public static String bytesToHex(ExecutionArrayList bytesList) { byte[] bytes = new byte[bytesList.size()]; for (int i = 0; i < bytesList.size(); i++) { From b33c39dd253215aec3652ddcf955d8ce78158361 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 15 Jun 2023 11:58:48 +0300 Subject: [PATCH 118/421] Refactoring --- .../org/thingsboard/server/controller/AlarmControllerTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index f83deaad2e..dccb650555 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -535,7 +535,6 @@ public class AlarmControllerTest extends AbstractControllerTest { public void testUnassignAlarmOnUserRemoving() throws Exception { loginTenantAdmin(); - User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(tenantId); From b79176f3b89fa16dd55c5d6e12cddf7dc482bd4b Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 15 Jun 2023 16:50:31 +0300 Subject: [PATCH 119/421] tbel: add parseLong parseHexToLong parseBytesToLong toFixed (float.class) --- .../thingsboard/script/api/tbel/TbUtils.java | 190 ++++++++++++++---- 1 file changed, 149 insertions(+), 41 deletions(-) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index 0708d1c959..d275466b95 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -64,6 +64,10 @@ public class TbUtils { String.class))); parserConfig.addImport("parseInt", new MethodStub(TbUtils.class.getMethod("parseInt", String.class, int.class))); + parserConfig.addImport("parseLong", new MethodStub(TbUtils.class.getMethod("parseLong", + String.class))); + parserConfig.addImport("parseLong", new MethodStub(TbUtils.class.getMethod("parseLong", + String.class, int.class))); parserConfig.addImport("parseFloat", new MethodStub(TbUtils.class.getMethod("parseFloat", String.class))); parserConfig.addImport("parseDouble", new MethodStub(TbUtils.class.getMethod("parseDouble", @@ -76,6 +80,10 @@ public class TbUtils { String.class))); parserConfig.addImport("parseHexToInt", new MethodStub(TbUtils.class.getMethod("parseHexToInt", String.class, boolean.class))); + parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", + String.class))); + parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", + String.class, boolean.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", List.class, int.class, int.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", @@ -84,6 +92,14 @@ public class TbUtils { byte[].class, int.class, int.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", byte[].class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + List.class, int.class, int.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + List.class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + byte[].class, int.class, int.class))); + parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", + byte[].class, int.class, int.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", byte[].class, int.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", @@ -92,16 +108,18 @@ public class TbUtils { List.class, int.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", List.class, int.class))); - parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", - byte[].class, int.class, boolean.class))); parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", byte[].class, int.class))); parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", - List.class, int.class, boolean.class))); + byte[].class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + List.class, int.class))); parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", - List.class, int.class))); + List.class, int.class, boolean.class))); parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", double.class, int.class))); + parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", + float.class, int.class))); parserConfig.addImport("hexToBytes", new MethodStub(TbUtils.class.getMethod("hexToBytes", ExecutionContext.class, String.class))); parserConfig.addImport("base64ToHex", new MethodStub(TbUtils.class.getMethod("base64ToHex", @@ -204,6 +222,38 @@ public class TbUtils { return null; } + public static Long parseLong(String value) { + if (value != null) { + try { + int radix = 10; + if (isHexadecimal(value)) { + radix = 16; + } + return Long.parseLong(prepareNumberString(value), radix); + } catch (NumberFormatException e) { + Double d = parseDouble(value); + if (d != null) { + return d.longValue(); + } + } + } + return null; + } + + public static Long parseLong(String value, int radix) { + if (value != null) { + try { + return Long.parseLong(prepareNumberString(value), radix); + } catch (NumberFormatException e) { + Double d = parseDouble(value); + if (d != null) { + return d.longValue(); + } + } + } + return null; + } + public static Float parseFloat(String value) { if (value != null) { try { @@ -251,6 +301,33 @@ public class TbUtils { return parseBytesToInt(data, 0, data.length, bigEndian); } + public static long parseLittleEndianHexToLong(String hex) { + return parseHexToLong(hex, false); + } + + public static long parseBigEndianHexToLong(String hex) { + return parseHexToInt(hex, true); + } + + public static long parseHexToLong(String hex) { + return parseHexToInt(hex, true); + } + + public static long parseHexToLong(String hex, boolean bigEndian) { + int length = hex.length(); + if (length > 16) { + throw new IllegalArgumentException("Hex string is too large. Maximum 8 symbols allowed."); + } + if (length % 2 > 0) { + throw new IllegalArgumentException("Hex string must be even-length."); + } + byte[] data = new byte[length / 2]; + for (int i = 0; i < length; i += 2) { + data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); + } + return parseBytesToLong(data, 0, data.length, bigEndian); + } + public static ExecutionArrayList hexToBytes(ExecutionContext ctx, String hex) { int len = hex.length(); if (len % 2 > 0) { @@ -312,66 +389,93 @@ public class TbUtils { return bb.getInt(); } - public static float parseBytesToFloat(byte[] data, int offset) { - return parseBytesToFloat(data, offset, true); + public static long parseBytesToLong(List data, int offset, int length) { + return parseBytesToLong(data, offset, length, true); } - public static float parseBytesToFloat(byte[] data, int offset, boolean bigEndian) { - if (data != null && data.length > 0) { - int length = 4; - if (offset > data.length) { - throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); - } - if ((offset + length) > data.length) { - throw new IllegalArgumentException("Default length is always 4 bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); - } - int i = parseBytesToInt(data, offset, length, bigEndian); - return Float.intBitsToFloat(i); - } else { - throw new IllegalArgumentException("Array is null or array length is 0!"); + public static long parseBytesToLong(List data, int offset, int length, boolean bigEndian) { + final byte[] bytes = new byte[data.size()]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = data.get(i); } + return parseBytesToLong(bytes, offset, length, bigEndian); } - public static float parseBytesToFloat(List data, int offset) { + + public static long parseBytesToLong(byte[] data, int offset, int length) { + return parseBytesToLong(data, offset, length, true); + } + + public static long parseBytesToLong(byte[] data, int offset, int length, boolean bigEndian) { + if (offset > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); + } + if (length > 8) { + throw new IllegalArgumentException("Length: " + length + " is too large. Maximum 4 bytes is allowed!"); + } + if (offset + length > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); + } + var bb = ByteBuffer.allocate(8); + if (!bigEndian) { + bb.order(ByteOrder.LITTLE_ENDIAN); + } + bb.position(bigEndian ? 8 - length : 0); + bb.put(data, offset, length); + bb.position(0); + return bb.getLong(); + } + + public static float parseBytesToFloat(byte[] data, int offset) { return parseBytesToFloat(data, offset, true); } + public static float parseBytesToFloat(List data, int offset) { + return parseBytesToFloat(data, offset,true); + } + public static float parseBytesToFloat(List data, int offset, boolean bigEndian) { return parseBytesToFloat(Bytes.toArray(data), offset, bigEndian); } - - public static double parseBytesToDouble(byte[] data, int offset) { - return parseBytesToDouble(data, offset, true); + public static float parseBytesToFloat(byte[] data, int offset, boolean bigEndian) { + byte[] bytesToNumber = prepareBytesToNumber (data, offset, 4, bigEndian); + return ByteBuffer.wrap(bytesToNumber).getFloat(); } - public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) { - if (data != null && data.length > 0) { - int length = 8; - if (offset > data.length) { - throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); - } - if ((offset + length) > data.length) { - throw new IllegalArgumentException("Default length is always 4 bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); - } - byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset+length)); - if (!bigEndian) { - ArrayUtils.reverse(dataBytesArray); - } - return ByteBuffer.wrap(dataBytesArray).getDouble(); - } else { - throw new IllegalArgumentException("Array is null or array length is 0!"); - } + public static double parseBytesToDouble(byte[] data, int offset) { + return parseBytesToDouble(data, offset, true); } public static double parseBytesToDouble(List data, int offset) { - return parseBytesToDouble(data, offset, true); + return parseBytesToDouble(data, offset,true); } public static double parseBytesToDouble(List data, int offset, boolean bigEndian) { return parseBytesToDouble(Bytes.toArray(data), offset, bigEndian); } + public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) { + byte[] bytesToNumber = prepareBytesToNumber (data, offset, 8, bigEndian); + return ByteBuffer.wrap(bytesToNumber).getDouble(); + } + + private static byte [] prepareBytesToNumber(byte[] data, int offset, int length, boolean bigEndian) { + if (offset > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); + } + if ((offset + length) > data.length) { + throw new IllegalArgumentException("Default length is always " + length + " bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); + } + byte[] bytesToNumber = new byte[length]; + byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset+length)); + if (!bigEndian) { + ArrayUtils.reverse(dataBytesArray); + } + System.arraycopy(dataBytesArray, 0, bytesToNumber, 0, length); + return bytesToNumber; + } + public static String bytesToHex(ExecutionArrayList bytesList) { byte[] bytes = new byte[bytesList.size()]; for (int i = 0; i < bytesList.size(); i++) { @@ -394,6 +498,10 @@ public class TbUtils { return BigDecimal.valueOf(value).setScale(precision, RoundingMode.HALF_UP).doubleValue(); } + public static float toFixed(float value, int precision) { + return BigDecimal.valueOf(value).setScale(precision, RoundingMode.HALF_UP).floatValue(); + } + private static boolean isHexadecimal(String value) { return value != null && (value.contains("0x") || value.contains("0X")); } From 59dfb4f4e1b11a18cd409ba058b6f57d084351d1 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 15 Jun 2023 17:02:34 +0300 Subject: [PATCH 120/421] tbel: refactoring prepareBytesToNumber --- .../main/java/org/thingsboard/script/api/tbel/TbUtils.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index d275466b95..dec4ff6f15 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -467,13 +467,11 @@ public class TbUtils { if ((offset + length) > data.length) { throw new IllegalArgumentException("Default length is always " + length + " bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); } - byte[] bytesToNumber = new byte[length]; byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset+length)); if (!bigEndian) { ArrayUtils.reverse(dataBytesArray); } - System.arraycopy(dataBytesArray, 0, bytesToNumber, 0, length); - return bytesToNumber; + return dataBytesArray; } public static String bytesToHex(ExecutionArrayList bytesList) { From f15d84e44aff576ed4208f6d7be5f601d6e882d6 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 15 Jun 2023 19:20:50 +0300 Subject: [PATCH 121/421] tbel: add parseHexToLong, Float, Double --- .../thingsboard/script/api/tbel/TbUtils.java | 109 +++++++++++++----- 1 file changed, 79 insertions(+), 30 deletions(-) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index dec4ff6f15..aced1512b6 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -80,10 +80,6 @@ public class TbUtils { String.class))); parserConfig.addImport("parseHexToInt", new MethodStub(TbUtils.class.getMethod("parseHexToInt", String.class, boolean.class))); - parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", - String.class))); - parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", - String.class, boolean.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", List.class, int.class, int.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", @@ -92,6 +88,14 @@ public class TbUtils { byte[].class, int.class, int.class))); parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", byte[].class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseLittleEndianHexToLong", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToLong", + String.class))); + parserConfig.addImport("parseBigEndianHexToLong", new MethodStub(TbUtils.class.getMethod("parseBigEndianHexToLong", + String.class))); + parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", + String.class))); + parserConfig.addImport("parseHexToLong", new MethodStub(TbUtils.class.getMethod("parseHexToLong", + String.class, boolean.class))); parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", List.class, int.class, int.class))); parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", @@ -100,20 +104,36 @@ public class TbUtils { byte[].class, int.class, int.class))); parserConfig.addImport("parseBytesToLong", new MethodStub(TbUtils.class.getMethod("parseBytesToLong", byte[].class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseLittleEndianHexToFloat", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToFloat", + String.class))); + parserConfig.addImport("parseBigEndianHexToFloat", new MethodStub(TbUtils.class.getMethod("parseBigEndianHexToFloat", + String.class))); + parserConfig.addImport("parseHexToFloat", new MethodStub(TbUtils.class.getMethod("parseHexToFloat", + String.class))); + parserConfig.addImport("parseHexToFloat", new MethodStub(TbUtils.class.getMethod("parseHexToFloat", + String.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", byte[].class, int.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", byte[].class, int.class))); - parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", - List.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", + List.class, int.class, boolean.class))); parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat", List.class, int.class))); + parserConfig.addImport("parseLittleEndianHexToDouble", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToDouble", + String.class))); + parserConfig.addImport("parseBigEndianHexToDouble", new MethodStub(TbUtils.class.getMethod("parseBigEndianHexToDouble", + String.class))); + parserConfig.addImport("parseHexToDouble", new MethodStub(TbUtils.class.getMethod("parseHexToDouble", + String.class))); + parserConfig.addImport("parseHexToDouble", new MethodStub(TbUtils.class.getMethod("parseHexToDouble", + String.class, boolean.class))); parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", byte[].class, int.class))); - parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", byte[].class, int.class, boolean.class))); - parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", - List.class, int.class))); + parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", + List.class, int.class))); parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble", List.class, int.class, boolean.class))); parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", @@ -287,17 +307,7 @@ public class TbUtils { } public static int parseHexToInt(String hex, boolean bigEndian) { - int length = hex.length(); - if (length > 8) { - throw new IllegalArgumentException("Hex string is too large. Maximum 8 symbols allowed."); - } - if (length % 2 > 0) { - throw new IllegalArgumentException("Hex string must be even-length."); - } - byte[] data = new byte[length / 2]; - for (int i = 0; i < length; i += 2) { - data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); - } + byte[] data = prepareHexToBytesNumber(hex, 8); return parseBytesToInt(data, 0, data.length, bigEndian); } @@ -306,16 +316,55 @@ public class TbUtils { } public static long parseBigEndianHexToLong(String hex) { - return parseHexToInt(hex, true); + return parseHexToLong(hex, true); } public static long parseHexToLong(String hex) { - return parseHexToInt(hex, true); + return parseHexToLong(hex, true); } public static long parseHexToLong(String hex, boolean bigEndian) { + byte[] data = prepareHexToBytesNumber(hex, 16); + return parseBytesToLong(data, 0, data.length, bigEndian); + } + + public static float parseLittleEndianHexToFloat(String hex) { + return parseHexToFloat(hex, false); + } + + public static float parseBigEndianHexToFloat(String hex) { + return parseHexToFloat(hex, true); + } + + public static float parseHexToFloat(String hex) { + return parseHexToFloat(hex, true); + } + + public static float parseHexToFloat(String hex, boolean bigEndian) { + byte[] data = prepareHexToBytesNumber(hex, 8); + return parseBytesToFloat(data, 0, bigEndian); + } + + public static double parseLittleEndianHexToDouble(String hex) { + return parseHexToDouble(hex, false); + } + + public static double parseBigEndianHexToDouble(String hex) { + return parseHexToDouble(hex, true); + } + + public static double parseHexToDouble(String hex) { + return parseHexToDouble(hex, true); + } + + public static double parseHexToDouble(String hex, boolean bigEndian) { + byte[] data = prepareHexToBytesNumber(hex, 16); + return parseBytesToDouble(data, 0, bigEndian); + } + + private static byte[] prepareHexToBytesNumber(String hex, int len) { int length = hex.length(); - if (length > 16) { + if (length > len) { throw new IllegalArgumentException("Hex string is too large. Maximum 8 symbols allowed."); } if (length % 2 > 0) { @@ -325,7 +374,7 @@ public class TbUtils { for (int i = 0; i < length; i += 2) { data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); } - return parseBytesToLong(data, 0, data.length, bigEndian); + return data; } public static ExecutionArrayList hexToBytes(ExecutionContext ctx, String hex) { @@ -430,7 +479,7 @@ public class TbUtils { } public static float parseBytesToFloat(List data, int offset) { - return parseBytesToFloat(data, offset,true); + return parseBytesToFloat(data, offset, true); } public static float parseBytesToFloat(List data, int offset, boolean bigEndian) { @@ -438,7 +487,7 @@ public class TbUtils { } public static float parseBytesToFloat(byte[] data, int offset, boolean bigEndian) { - byte[] bytesToNumber = prepareBytesToNumber (data, offset, 4, bigEndian); + byte[] bytesToNumber = prepareBytesToNumber(data, offset, 4, bigEndian); return ByteBuffer.wrap(bytesToNumber).getFloat(); } @@ -448,7 +497,7 @@ public class TbUtils { } public static double parseBytesToDouble(List data, int offset) { - return parseBytesToDouble(data, offset,true); + return parseBytesToDouble(data, offset, true); } public static double parseBytesToDouble(List data, int offset, boolean bigEndian) { @@ -456,18 +505,18 @@ public class TbUtils { } public static double parseBytesToDouble(byte[] data, int offset, boolean bigEndian) { - byte[] bytesToNumber = prepareBytesToNumber (data, offset, 8, bigEndian); + byte[] bytesToNumber = prepareBytesToNumber(data, offset, 8, bigEndian); return ByteBuffer.wrap(bytesToNumber).getDouble(); } - private static byte [] prepareBytesToNumber(byte[] data, int offset, int length, boolean bigEndian) { + private static byte[] prepareBytesToNumber(byte[] data, int offset, int length, boolean bigEndian) { if (offset > data.length) { throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); } if ((offset + length) > data.length) { throw new IllegalArgumentException("Default length is always " + length + " bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); } - byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset+length)); + byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset + length)); if (!bigEndian) { ArrayUtils.reverse(dataBytesArray); } From 7e5069d78452ee48217bbeb22d08476e0ba7ff59 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 16 Jun 2023 09:26:19 +0300 Subject: [PATCH 122/421] Changed test to work with different tenant, to avoid affecting by other tests --- .../server/controller/AlarmControllerTest.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index dccb650555..c2e34c5d2e 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -533,7 +533,7 @@ public class AlarmControllerTest extends AbstractControllerTest { @Test public void testUnassignAlarmOnUserRemoving() throws Exception { - loginTenantAdmin(); + loginDifferentTenant(); User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); @@ -541,7 +541,20 @@ public class AlarmControllerTest extends AbstractControllerTest { user.setEmail("tenantForAssign@thingsboard.org"); User savedUser = createUser(user, "password"); - Alarm alarm = createAlarm(TEST_ALARM_TYPE); + Device device = createDevice("Different tenant device", "default", "differentTenantTest"); + + Alarm alarm = Alarm.builder() + .type(TEST_ALARM_TYPE) + .tenantId(differentTenantId) + .originator(device.getId()) + .severity(AlarmSeverity.MAJOR) + .build(); + alarm = doPost("/api/alarm", alarm, Alarm.class); + Assert.assertNotNull(alarm); + + alarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(alarm); + Mockito.reset(tbClusterService, auditLogService); long beforeAssignmentTs = System.currentTimeMillis(); Thread.sleep(2); From b8e12a46217e6359250b645b33b364d54c39d0a3 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 16 Jun 2023 10:38:55 +0300 Subject: [PATCH 123/421] Refactoring --- .../server/service/entitiy/alarm/DefaultTbAlarmService.java | 4 +--- .../server/service/entitiy/alarm/TbAlarmService.java | 2 +- .../thingsboard/server/controller/AlarmControllerTest.java | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index fc3198a736..07c66e359a 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -216,7 +216,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } @Override - public void unassignUserAlarms(TenantId tenantId, User user, long unassignTs) throws ThingsboardException { + public void unassignUserAlarms(TenantId tenantId, User user, long unassignTs) { AlarmQueryV2 alarmQuery = AlarmQueryV2.builder().assigneeId(user.getId()).pageLink(new TimePageLink(Integer.MAX_VALUE)).build(); try { List alarms = alarmService.findAlarmsV2(tenantId, alarmQuery).get(30, TimeUnit.SECONDS).getData(); @@ -240,8 +240,6 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb log.error("Failed to save alarm comment", e); } notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user); - } else { - throw new ThingsboardException("Alarm was already unassigned!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java index ed4af5d1bd..24af185539 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java @@ -38,7 +38,7 @@ public interface TbAlarmService { AlarmInfo unassign(Alarm alarm, long unassignTs, User user) throws ThingsboardException; - void unassignUserAlarms(TenantId tenantId, User user, long unassignTs) throws ThingsboardException; + void unassignUserAlarms(TenantId tenantId, User user, long unassignTs); Boolean delete(Alarm alarm, User user); } diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index c2e34c5d2e..8f28ca0110 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -557,25 +557,23 @@ public class AlarmControllerTest extends AbstractControllerTest { Mockito.reset(tbClusterService, auditLogService); long beforeAssignmentTs = System.currentTimeMillis(); - Thread.sleep(2); doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); Assert.assertNotNull(foundAlarm); Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); beforeAssignmentTs = System.currentTimeMillis(); Mockito.reset(tbClusterService, auditLogService); doDelete("/api/user/" + savedUser.getId().getId()).andExpect(status().isOk()); - Thread.sleep(2); foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); Assert.assertNotNull(foundAlarm); Assert.assertNull(foundAlarm.getAssigneeId()); - Assert.assertTrue(foundAlarm.getAssignTs() > beforeAssignmentTs); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); } @Test From aa28b276d23210308b93959669ab71de0f0fd4dc Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 16 Jun 2023 15:40:29 +0200 Subject: [PATCH 124/421] added recalculetePartitions delay for node restart --- .../src/main/resources/thingsboard.yml | 1 + .../queue/discovery/ZkDiscoveryService.java | 31 ++++++++++++++++++- .../src/main/resources/tb-vc-executor.yml | 1 + .../src/main/resources/tb-coap-transport.yml | 1 + .../src/main/resources/tb-http-transport.yml | 1 + .../src/main/resources/tb-lwm2m-transport.yml | 1 + .../src/main/resources/tb-mqtt-transport.yml | 1 + .../src/main/resources/tb-snmp-transport.yml | 1 + 8 files changed, 37 insertions(+), 1 deletion(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index e7fbbd2a3d..9cec475335 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -96,6 +96,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cluster: stats: diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index fcf80bcf3d..17d046a4cb 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -44,8 +44,10 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.List; import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -66,6 +68,10 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi private Integer zkSessionTimeout; @Value("${zk.zk_dir}") private String zkDir; + @Value("${zk.recalculate_delay:120000}") + private Long recalculateDelay; + + private final ConcurrentHashMap> delayedTasks; private final TbServiceInfoProvider serviceInfoProvider; private final PartitionService partitionService; @@ -82,6 +88,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi PartitionService partitionService) { this.serviceInfoProvider = serviceInfoProvider; this.partitionService = partitionService; + delayedTasks = new ConcurrentHashMap<>(); } @PostConstruct @@ -290,8 +297,30 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi log.debug("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), instance.getServiceId()); switch (pathChildrenCacheEvent.getType()) { case CHILD_ADDED: + ScheduledFuture task = delayedTasks.remove(instance.getServiceId()); + if (task != null) { + if (!task.cancel(false)) { + log.debug("[{}] Going to recalculate partitions due to adding new node [{}]", + instance.getServiceId(), instance.getServiceTypesList()); + recalculatePartitions(); + } else { + log.debug("[{}] Recalculate partitions ignored. Service restarted in time [{}]", + instance.getServiceId(), instance.getServiceTypesList()); + } + } else { + log.debug("[{}] Going to recalculate partitions due to adding new node [{}]", + instance.getServiceId(), instance.getServiceTypesList()); + recalculatePartitions(); + } + break; case CHILD_REMOVED: - recalculatePartitions(); + ScheduledFuture future = zkExecutorService.schedule(() -> { + log.debug("[{}] Going to recalculate partitions due to removed node [{}]", + instance.getServiceId(), instance.getServiceTypesList()); + delayedTasks.remove(instance.getServiceId()); + recalculatePartitions(); + }, recalculateDelay, TimeUnit.MILLISECONDS); + delayedTasks.put(instance.getServiceId(), future); break; default: break; diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 094e0e2099..2c90082eb5 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" queue: type: "${TB_QUEUE_TYPE:kafka}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index b9db930657..aef46a1234 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index bff7adb561..4bce6e28d7 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -68,6 +68,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index ae8f0138a7..eab5b107c8 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 076dde0234..f0968aa6b9 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index c68c9c56a8..c7dcd70574 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" From 35dfa1e7bd82d9bb1adf75b6d5ceb9ad3cf4ea72 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 16 Jun 2023 18:57:20 +0300 Subject: [PATCH 125/421] tbel: add parseLong Test --- .../thingsboard/script/api/tbel/TbUtils.java | 104 +++++++++++------- .../script/api/tbel/TbUtilsTest.java | 93 ++++++++++++++++ 2 files changed, 155 insertions(+), 42 deletions(-) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index aced1512b6..b337612011 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.StringUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; +import java.math.BigInteger; import java.math.RoundingMode; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -211,69 +212,73 @@ public class TbUtils { } public static Integer parseInt(String value) { - if (value != null) { - try { - int radix = 10; - if (isHexadecimal(value)) { - radix = 16; - } - return Integer.parseInt(prepareNumberString(value), radix); - } catch (NumberFormatException e) { - Float f = parseFloat(value); - if (f != null) { - return f.intValue(); - } - } - } - return null; + int radix = getRadix(value); + return parseInt(value, radix); } public static Integer parseInt(String value, int radix) { - if (value != null) { + if (StringUtils.isNotBlank(value)) { try { - return Integer.parseInt(prepareNumberString(value), radix); - } catch (NumberFormatException e) { - Float f = parseFloat(value); - if (f != null) { - return f.intValue(); + String valueP = prepareNumberString(value); + isValidRadix(valueP, radix); + try { + return Integer.parseInt(valueP, radix); + } catch (NumberFormatException e) { + BigInteger bi = new BigInteger(valueP, radix); + if (bi.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) + throw new NumberFormatException("Value \"" + value + "\" is greater than the maximum Integer value " + Integer.MAX_VALUE + " !"); + if (bi.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0) + throw new NumberFormatException("Value \"" + value + "\" is less than the minimum Integer value " + Integer.MIN_VALUE + " !"); + Float f = parseFloat(valueP); + if (f != null) { + return f.intValue(); + } else { + throw new NumberFormatException(e.getMessage()); + } } + } catch (NumberFormatException e) { + throw new NumberFormatException(e.getMessage()); } } return null; } public static Long parseLong(String value) { - if (value != null) { - try { - int radix = 10; - if (isHexadecimal(value)) { - radix = 16; - } - return Long.parseLong(prepareNumberString(value), radix); - } catch (NumberFormatException e) { - Double d = parseDouble(value); - if (d != null) { - return d.longValue(); - } - } - } - return null; + int radix = getRadix(value); + return parseLong(value, radix); } public static Long parseLong(String value, int radix) { - if (value != null) { + if (StringUtils.isNotBlank(value)) { try { - return Long.parseLong(prepareNumberString(value), radix); - } catch (NumberFormatException e) { - Double d = parseDouble(value); - if (d != null) { - return d.longValue(); + String valueP = prepareNumberString(value); + isValidRadix(valueP, radix); + try { + return Long.parseLong(valueP, radix); + } catch (NumberFormatException e) { + BigInteger bi = new BigInteger(valueP, radix); + if (bi.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) + throw new NumberFormatException("Value \"" + value + "\"is greater than the maximum Long value " + Long.MAX_VALUE + " !"); + if (bi.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0) + throw new NumberFormatException("Value \"" + value + "\" is less than the minimum Long value " + Long.MIN_VALUE + " !"); + Double dd = parseDouble(valueP); + if (dd != null) { + return dd.longValue(); + } else { + throw new NumberFormatException(e.getMessage()); + } } + } catch (NumberFormatException e) { + throw new NumberFormatException(e.getMessage()); } } return null; } + private static int getRadix(String value, int... radixS) { + return radixS.length > 0 ? radixS[0] : isHexadecimal(value) ? 16 : 10; + } + public static Float parseFloat(String value) { if (value != null) { try { @@ -622,4 +627,19 @@ public class TbUtils { } } } + + public static boolean isValidRadix(String value, int radix) { + for (int i = 0; i < value.length(); i++) { + if (i == 0 && value.charAt(i) == '-') { + if (value.length() == 1) + throw new NumberFormatException("Failed radix [" + radix + "] for value: \"" + value + "\"!"); + else + continue; + } + if (Character.digit(value.charAt(i), radix) < 0) + throw new NumberFormatException("Failed radix: [" + radix + "] for value: \"" + value + "\"!"); + } + return true; + } + } diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java index 82cd74ca30..35a8936e4b 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java @@ -26,6 +26,7 @@ import org.mvel2.SandboxedParserConfiguration; import org.mvel2.execution.ExecutionArrayList; import org.mvel2.execution.ExecutionHashMap; +import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Calendar; @@ -182,6 +183,98 @@ public class TbUtilsTest { Assert.assertEquals(expectedMapWithoutPaths, actualMapWithoutPaths); } + @Test + public void parseInt() { + Assert.assertNull(TbUtils.parseInt(null)); + Assert.assertNull(TbUtils.parseInt("")); + Assert.assertNull(TbUtils.parseInt(" ")); + + Assert.assertEquals(java.util.Optional.of(0).get(), TbUtils.parseInt("0")); + Assert.assertEquals(java.util.Optional.of(0).get(), TbUtils.parseInt("-0")); + Assert.assertEquals(java.util.Optional.of(473).get(), TbUtils.parseInt("473")); + Assert.assertEquals(java.util.Optional.of(-255).get(), TbUtils.parseInt("-0xFF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("0xFG")); + + Assert.assertEquals(java.util.Optional.of(102).get(), TbUtils.parseInt("1100110", 2)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("1100210", 2)); + + Assert.assertEquals(java.util.Optional.of(63).get(), TbUtils.parseInt("77", 8)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("18", 8)); + + Assert.assertEquals(java.util.Optional.of(-255).get(), TbUtils.parseInt("-FF", 16)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FG", 16)); + + + Assert.assertEquals(java.util.Optional.of(Integer.MAX_VALUE).get(), TbUtils.parseInt(Integer.toString(Integer.MAX_VALUE), 10)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt(BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.valueOf(1)).toString(10), 10)); + Assert.assertEquals(java.util.Optional.of(Integer.MIN_VALUE).get(), TbUtils.parseInt(Integer.toString(Integer.MIN_VALUE), 10)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt(BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.valueOf(1)).toString(10), 10)); + + Assert.assertEquals(java.util.Optional.of(506070563).get(), TbUtils.parseInt("KonaIn", 30)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("KonaIn", 10)); + } + + @Test + public void parseLong() { + Assert.assertNull(TbUtils.parseLong(null)); + Assert.assertNull(TbUtils.parseLong("")); + Assert.assertNull(TbUtils.parseLong(" ")); + + Assert.assertEquals(java.util.Optional.of(0L).get(), TbUtils.parseLong("0")); + Assert.assertEquals(java.util.Optional.of(0L).get(), TbUtils.parseLong("-0")); + Assert.assertEquals(java.util.Optional.of(473L).get(), TbUtils.parseLong("473")); + Assert.assertEquals(java.util.Optional.of(-65535L).get(), TbUtils.parseLong("-0xFFFF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FFFF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("0xFGFF")); + + Assert.assertEquals(java.util.Optional.of(13158L).get(), TbUtils.parseLong("11001101100110", 2)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("11001101100210", 2)); + + Assert.assertEquals(java.util.Optional.of(9223372036854775807L).get(), TbUtils.parseLong("777777777777777777777", 8)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("1787", 8)); + + Assert.assertEquals(java.util.Optional.of(-255L).get(), TbUtils.parseLong("-FF", 16)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("FG", 16)); + + + Assert.assertEquals(java.util.Optional.of(Long.MAX_VALUE).get(), TbUtils.parseLong(Long.toString(Long.MAX_VALUE), 10)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(1)).toString(10), 10)); + Assert.assertEquals(java.util.Optional.of(Long.MIN_VALUE).get(), TbUtils.parseLong(Long.toString(Long.MIN_VALUE), 10)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.valueOf(1)).toString(10), 10)); + + Assert.assertEquals(java.util.Optional.of(218840926543L).get(), TbUtils.parseLong("KonaLong", 27)); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("KonaLong", 10)); + } + + + // parseLong String.class, int.class +// parseLittleEndianHexToLong String.class + // parseBigEndianHexToLong String.class + // parseHexToLong String.class + // parseHexToLong String.class boolean.class + // parseBytesToLong List.class, int.class, int.class + // parseBytesToLong List.class, int.class, int.class, boolean.class + // parseBytesToLong byte[].class, int.class, int.class + // parseBytesToLong byte[].class, int.class, int.class, boolean.class + // parseLittleEndianHexToFloat String.class + // parseBigEndianHexToFloat String.class + // parseHexToFloat String.class + // parseHexToFloat String.class boolean.class + // parseBytesToFloat byte[].class, int.class, boolean.class + // parseBytesToFloat byte[].class, int.class + // parseBytesToFloat List.class, int.class, boolean.class + // parseBytesToFloat List.class, int.class + // toFixed float.class, int.class + // parseLittleEndianHexToDouble String.class + // parseBigEndianHexToDouble String.class + // parseHexToDouble String.class + // parseHexToDouble String.class boolean.class + // parseBytesToDouble byte[].class, int.class + // parseBytesToDouble byte[].class, int.class, boolean.class + // parseBytesToDouble List.class, int.class + // parseBytesToDouble List.class, int.class boolean.class + private static String keyToValue(String key, String extraSymbol) { return key + "Value" + (extraSymbol == null ? "" : extraSymbol); From ce103cf3396614c5a151c9bfd74c23e4fcbade05 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Mon, 19 Jun 2023 07:27:44 +0300 Subject: [PATCH 126/421] changed test to get id of savedDifferentTenant --- .../org/thingsboard/server/controller/AlarmControllerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index 8f28ca0110..50761be096 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -545,7 +545,7 @@ public class AlarmControllerTest extends AbstractControllerTest { Alarm alarm = Alarm.builder() .type(TEST_ALARM_TYPE) - .tenantId(differentTenantId) + .tenantId(savedDifferentTenant.getId()) .originator(device.getId()) .severity(AlarmSeverity.MAJOR) .build(); From a5990599551233bfc4daec1d3cf3268ea1951888 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 19 Jun 2023 13:31:04 +0300 Subject: [PATCH 127/421] UI: Fixed notify again dialog with template --- .../sent/sent-notification-dialog.componet.ts | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.componet.ts b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.componet.ts index 4846cd063d..765404b880 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.componet.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.componet.ts @@ -154,6 +154,7 @@ export class SentNotificationDialogComponent extends let useTemplate = true; if (isDefinedAndNotNull(this.data.request.template)) { useTemplate = false; + this.refreshAllowDeliveryMethod(); // eslint-disable-next-line guard-for-in for (const method in this.data.request.template.configuration.deliveryMethodsTemplates) { this.deliveryMethodFormsMap.get(NotificationDeliveryMethod[method]) @@ -162,8 +163,6 @@ export class SentNotificationDialogComponent extends } this.notificationRequestForm.get('useTemplate').setValue(useTemplate, {onlySelf : true}); } - - this.refreshAllowDeliveryMethod(); } ngOnDestroy() { @@ -343,13 +342,15 @@ export class SentNotificationDialogComponent extends } private updateDeliveryMethodsDisableState() { - this.notificationDeliveryMethods.forEach(method => { - if (this.allowNotificationDeliveryMethods.includes(method)) { - this.getDeliveryMethodsTemplatesControl(method).enable({emitEvent: true}); - } else { - this.getDeliveryMethodsTemplatesControl(method).disable({emitEvent: true}); - this.getDeliveryMethodsTemplatesControl(method).setValue(false, {emitEvent: true}); //used for notify again - } - }); + if (this.allowNotificationDeliveryMethods) { + this.notificationDeliveryMethods.forEach(method => { + if (this.allowNotificationDeliveryMethods.includes(method)) { + this.getDeliveryMethodsTemplatesControl(method).enable({emitEvent: true}); + } else { + this.getDeliveryMethodsTemplatesControl(method).disable({emitEvent: true}); + this.getDeliveryMethodsTemplatesControl(method).setValue(false, {emitEvent: true}); //used for notify again + } + }); + } } } From 6894ffb8a99b85fabd9c2a21298bfea11de43f95 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 19 Jun 2023 17:38:41 +0300 Subject: [PATCH 128/421] tbel: add Tests - long, float, double --- .../script/api/tbel/TbUtilsTest.java | 134 +++++++++++++----- 1 file changed, 101 insertions(+), 33 deletions(-) diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java index 35a8936e4b..e2f239f30e 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.script.api.tbel; +import com.google.common.primitives.Bytes; import lombok.extern.slf4j.Slf4j; import org.junit.After; import org.junit.Assert; @@ -39,6 +40,23 @@ public class TbUtilsTest { private ExecutionContext ctx; + private final String intValHex = "41EA62CC"; + private final float floatVal = 29.29824f; + private final String floatValStr = "29.29824"; + + + private final String floatValHexRev = "CC62EA41"; + private final float floatValRev = -5.948442E7f; + + private final long longVal = 0x409B04B10CB295EAL; + private final String longValHex = "409B04B10CB295EA"; + private final long longValRev = 0xEA95B20CB1049B40L; + private final String longValHexRev = "EA95B20CB1049B40"; + private final String doubleValStr = "1729.1729"; + private final double doubleVal = 1729.1729; + private final double doubleValRev = -2.7208640774822924E205; + + @Before public void before() { SandboxedParserConfiguration parserConfig = ParserContext.enableSandboxedMode(); @@ -63,6 +81,7 @@ public class TbUtilsTest { @Test public void parseHexToInt() { Assert.assertEquals(0xAB, TbUtils.parseHexToInt("AB")); + Assert.assertEquals(0xABBA, TbUtils.parseHexToInt("ABBA", true)); Assert.assertEquals(0xBAAB, TbUtils.parseHexToInt("ABBA", false)); Assert.assertEquals(0xAABBCC, TbUtils.parseHexToInt("AABBCC", true)); @@ -215,6 +234,37 @@ public class TbUtilsTest { Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("KonaIn", 10)); } + @Test + public void parseFloat() { + Assert.assertEquals(java.util.Optional.of(floatVal).get(), TbUtils.parseFloat(floatValStr)); + } + + @Test + public void toFixedFloat() { + float actualF = TbUtils.toFixed(floatVal, 3); + Assert.assertEquals(1, Float.compare(floatVal, actualF)); + Assert.assertEquals(0, Float.compare(29.298f, actualF)); + } + + @Test + public void parseHexToFloat() { + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseHexToFloat(intValHex))); + Assert.assertEquals(0, Float.compare(floatValRev, TbUtils.parseHexToFloat(intValHex, false))); + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseBigEndianHexToFloat(intValHex))); + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseLittleEndianHexToFloat(floatValHexRev))); + } + + @Test + public void arseBytesToFloat() { + byte[] floatValByte = {65, -22, 98, -52}; + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValByte, 0))); + Assert.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValByte, 0, false))); + + List floatVaList = Bytes.asList(floatValByte); + Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatVaList, 0))); + Assert.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatVaList, 0, false))); + } + @Test public void parseLong() { Assert.assertNull(TbUtils.parseLong(null)); @@ -225,8 +275,8 @@ public class TbUtilsTest { Assert.assertEquals(java.util.Optional.of(0L).get(), TbUtils.parseLong("-0")); Assert.assertEquals(java.util.Optional.of(473L).get(), TbUtils.parseLong("473")); Assert.assertEquals(java.util.Optional.of(-65535L).get(), TbUtils.parseLong("-0xFFFF")); - Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FFFF")); - Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("0xFGFF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("FFFFFFFF")); + Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("0xFGFFFFFF")); Assert.assertEquals(java.util.Optional.of(13158L).get(), TbUtils.parseLong("11001101100110", 2)); Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("11001101100210", 2)); @@ -247,37 +297,55 @@ public class TbUtilsTest { Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("KonaLong", 10)); } + @Test + public void parseHexToLong() { + Assert.assertEquals(longVal, TbUtils.parseHexToLong(longValHex)); + Assert.assertEquals(longVal, TbUtils.parseHexToLong(longValHexRev, false)); + Assert.assertEquals(longVal, TbUtils.parseBigEndianHexToLong(longValHex)); + Assert.assertEquals(longVal, TbUtils.parseLittleEndianHexToLong(longValHexRev)); + } + + @Test + public void parseBytesToLong() { + byte[] longValByte = {64, -101, 4, -79, 12, -78, -107, -22}; + Assert.assertEquals(longVal, TbUtils.parseBytesToLong(longValByte, 0, 8)); + Bytes.reverse(longValByte); + Assert.assertEquals(longVal, TbUtils.parseBytesToLong(longValByte, 0, 8, false)); + + List longVaList = Bytes.asList(longValByte); + Assert.assertEquals(longVal, TbUtils.parseBytesToLong(longVaList, 0, 8, false)); + Assert.assertEquals(longValRev, TbUtils.parseBytesToLong(longVaList, 0, 8)); + } - // parseLong String.class, int.class -// parseLittleEndianHexToLong String.class - // parseBigEndianHexToLong String.class - // parseHexToLong String.class - // parseHexToLong String.class boolean.class - // parseBytesToLong List.class, int.class, int.class - // parseBytesToLong List.class, int.class, int.class, boolean.class - // parseBytesToLong byte[].class, int.class, int.class - // parseBytesToLong byte[].class, int.class, int.class, boolean.class - // parseLittleEndianHexToFloat String.class - // parseBigEndianHexToFloat String.class - // parseHexToFloat String.class - // parseHexToFloat String.class boolean.class - // parseBytesToFloat byte[].class, int.class, boolean.class - // parseBytesToFloat byte[].class, int.class - // parseBytesToFloat List.class, int.class, boolean.class - // parseBytesToFloat List.class, int.class - // toFixed float.class, int.class - // parseLittleEndianHexToDouble String.class - // parseBigEndianHexToDouble String.class - // parseHexToDouble String.class - // parseHexToDouble String.class boolean.class - // parseBytesToDouble byte[].class, int.class - // parseBytesToDouble byte[].class, int.class, boolean.class - // parseBytesToDouble List.class, int.class - // parseBytesToDouble List.class, int.class boolean.class - - - private static String keyToValue(String key, String extraSymbol) { - return key + "Value" + (extraSymbol == null ? "" : extraSymbol); + @Test + public void parsDouble() { + Assert.assertEquals(java.util.Optional.of(doubleVal).get(), TbUtils.parseDouble(doubleValStr)); + } + + @Test + public void toFixedDouble() { + double actualD = TbUtils.toFixed(doubleVal, 3); + Assert.assertEquals(-1, Double.compare(doubleVal, actualD)); + Assert.assertEquals(0, Double.compare(1729.173, actualD)); + } + + @Test + public void parseHexToDouble() { + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseHexToDouble(longValHex))); + Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseHexToDouble(longValHex, false))); + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBigEndianHexToDouble(longValHex))); + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseLittleEndianHexToDouble(longValHexRev))); + } + + @Test + public void arseBytesToDouble() { + byte[] doubleValByte = {64, -101, 4, -79, 12, -78, -107, -22}; + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValByte, 0))); + Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, false))); + + List doubleVaList = Bytes.asList(doubleValByte); + Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleVaList, 0))); + Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleVaList, 0, false))); } private static List toList(byte[] data) { @@ -287,5 +355,5 @@ public class TbUtilsTest { } return result; } - } + From d9c028f566ec695f6d9b975bd5c86abd1564af9d Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Mon, 19 Jun 2023 17:41:28 +0300 Subject: [PATCH 129/421] tbel: add Tests - long, float, double (syntax) --- .../test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java index e2f239f30e..b6d5395af8 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java @@ -338,7 +338,7 @@ public class TbUtilsTest { } @Test - public void arseBytesToDouble() { + public void parseBytesToDouble() { byte[] doubleValByte = {64, -101, 4, -79, 12, -78, -107, -22}; Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValByte, 0))); Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, false))); From 22874e8a65c1a353bc639be00f005a75030b9be9 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 19 Jun 2023 17:55:39 +0300 Subject: [PATCH 130/421] filter nodes && added TbMsgType enum --- .../actors/ruleChain/DefaultTbContext.java | 26 ++--- .../RuleChainActorMessageProcessor.java | 4 +- .../server/controller/RpcV2Controller.java | 4 +- .../service/action/EntityActionService.java | 94 ++---------------- .../AnnotationComponentDiscoveryService.java | 25 +++-- .../device/DeviceProvisionServiceImpl.java | 24 +++-- .../service/edge/rpc/EdgeGrpcService.java | 10 +- .../processor/device/DeviceEdgeProcessor.java | 6 +- .../telemetry/BaseTelemetryProcessor.java | 4 +- .../DefaultTbNotificationEntityService.java | 5 +- .../rpc/DefaultTbCoreDeviceRpcService.java | 5 +- .../state/DefaultDeviceStateService.java | 18 ++-- .../transport/DefaultTransportApiService.java | 3 +- .../server/common/data/DataConstants.java | 44 --------- .../server/common/data/EntityType.java | 8 ++ .../server/common/data/audit/ActionType.java | 88 +++++++++-------- .../server/common/data/msg/TbMsgType.java | 95 +++++++++++++++++++ .../engine/api/EmptyNodeConfiguration.java | 3 +- ...onTypes.java => TbNodeConnectionType.java} | 9 +- .../engine/action/TbAbstractAlarmNode.java | 15 ++- .../action/TbAbstractRelationActionNode.java | 4 +- .../TbCopyAttributesToEntityViewNode.java | 22 +++-- .../rule/engine/action/TbMsgCountNode.java | 2 +- .../rule/engine/debug/TbMsgGeneratorNode.java | 2 +- .../deduplication/TbMsgDeduplicationNode.java | 4 +- .../rule/engine/delay/TbMsgDelayNode.java | 2 +- .../engine/edge/AbstractTbMsgPushNode.java | 52 ++++++---- .../engine/filter/TbAssetTypeSwitchNode.java | 3 +- .../engine/filter/TbCheckAlarmStatusNode.java | 37 +++----- .../filter/TbCheckAlarmStatusNodeConfig.java | 4 +- .../engine/filter/TbCheckMessageNode.java | 13 +-- .../engine/filter/TbCheckRelationNode.java | 29 +++--- .../engine/filter/TbDeviceTypeSwitchNode.java | 3 +- .../rule/engine/filter/TbJsFilterNode.java | 9 +- .../rule/engine/filter/TbJsSwitchNode.java | 3 +- .../engine/filter/TbMsgTypeFilterNode.java | 8 +- .../engine/filter/TbMsgTypeSwitchNode.java | 86 +---------------- .../filter/TbOriginatorTypeFilterNode.java | 8 +- .../filter/TbOriginatorTypeSwitchNode.java | 50 +--------- .../rule/engine/flow/TbCheckpointNode.java | 4 +- .../engine/geo/TbGpsGeofencingFilterNode.java | 8 +- .../rule/engine/kafka/TbKafkaNode.java | 4 +- .../rule/engine/mail/TbMsgToEmailNode.java | 3 +- .../TbAbstractGetEntityDetailsNode.java | 2 +- .../rule/engine/profile/DeviceState.java | 31 ++++-- .../engine/profile/TbDeviceProfileNode.java | 8 +- .../rule/engine/rest/TbHttpClient.java | 4 +- .../rule/engine/rpc/TbSendRPCRequestNode.java | 7 +- .../transform/TbAbstractTransformNode.java | 4 +- .../engine/transform/TbSplitArrayMsgNode.java | 4 +- .../action/TbCreateRelationNodeTest.java | 13 +-- .../engine/edge/TbMsgPushToEdgeNodeTest.java | 18 ++-- .../engine/filter/TbJsFilterNodeTest.java | 14 +-- .../rule/engine/profile/DeviceStateTest.java | 15 +-- .../transform/TbMsgDeduplicationNodeTest.java | 12 +-- 55 files changed, 464 insertions(+), 518 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java rename rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/{TbRelationTypes.java => TbNodeConnectionType.java} (74%) diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 8b76924d96..778a3db51f 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.actors.ruleChain; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.netty.channel.EventLoopGroup; @@ -34,7 +33,7 @@ import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.rule.engine.api.ScriptEngine; import org.thingsboard.rule.engine.api.SmsService; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.slack.SlackService; import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; import org.thingsboard.rule.engine.util.TenantIdLoader; @@ -42,7 +41,6 @@ import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.TbActorRef; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.Customer; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityType; @@ -114,6 +112,10 @@ import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED; + /** * Created by ashvayka on 19.03.18. */ @@ -132,7 +134,7 @@ class DefaultTbContext implements TbContext { @Override public void tellSuccess(TbMsg msg) { - tellNext(msg, Collections.singleton(TbRelationTypes.SUCCESS), null); + tellNext(msg, Collections.singleton(TbNodeConnectionType.SUCCESS), null); } @Override @@ -211,7 +213,7 @@ class DefaultTbContext implements TbContext { @Override public void enqueueForTellFailure(TbMsg tbMsg, String failureMessage) { TopicPartitionInfo tpi = resolvePartition(tbMsg); - enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbRelationTypes.FAILURE), failureMessage, null, null); + enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbNodeConnectionType.FAILURE), failureMessage, null, null); } @Override @@ -309,7 +311,7 @@ class DefaultTbContext implements TbContext { @Override public void tellFailure(TbMsg msg, Throwable th) { if (nodeCtx.getSelf().isDebugMode()) { - mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th); + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbNodeConnectionType.FAILURE, th); } String failureMessage; if (th != null) { @@ -322,7 +324,7 @@ class DefaultTbContext implements TbContext { failureMessage = null; } nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getRuleChainId(), - nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), + nodeCtx.getSelf().getId(), Collections.singleton(TbNodeConnectionType.FAILURE), msg, failureMessage)); } @@ -346,7 +348,7 @@ class DefaultTbContext implements TbContext { } public TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId) { - return entityActionMsg(customer, customer.getId(), ruleNodeId, DataConstants.ENTITY_CREATED); + return entityActionMsg(customer, customer.getId(), ruleNodeId, ENTITY_CREATED.name()); } public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) { @@ -354,7 +356,7 @@ class DefaultTbContext implements TbContext { if (device.getDeviceProfileId() != null) { deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId()); } - return entityActionMsg(device, device.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, deviceProfile); + return entityActionMsg(device, device.getId(), ruleNodeId, ENTITY_CREATED.name(), deviceProfile); } public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) { @@ -362,7 +364,7 @@ class DefaultTbContext implements TbContext { if (asset.getAssetProfileId() != null) { assetProfile = mainCtx.getAssetProfileCache().find(asset.getAssetProfileId()); } - return entityActionMsg(asset, asset.getId(), ruleNodeId, DataConstants.ENTITY_CREATED, assetProfile); + return entityActionMsg(asset, asset.getId(), ruleNodeId, ENTITY_CREATED.name(), assetProfile); } public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) { @@ -382,7 +384,7 @@ class DefaultTbContext implements TbContext { if (attributes != null) { attributes.forEach(attributeKvEntry -> JacksonUtil.addKvEntry(entityNode, attributeKvEntry)); } - return attributesActionMsg(originator, ruleNodeId, scope, DataConstants.ATTRIBUTES_UPDATED, JacksonUtil.toString(entityNode)); + return attributesActionMsg(originator, ruleNodeId, scope, ATTRIBUTES_UPDATED.name(), JacksonUtil.toString(entityNode)); } public TbMsg attributesDeletedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List keys) { @@ -391,7 +393,7 @@ class DefaultTbContext implements TbContext { if (keys != null) { keys.forEach(attrsArrayNode::add); } - return attributesActionMsg(originator, ruleNodeId, scope, DataConstants.ATTRIBUTES_DELETED, JacksonUtil.toString(entityNode)); + return attributesActionMsg(originator, ruleNodeId, scope, ATTRIBUTES_DELETED.name(), JacksonUtil.toString(entityNode)); } private TbMsg attributesActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, String action, String msgData) { diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java index 4bd082ee38..351a012d73 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java @@ -16,7 +16,7 @@ package org.thingsboard.server.actors.ruleChain; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.TbActorCtx; import org.thingsboard.server.actors.TbActorRef; @@ -307,7 +307,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor msgType = actionType.getRuleEngineMsgType(); + if (msgType.isPresent()) { try { TbMsgMetaData metaData = new TbMsgMetaData(); if (user != null) { @@ -247,7 +171,7 @@ public class EntityActionService { if (tenantId != null && !tenantId.isSysTenantId()) { processNotificationRules(tenantId, entityId, entity, actionType, user, additionalInfo); } - TbMsg tbMsg = TbMsg.newMsg(msgType, entityId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); + TbMsg tbMsg = TbMsg.newMsg(msgType.get().name(), entityId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, null); } catch (Exception e) { log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e); diff --git a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java index ad65ee805b..e8fff7ba60 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java @@ -30,8 +30,12 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.NodeConfiguration; import org.thingsboard.rule.engine.api.NodeDefinition; import org.thingsboard.rule.engine.api.RuleNode; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.TbVersionedNode; +import org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode; +import org.thingsboard.rule.engine.filter.TbOriginatorTypeSwitchNode; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -194,7 +198,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe scannedComponent.setName(ruleNodeAnnotation.name()); scannedComponent.setScope(ruleNodeAnnotation.scope()); scannedComponent.setClusteringMode(ruleNodeAnnotation.clusteringMode()); - NodeDefinition nodeDefinition = prepareNodeDefinition(ruleNodeAnnotation); + NodeDefinition nodeDefinition = prepareNodeDefinition(clazz, ruleNodeAnnotation); ObjectNode configurationDescriptor = JacksonUtil.newObjectNode(); JsonNode node = JacksonUtil.valueToTree(nodeDefinition); configurationDescriptor.set("nodeDefinition", node); @@ -221,13 +225,13 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe return scannedComponent; } - private NodeDefinition prepareNodeDefinition(RuleNode nodeAnnotation) throws Exception { + private NodeDefinition prepareNodeDefinition(Class clazz, RuleNode nodeAnnotation) throws Exception { NodeDefinition nodeDefinition = new NodeDefinition(); nodeDefinition.setDetails(nodeAnnotation.nodeDetails()); nodeDefinition.setDescription(nodeAnnotation.nodeDescription()); nodeDefinition.setInEnabled(nodeAnnotation.inEnabled()); nodeDefinition.setOutEnabled(nodeAnnotation.outEnabled()); - nodeDefinition.setRelationTypes(getRelationTypesWithFailureRelation(nodeAnnotation)); + nodeDefinition.setRelationTypes(getRelationTypesWithFailureRelation(clazz, nodeAnnotation)); nodeDefinition.setCustomRelations(nodeAnnotation.customRelations()); nodeDefinition.setRuleChainNode(nodeAnnotation.ruleChainNode()); Class configClazz = nodeAnnotation.configClazz(); @@ -242,10 +246,17 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe return nodeDefinition; } - private String[] getRelationTypesWithFailureRelation(RuleNode nodeAnnotation) { + private String[] getRelationTypesWithFailureRelation(Class clazz, RuleNode nodeAnnotation) { List relationTypes = new ArrayList<>(Arrays.asList(nodeAnnotation.relationTypes())); - if (!relationTypes.contains(TbRelationTypes.FAILURE)) { - relationTypes.add(TbRelationTypes.FAILURE); + if (TbOriginatorTypeSwitchNode.class.equals(clazz)) { + relationTypes.addAll(EntityType.NORMAL_NAMES); + } + if (TbMsgTypeSwitchNode.class.equals(clazz)) { + relationTypes.addAll(TbMsgType.NODE_CONNECTIONS); + relationTypes.add(TbMsgType.OTHER); + } + if (!relationTypes.contains(TbNodeConnectionType.FAILURE)) { + relationTypes.add(TbNodeConnectionType.FAILURE); } return relationTypes.toArray(new String[relationTypes.size()]); } diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java index beecebe2ba..3bed8a1905 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java @@ -23,7 +23,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @@ -69,6 +68,11 @@ import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED; +import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_FAILURE; +import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_SUCCESS; + @Service @Slf4j @@ -162,7 +166,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { if (targetProfile.getProfileData().getProvisionConfiguration().getProvisionDeviceSecret().equals(provisionRequestSecret)) { if (targetDevice != null) { log.warn("[{}] The device is present and could not be provisioned once more!", targetDevice.getName()); - notify(targetDevice, provisionRequest, DataConstants.PROVISION_FAILURE, false); + notify(targetDevice, provisionRequest, PROVISION_FAILURE.name(), false); throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); } else { return createDevice(provisionRequest, targetProfile); @@ -188,13 +192,13 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { private ProvisionResponse processProvision(Device device, ProvisionRequest provisionRequest) { try { Optional provisionState = attributesService.find(device.getTenantId(), device.getId(), - DataConstants.SERVER_SCOPE, DEVICE_PROVISION_STATE).get(); + SERVER_SCOPE, DEVICE_PROVISION_STATE).get(); if (provisionState != null && provisionState.isPresent() && !provisionState.get().getValueAsString().equals(PROVISIONED_STATE)) { - notify(device, provisionRequest, DataConstants.PROVISION_FAILURE, false); + notify(device, provisionRequest, PROVISION_FAILURE.name(), false); throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); } else { saveProvisionStateAttribute(device).get(); - notify(device, provisionRequest, DataConstants.PROVISION_SUCCESS, true); + notify(device, provisionRequest, PROVISION_SUCCESS.name(), true); } } catch (InterruptedException | ExecutionException e) { throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); @@ -222,14 +226,14 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { clusterService.onDeviceUpdated(savedDevice, null); saveProvisionStateAttribute(savedDevice).get(); pushDeviceCreatedEventToRuleEngine(savedDevice); - notify(savedDevice, provisionRequest, DataConstants.PROVISION_SUCCESS, true); + notify(savedDevice, provisionRequest, PROVISION_SUCCESS.name(), true); return new ProvisionResponse(getDeviceCredentials(savedDevice), ProvisionResponseStatus.SUCCESS); } catch (Exception e) { log.warn("[{}] Error during device creation from provision request: [{}]", provisionRequest.getDeviceName(), provisionRequest, e); Device device = deviceService.findDeviceByTenantIdAndName(profile.getTenantId(), provisionRequest.getDeviceName()); if (device != null) { - notify(device, provisionRequest, DataConstants.PROVISION_FAILURE, false); + notify(device, provisionRequest, PROVISION_FAILURE.name(), false); } throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); } @@ -244,7 +248,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { } private ListenableFuture> saveProvisionStateAttribute(Device device) { - return attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE, + return attributesService.save(device.getTenantId(), device.getId(), SERVER_SCOPE, Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry(DEVICE_PROVISION_STATE, PROVISIONED_STATE), System.currentTimeMillis()))); } @@ -266,10 +270,10 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { private void pushDeviceCreatedEventToRuleEngine(Device device) { try { ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device); - TbMsg msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); + TbMsg msg = TbMsg.newMsg(ENTITY_CREATED.name(), device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); sendToRuleEngine(device.getTenantId(), msg, null); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), DataConstants.ENTITY_CREATED, e); + log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), ENTITY_CREATED, e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index b7334ebf5a..233dcba2cc 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -71,9 +71,9 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; -import static org.thingsboard.server.common.data.DataConstants.CONNECT_EVENT; -import static org.thingsboard.server.common.data.DataConstants.DISCONNECT_EVENT; import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; +import static org.thingsboard.server.common.data.msg.TbMsgType.CONNECT_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.DISCONNECT_EVENT; @Service @Slf4j @@ -278,7 +278,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true); long lastConnectTs = System.currentTimeMillis(); save(edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, lastConnectTs); - pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, CONNECT_EVENT); + pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, CONNECT_EVENT.name()); cancelScheduleEdgeEventsCheck(edgeId); scheduleEdgeEventsCheck(edgeGrpcSession); } @@ -395,7 +395,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false); long lastDisconnectTs = System.currentTimeMillis(); save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs); - pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, DISCONNECT_EVENT); + pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, DISCONNECT_EVENT.name()); cancelScheduleEdgeEventsCheck(edgeId); } else { log.debug("[{}] edge session [{}] is not available anymore, nothing to remove. most probably this session is already outdated!", edgeId, sessionId); @@ -451,7 +451,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i private void pushRuleEngineMessage(TenantId tenantId, EdgeId edgeId, long ts, String msgType) { try { ObjectNode edgeState = JacksonUtil.newObjectNode(); - if (msgType.equals(CONNECT_EVENT)) { + if (msgType.equals(CONNECT_EVENT.name())) { edgeState.put(DefaultDeviceStateService.ACTIVITY_STATE, true); edgeState.put(DefaultDeviceStateService.LAST_CONNECT_TIME, ts); } else { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java index 3e617de8c6..0d48f1532f 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java @@ -62,6 +62,8 @@ import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg; import java.util.UUID; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED; + @Component @Slf4j @TbCoreComponent @@ -124,7 +126,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { try { Device device = deviceService.findDeviceById(tenantId, deviceId); ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device); - TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, device.getCustomerId(), + TbMsg tbMsg = TbMsg.newMsg(ENTITY_CREATED.name(), deviceId, device.getCustomerId(), getActionTbMsgMetaData(edge, device.getCustomerId()), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() { @Override @@ -138,7 +140,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { } }); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, DataConstants.ENTITY_CREATED, e); + log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, ENTITY_CREATED.name(), e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java index fece86b92a..6a7ffe2c40 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java @@ -73,6 +73,8 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; + @Slf4j public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { @@ -257,7 +259,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { @Override public void onSuccess(@Nullable Void tmp) { var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), DataConstants.ATTRIBUTES_UPDATED, entityId, + TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), ATTRIBUTES_UPDATED.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index 0a75404fb4..719158403c 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -21,7 +21,6 @@ import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; import org.thingsboard.server.cluster.TbClusterService; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasName; @@ -53,6 +52,8 @@ import org.thingsboard.server.service.gateway_device.GatewayNotificationsService import java.util.List; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED_FROM_TENANT; + @Slf4j @Service @RequiredArgsConstructor @@ -286,7 +287,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) { String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice)); if (data != null) { - TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), + TbMsg tbMsg = TbMsg.newMsg(ENTITY_ASSIGNED_FROM_TENANT.name(), assignedDevice.getId(), assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data); tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null); } diff --git a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java index bca7c7d81a..2ec8f09bd0 100644 --- a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.rpc; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -49,6 +48,8 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import static org.thingsboard.server.common.data.msg.TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE; + /** * Created by ashvayka on 27.03.18. */ @@ -182,7 +183,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { entityNode.put(DataConstants.ADDITIONAL_INFO, msg.getAdditionalInfo()); try { - TbMsg tbMsg = TbMsg.newMsg(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null), metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); + TbMsg tbMsg = TbMsg.newMsg(RPC_CALL_FROM_SERVER_TO_DEVICE.name(), msg.getDeviceId(), Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null), metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null); } catch (IllegalArgumentException e) { throw new RuntimeException(e); diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 554359fd6d..965b781fe9 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -51,6 +51,7 @@ import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.query.EntityData; @@ -63,7 +64,6 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; -import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; @@ -102,11 +102,11 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import static org.thingsboard.server.common.data.DataConstants.ACTIVITY_EVENT; -import static org.thingsboard.server.common.data.DataConstants.CONNECT_EVENT; -import static org.thingsboard.server.common.data.DataConstants.DISCONNECT_EVENT; -import static org.thingsboard.server.common.data.DataConstants.INACTIVITY_EVENT; import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; +import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.CONNECT_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.DISCONNECT_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; /** * Created by ashvayka on 01.05.18. @@ -229,7 +229,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService NORMAL_NAMES = EnumSet.allOf(EntityType.class).stream() + .map(EntityType::getNormalName).collect(Collectors.toUnmodifiableList()); + @Getter private final String normalName = StringUtils.capitalize(StringUtils.removeStart(name(), "TB_") .toLowerCase().replaceAll("_", " ")); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java b/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java index 01009751d4..056be5a958 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java @@ -16,49 +16,61 @@ package org.thingsboard.server.common.data.audit; import lombok.Getter; +import org.thingsboard.server.common.data.msg.TbMsgType; + +import java.util.Optional; -@Getter public enum ActionType { - ADDED(false), // log entity - DELETED(false), // log string id - UPDATED(false), // log entity - ATTRIBUTES_UPDATED(false), // log attributes/values - ATTRIBUTES_DELETED(false), // log attributes - TIMESERIES_UPDATED(false), // log timeseries update - TIMESERIES_DELETED(false), // log timeseries - RPC_CALL(false), // log method and params - CREDENTIALS_UPDATED(false), // log new credentials - ASSIGNED_TO_CUSTOMER(false), // log customer name - UNASSIGNED_FROM_CUSTOMER(false), // log customer name - ACTIVATED(false), // log string id - SUSPENDED(false), // log string id - CREDENTIALS_READ(true), // log device id - ATTRIBUTES_READ(true), // log attributes - RELATION_ADD_OR_UPDATE(false), - RELATION_DELETED(false), - RELATIONS_DELETED(false), - ALARM_ACK(false), - ALARM_CLEAR(false), - ALARM_DELETE(false), - ALARM_ASSIGNED(false), - ALARM_UNASSIGNED(false), - LOGIN(false), - LOGOUT(false), - LOCKOUT(false), - ASSIGNED_FROM_TENANT(false), - ASSIGNED_TO_TENANT(false), - PROVISION_SUCCESS(false), - PROVISION_FAILURE(false), - ASSIGNED_TO_EDGE(false), // log edge name - UNASSIGNED_FROM_EDGE(false), - ADDED_COMMENT(false), - UPDATED_COMMENT(false), - DELETED_COMMENT(false), - SMS_SENT(false); + ADDED(false, TbMsgType.ENTITY_CREATED), // log entity + DELETED(false, TbMsgType.ENTITY_DELETED), // log string id + UPDATED(false, TbMsgType.ENTITY_UPDATED), // log entity + ATTRIBUTES_UPDATED(false, TbMsgType.ATTRIBUTES_UPDATED), // log attributes/values + ATTRIBUTES_DELETED(false, TbMsgType.ATTRIBUTES_DELETED), // log attributes + TIMESERIES_UPDATED(false, TbMsgType.TIMESERIES_UPDATED), // log timeseries update + TIMESERIES_DELETED(false, TbMsgType.TIMESERIES_DELETED), // log timeseries + RPC_CALL(false, null), // log method and params + CREDENTIALS_UPDATED(false, null), // log new credentials + ASSIGNED_TO_CUSTOMER(false, TbMsgType.ENTITY_ASSIGNED), // log customer name + UNASSIGNED_FROM_CUSTOMER(false, TbMsgType.ENTITY_UNASSIGNED), // log customer name + ACTIVATED(false, null), // log string id + SUSPENDED(false, null), // log string id + CREDENTIALS_READ(true, null), // log device id + ATTRIBUTES_READ(true, null), // log attributes + RELATION_ADD_OR_UPDATE(false, TbMsgType.RELATION_ADD_OR_UPDATE), + RELATION_DELETED(false, TbMsgType.RELATION_DELETED), + RELATIONS_DELETED(false, TbMsgType.RELATIONS_DELETED), + ALARM_ACK(false, TbMsgType.ALARM_ACK), + ALARM_CLEAR(false, TbMsgType.ALARM_CLEAR), + ALARM_DELETE(false, TbMsgType.ALARM_DELETE), + ALARM_ASSIGNED(false, TbMsgType.ALARM_ASSIGNED), + ALARM_UNASSIGNED(false, TbMsgType.ALARM_UNASSIGNED), + LOGIN(false, null), + LOGOUT(false, null), + LOCKOUT(false, null), + ASSIGNED_FROM_TENANT(false, TbMsgType.ENTITY_ASSIGNED_FROM_TENANT), + ASSIGNED_TO_TENANT(false, TbMsgType.ENTITY_ASSIGNED_TO_TENANT), + PROVISION_SUCCESS(false, TbMsgType.PROVISION_SUCCESS), + PROVISION_FAILURE(false, TbMsgType.PROVISION_FAILURE), + ASSIGNED_TO_EDGE(false, TbMsgType.ENTITY_ASSIGNED_TO_EDGE), // log edge name + UNASSIGNED_FROM_EDGE(false, TbMsgType.ENTITY_UNASSIGNED_FROM_EDGE), + ADDED_COMMENT(false, TbMsgType.COMMENT_CREATED), + UPDATED_COMMENT(false, TbMsgType.COMMENT_UPDATED), + DELETED_COMMENT(false, null), + SMS_SENT(false, null); + + @Getter private final boolean isRead; - ActionType(boolean isRead) { + private final TbMsgType ruleEngineMsgType; + + ActionType(boolean isRead, TbMsgType ruleEngineMsgType) { this.isRead = isRead; + this.ruleEngineMsgType = ruleEngineMsgType; } + + public Optional getRuleEngineMsgType() { + return Optional.ofNullable(ruleEngineMsgType); + } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java new file mode 100644 index 0000000000..645b8cc9fd --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java @@ -0,0 +1,95 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.msg; + +import lombok.Getter; + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public enum TbMsgType { + + POST_ATTRIBUTES_REQUEST("Post attributes"), + POST_TELEMETRY_REQUEST("Post telemetry"), + TO_SERVER_RPC_REQUEST("RPC Request from Device"), + ACTIVITY_EVENT("Activity Event"), + INACTIVITY_EVENT("Inactivity Event"), + CONNECT_EVENT("Connect Event"), + DISCONNECT_EVENT("Disconnect Event"), + ENTITY_CREATED("Entity Created"), + ENTITY_UPDATED("Entity Updated"), + ENTITY_DELETED("Entity Deleted"), + ENTITY_ASSIGNED("Entity Assigned"), + ENTITY_UNASSIGNED("Entity Unassigned"), + ATTRIBUTES_UPDATED("Attributes Updated"), + ATTRIBUTES_DELETED("Attributes Deleted"), + ALARM(null), + ALARM_ACK("Alarm Acknowledged"), + ALARM_CLEAR("Alarm Cleared"), + ALARM_DELETE("Alarm Deleted"), + ALARM_ASSIGNED("Alarm Assigned"), + ALARM_UNASSIGNED("Alarm Unassigned"), + COMMENT_CREATED("Comment Created"), + COMMENT_UPDATED("Comment Updated"), + RPC_CALL_FROM_SERVER_TO_DEVICE("RPC Request to Device"), + ENTITY_ASSIGNED_FROM_TENANT("Entity Assigned From Tenant"), + ENTITY_ASSIGNED_TO_TENANT("Entity Assigned To Tenant"), + ENTITY_ASSIGNED_TO_EDGE(null), + ENTITY_UNASSIGNED_FROM_EDGE(null), + TIMESERIES_UPDATED("Timeseries Updated"), + TIMESERIES_DELETED("Timeseries Deleted"), + RPC_QUEUED("RPC Queued"), + RPC_SENT("RPC Sent"), + RPC_DELIVERED("RPC Delivered"), + RPC_SUCCESSFUL("RPC Successful"), + RPC_TIMEOUT("RPC Timeout"), + RPC_EXPIRED("RPC Expired"), + RPC_FAILED("RPC Failed"), + RPC_DELETED("RPC Deleted"), + RELATION_ADD_OR_UPDATE("Relation Added or Updated"), + RELATION_DELETED("Relation Deleted"), + RELATIONS_DELETED("All Relations Deleted"), + PROVISION_SUCCESS(null), + PROVISION_FAILURE(null); + + public static final String OTHER = "Other"; + + public static final List NODE_CONNECTIONS = EnumSet.allOf(TbMsgType.class).stream() + .map(TbMsgType::getNodeConnection).filter(Objects::nonNull).collect(Collectors.toUnmodifiableList()); + + @Getter + private final String nodeConnection; + + TbMsgType(String nodeConnection) { + this.nodeConnection = nodeConnection; + } + + public static String getNodeConnection(String msgType) { + if (msgType == null) { + return OTHER; + } else { + return Arrays.stream(TbMsgType.values()) + .filter(type -> type.name().equals(msgType)) + .findFirst() + .map(TbMsgType::getNodeConnection) + .orElse(OTHER); + } + } + +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EmptyNodeConfiguration.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EmptyNodeConfiguration.java index 5c54687205..22ffe34769 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EmptyNodeConfiguration.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EmptyNodeConfiguration.java @@ -24,7 +24,6 @@ public class EmptyNodeConfiguration implements NodeConfiguration { if (alarmResult.alarm == null) { - ctx.tellNext(msg, "False"); + ctx.tellNext(msg, TbNodeConnectionType.FALSE); } else if (alarmResult.isCreated) { - tellNext(ctx, msg, alarmResult, DataConstants.ENTITY_CREATED, "Created"); + tellNext(ctx, msg, alarmResult, ENTITY_CREATED.name(), "Created"); } else if (alarmResult.isUpdated) { - tellNext(ctx, msg, alarmResult, DataConstants.ENTITY_UPDATED, "Updated"); + tellNext(ctx, msg, alarmResult, ENTITY_UPDATED.name(), "Updated"); } else if (alarmResult.isCleared) { - tellNext(ctx, msg, alarmResult, DataConstants.ALARM_CLEAR, "Cleared"); + tellNext(ctx, msg, alarmResult, ALARM_CLEAR.name(), "Cleared"); } else { ctx.tellSuccess(msg); } @@ -96,7 +101,7 @@ public abstract class TbAbstractAlarmNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index 6f7bb7cf8d..61004bfa11 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -36,7 +36,6 @@ import org.thingsboard.server.common.data.objects.AttributesEntityView; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import javax.annotation.Nullable; @@ -45,7 +44,12 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; +import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; +import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; +import static org.thingsboard.rule.engine.api.TbNodeConnectionType.SUCCESS; @Slf4j @RuleNode( @@ -71,14 +75,14 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) || - DataConstants.ATTRIBUTES_DELETED.equals(msg.getType()) || - DataConstants.ACTIVITY_EVENT.equals(msg.getType()) || - DataConstants.INACTIVITY_EVENT.equals(msg.getType()) || - SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType())) { + if (ATTRIBUTES_UPDATED.name().equals(msg.getType()) || + ATTRIBUTES_DELETED.name().equals(msg.getType()) || + ACTIVITY_EVENT.name().equals(msg.getType()) || + INACTIVITY_EVENT.name().equals(msg.getType()) || + POST_ATTRIBUTES_REQUEST.name().equals(msg.getType())) { if (!msg.getMetaData().getData().isEmpty()) { long now = System.currentTimeMillis(); - String scope = msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ? + String scope = msg.getType().equals(POST_ATTRIBUTES_REQUEST.name()) ? DataConstants.CLIENT_SCOPE : msg.getMetaData().getValue(DataConstants.SCOPE); ListenableFuture> entityViewsFuture = @@ -90,7 +94,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { long startTime = entityView.getStartTimeMs(); long endTime = entityView.getEndTimeMs(); if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) { - if (DataConstants.ATTRIBUTES_DELETED.equals(msg.getType())) { + if (ATTRIBUTES_DELETED.name().equals(msg.getType())) { List attributes = new ArrayList<>(); for (JsonElement element : new JsonParser().parse(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray()) { if (element.isJsonPrimitive()) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java index 88f2be46a8..58c42a1109 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java @@ -33,7 +33,7 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; +import static org.thingsboard.rule.engine.api.TbNodeConnectionType.SUCCESS; @Slf4j @RuleNode( diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java index 51effe02ef..6bd8f52285 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java @@ -41,7 +41,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import static org.thingsboard.common.util.DonAsynchron.withCallback; -import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; +import static org.thingsboard.rule.engine.api.TbNodeConnectionType.SUCCESS; @Slf4j @RuleNode( diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java index 6890aa6bf4..af119d263f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java @@ -24,7 +24,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -196,7 +196,7 @@ public class TbMsgDeduplicationNode implements TbNode { private void enqueueForTellNextWithRetry(TbContext ctx, TbMsg msg, int retryAttempt) { if (config.getMaxRetries() > retryAttempt) { - ctx.enqueueForTellNext(msg, TbRelationTypes.SUCCESS, + ctx.enqueueForTellNext(msg, TbNodeConnectionType.SUCCESS, () -> { log.trace("[{}][{}][{}] Successfully enqueue deduplication result message!", ctx.getSelfId(), msg.getOriginator(), retryAttempt); }, diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index 1f18aea86e..17224c18b8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -32,7 +32,7 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; -import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; +import static org.thingsboard.rule.engine.api.TbNodeConnectionType.SUCCESS; @Slf4j @RuleNode( diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java index 318b38aa39..bbec000077 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java @@ -30,13 +30,23 @@ import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.session.SessionMsgType; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; +import static org.thingsboard.server.common.data.msg.TbMsgType.CONNECT_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.DISCONNECT_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; +import static org.thingsboard.server.common.data.msg.TbMsgType.TIMESERIES_UPDATED; + @Slf4j public abstract class AbstractTbMsgPushNode implements TbNode { @@ -73,7 +83,7 @@ public abstract class AbstractTbMsgPushNode metadata) { EdgeEventActionType actionType; - if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msgType) - || DataConstants.TIMESERIES_UPDATED.equals(msgType)) { + if (POST_TELEMETRY_REQUEST.name().equals(msgType) + || TIMESERIES_UPDATED.name().equals(msgType)) { actionType = EdgeEventActionType.TIMESERIES_UPDATED; - } else if (DataConstants.ATTRIBUTES_UPDATED.equals(msgType)) { + } else if (ATTRIBUTES_UPDATED.name().equals(msgType)) { actionType = EdgeEventActionType.ATTRIBUTES_UPDATED; - } else if (SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msgType)) { + } else if (POST_ATTRIBUTES_REQUEST.name().equals(msgType)) { actionType = EdgeEventActionType.POST_ATTRIBUTES; - } else if (DataConstants.ATTRIBUTES_DELETED.equals(msgType)) { + } else if (ATTRIBUTES_DELETED.name().equals(msgType)) { actionType = EdgeEventActionType.ATTRIBUTES_DELETED; - } else if (DataConstants.CONNECT_EVENT.equals(msgType) - || DataConstants.DISCONNECT_EVENT.equals(msgType) - || DataConstants.ACTIVITY_EVENT.equals(msgType) - || DataConstants.INACTIVITY_EVENT.equals(msgType)) { + } else if (CONNECT_EVENT.name().equals(msgType) + || DISCONNECT_EVENT.name().equals(msgType) + || ACTIVITY_EVENT.name().equals(msgType) + || INACTIVITY_EVENT.name().equals(msgType)) { String scope = metadata.get(SCOPE); if ( StringUtils.isEmpty(scope)) { actionType = EdgeEventActionType.TIMESERIES_UPDATED; @@ -177,16 +187,16 @@ public abstract class AbstractTbMsgPushNodeFailure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNode.java index dcaf6698cd..f76366e622 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNode.java @@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.filter; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleNode; @@ -26,26 +25,27 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.alarm.Alarm; -import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import javax.annotation.Nullable; -import java.io.IOException; @Slf4j @RuleNode( type = ComponentType.FILTER, - name = "check alarm status", + name = "alarm status filter", configClazz = TbCheckAlarmStatusNodeConfig.class, - relationTypes = {"True", "False"}, + relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE}, nodeDescription = "Checks alarm status.", - nodeDetails = "Checks the alarm status to match one of the specified statuses.", + nodeDetails = "Checks the alarm status to match one of the specified statuses.

" + + "Output connection types: True, False, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeCheckAlarmStatusConfig") public class TbCheckAlarmStatusNode implements TbNode { + private TbCheckAlarmStatusNodeConfig config; @Override @@ -60,33 +60,24 @@ public class TbCheckAlarmStatusNode implements TbNode { ListenableFuture latest = ctx.getAlarmService().findAlarmByIdAsync(ctx.getTenantId(), alarm.getId()); - Futures.addCallback(latest, new FutureCallback() { + Futures.addCallback(latest, new FutureCallback<>() { @Override public void onSuccess(@Nullable Alarm result) { - if (result != null) { - boolean isPresent = false; - for (AlarmStatus alarmStatus : config.getAlarmStatusList()) { - if (result.getStatus() == alarmStatus) { - isPresent = true; - break; - } - } - if (isPresent) { - ctx.tellNext(msg, "True"); - } else { - ctx.tellNext(msg, "False"); - } - } else { + if (result == null) { ctx.tellFailure(msg, new TbNodeException("No such alarm found.")); + return; } + boolean isPresent = config.getAlarmStatusList().stream() + .anyMatch(alarmStatus -> result.getStatus() == alarmStatus); + ctx.tellNext(msg, isPresent ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE); } @Override public void onFailure(Throwable t) { ctx.tellFailure(msg, t); } - }, MoreExecutors.directExecutor()); - } catch (IllegalArgumentException e) { + }, ctx.getDbCallbackExecutor()); + } catch (Exception e) { log.error("Failed to parse alarm: [{}]", msg.getData()); throw new TbNodeException(e); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeConfig.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeConfig.java index d979eb10ca..4c15d635b8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeConfig.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeConfig.java @@ -24,12 +24,14 @@ import java.util.List; @Data public class TbCheckAlarmStatusNodeConfig implements NodeConfiguration { + private List alarmStatusList; @Override public TbCheckAlarmStatusNodeConfig defaultConfiguration() { - TbCheckAlarmStatusNodeConfig config = new TbCheckAlarmStatusNodeConfig(); + var config = new TbCheckAlarmStatusNodeConfig(); config.setAlarmStatusList(Arrays.asList(AlarmStatus.ACTIVE_ACK, AlarmStatus.ACTIVE_UNACK)); return config; } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java index 3853b3a62a..c461b258a8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java @@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -33,12 +34,12 @@ import java.util.Map; @RuleNode( type = ComponentType.FILTER, name = "check fields presence", - relationTypes = {"True", "False"}, + relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE}, configClazz = TbCheckMessageNodeConfiguration.class, nodeDescription = "Checks the presence of the specified fields in the message and/or metadata.", - nodeDetails = "Checks the presence of the specified fields in the message and/or metadata. " + - "By default, the rule node checks that all specified fields need to be present. " + - "Uncheck the 'Check that all specified fields are present' if the presence of at least one field is sufficient.", + nodeDetails = "By default, the rule node checks that all specified fields are present. " + + "Uncheck the 'Check that all selected fields are present' if the presence of at least one field is sufficient.

" + + "Output connection types: True, False, Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeCheckMessageConfig") public class TbCheckMessageNode implements TbNode { @@ -60,9 +61,9 @@ public class TbCheckMessageNode implements TbNode { public void onMsg(TbContext ctx, TbMsg msg) { try { if (config.isCheckAllKeys()) { - ctx.tellNext(msg, allKeysData(msg) && allKeysMetadata(msg) ? "True" : "False"); + ctx.tellNext(msg, allKeysData(msg) && allKeysMetadata(msg) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE); } else { - ctx.tellNext(msg, atLeastOneData(msg) || atLeastOneMetadata(msg) ? "True" : "False"); + ctx.tellNext(msg, atLeastOneData(msg) || atLeastOneMetadata(msg) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE); } } catch (Exception e) { ctx.tellFailure(msg, e); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java index 4a0d6b05e7..43bec5a3c1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java @@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -43,12 +44,14 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; @Slf4j @RuleNode( type = ComponentType.FILTER, - name = "check relation", + name = "check relation presence", configClazz = TbCheckRelationNodeConfiguration.class, - relationTypes = {"True", "False"}, + relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE}, nodeDescription = "Checks the presence of the relation between the originator of the message and other entities.", - nodeDetails = "If 'check relation to specific entity' is selected, one must specify a related entity. " + - "Otherwise, the rule node checks the presence of a relation to any entity that matches the direction and relation type criteria.", + nodeDetails = "If 'check relation to specific entity' is selected, you should specify a related entity. " + + "Otherwise, the rule node checks the presence of a relation to any entity. " + + "In both cases, relation lookup is based on configured direction and type.

" + + "Output connection types: True, False, Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeCheckRelationConfig") public class TbCheckRelationNode implements TbNode { @@ -67,13 +70,11 @@ public class TbCheckRelationNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException { - ListenableFuture checkRelationFuture; - if (config.isCheckForSingleEntity()) { - checkRelationFuture = processSingle(ctx, msg); - } else { - checkRelationFuture = processList(ctx, msg); - } - withCallback(checkRelationFuture, filterResult -> ctx.tellNext(msg, filterResult ? "True" : "False"), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); + ListenableFuture checkRelationFuture = config.isCheckForSingleEntity() ? + processSingle(ctx, msg) : processList(ctx, msg); + withCallback(checkRelationFuture, + filterResult -> ctx.tellNext(msg, filterResult ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE), + t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } private ListenableFuture processSingle(TbContext ctx, TbMsg msg) { @@ -100,11 +101,7 @@ public class TbCheckRelationNode implements TbNode { } private ListenableFuture isEmptyList(List entityRelations) { - if (entityRelations.isEmpty()) { - return Futures.immediateFuture(false); - } else { - return Futures.immediateFuture(true); - } + return entityRelations.isEmpty() ? Futures.immediateFuture(false) : Futures.immediateFuture(true); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java index 16131ecc05..4409702d9a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java @@ -34,7 +34,8 @@ import org.thingsboard.server.common.data.plugin.ComponentType; relationTypes = {"default"}, configClazz = EmptyNodeConfiguration.class, nodeDescription = "Route incoming messages based on the name of the device profile", - nodeDetails = "Route incoming messages based on the name of the device profile. The device profile name is case-sensitive", + nodeDetails = "Route incoming messages based on the name of the device profile. The device profile name is case-sensitive

" + + "Output connection types: Profile name of message originator or Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java index 0bde9402a7..1b8461b44b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java @@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.script.ScriptLanguage; @@ -32,7 +33,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; @Slf4j @RuleNode( type = ComponentType.FILTER, - name = "script", relationTypes = {"True", "False"}, + name = "script", + relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE}, configClazz = TbJsFilterNodeConfiguration.class, nodeDescription = "Filter incoming messages using TBEL or JS script", nodeDetails = "Evaluates boolean function using incoming message. " + @@ -40,7 +42,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; "Script function should return boolean value and accepts three parameters:
" + "Message payload can be accessed via msg property. For example msg.temperature < 10;
" + "Message metadata can be accessed via metadata property. For example metadata.customerName === 'John';
" + - "Message type can be accessed via msgType property.", + "Message type can be accessed via msgType property.

" + + "Output connection types: True, False, Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeScriptConfig" ) @@ -62,7 +65,7 @@ public class TbJsFilterNode implements TbNode { withCallback(scriptEngine.executeFilterAsync(msg), filterResult -> { ctx.logJsEvalResponse(); - ctx.tellNext(msg, filterResult ? "True" : "False"); + ctx.tellNext(msg, filterResult ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE); }, t -> { ctx.tellFailure(msg, t); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java index 706978846a..8c0f058ed3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java @@ -44,7 +44,8 @@ import java.util.Set; "If Array is empty - message not routed to next Node. " + "Message payload can be accessed via msg property. For example msg.temperature < 10;
" + "Message metadata can be accessed via metadata property. For example metadata.customerName === 'John';
" + - "Message type can be accessed via msgType property.", + "Message type can be accessed via msgType property.

" + + "Output connection types: Custom connection(s) defined by switch node or Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeSwitchConfig") public class TbJsSwitchNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java index 765deb2ea7..5074991cb1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java @@ -21,6 +21,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -33,9 +34,10 @@ import org.thingsboard.server.common.msg.TbMsg; type = ComponentType.FILTER, name = "message type", configClazz = TbMsgTypeFilterNodeConfiguration.class, - relationTypes = {"True", "False"}, + relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE}, nodeDescription = "Filter incoming messages by Message Type", - nodeDetails = "If incoming MessageType is expected - send Message via True chain, otherwise False chain is used.", + nodeDetails = "If incoming message type is expected - send Message via True chain, otherwise False chain is used.

" + + "Output connection types: True, False, Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeMessageTypeConfig") public class TbMsgTypeFilterNode implements TbNode { @@ -49,7 +51,7 @@ public class TbMsgTypeFilterNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - ctx.tellNext(msg, config.getMessageTypes().contains(msg.getType()) ? "True" : "False"); + ctx.tellNext(msg, config.getMessageTypes().contains(msg.getType()) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java index 16649f8f85..99a3d41c3a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java @@ -19,24 +19,20 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.session.SessionMsgType; @Slf4j @RuleNode( type = ComponentType.FILTER, name = "message type switch", configClazz = EmptyNodeConfiguration.class, - relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "RPC Queued", "RPC Sent", "RPC Delivered", "RPC Successful", "RPC Timeout", "RPC Expired", "RPC Failed", "RPC Deleted", - "Activity Event", "Inactivity Event", "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned", - "Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Alarm Assigned", "Alarm Unassigned", "Comment Created", "Comment Updated", "Other", "Entity Assigned From Tenant", "Entity Assigned To Tenant", - "Relation Added or Updated", "Relation Deleted", "All Relations Deleted", "Timeseries Updated", "Timeseries Deleted"}, + relationTypes = {}, // should always be empty. We add the relation types for this node in AnnotationComponentDiscoveryService. nodeDescription = "Route incoming messages by Message Type", nodeDetails = "Sends messages with message types \"Post attributes\", \"Post telemetry\", \"RPC Request\" etc. via corresponding chain, otherwise Other chain is used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, @@ -52,83 +48,7 @@ public class TbMsgTypeSwitchNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - String relationType; - if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) { - relationType = "Post attributes"; - } else if (msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())) { - relationType = "Post telemetry"; - } else if (msg.getType().equals(SessionMsgType.TO_SERVER_RPC_REQUEST.name())) { - relationType = "RPC Request from Device"; - } else if (msg.getType().equals(DataConstants.ACTIVITY_EVENT)) { - relationType = "Activity Event"; - } else if (msg.getType().equals(DataConstants.INACTIVITY_EVENT)) { - relationType = "Inactivity Event"; - } else if (msg.getType().equals(DataConstants.CONNECT_EVENT)) { - relationType = "Connect Event"; - } else if (msg.getType().equals(DataConstants.DISCONNECT_EVENT)) { - relationType = "Disconnect Event"; - } else if (msg.getType().equals(DataConstants.ENTITY_CREATED)) { - relationType = "Entity Created"; - } else if (msg.getType().equals(DataConstants.ENTITY_UPDATED)) { - relationType = "Entity Updated"; - } else if (msg.getType().equals(DataConstants.ENTITY_DELETED)) { - relationType = "Entity Deleted"; - } else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED)) { - relationType = "Entity Assigned"; - } else if (msg.getType().equals(DataConstants.ENTITY_UNASSIGNED)) { - relationType = "Entity Unassigned"; - } else if (msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) { - relationType = "Attributes Updated"; - } else if (msg.getType().equals(DataConstants.ATTRIBUTES_DELETED)) { - relationType = "Attributes Deleted"; - } else if (msg.getType().equals(DataConstants.ALARM_ACK)) { - relationType = "Alarm Acknowledged"; - } else if (msg.getType().equals(DataConstants.ALARM_CLEAR)) { - relationType = "Alarm Cleared"; - } else if (msg.getType().equals(DataConstants.ALARM_ASSIGNED)) { - relationType = "Alarm Assigned"; - } else if (msg.getType().equals(DataConstants.ALARM_UNASSIGNED)) { - relationType = "Alarm Unassigned"; - } else if (msg.getType().equals(DataConstants.COMMENT_CREATED)) { - relationType = "Comment Created"; - } else if (msg.getType().equals(DataConstants.COMMENT_UPDATED)) { - relationType = "Comment Updated"; - } else if (msg.getType().equals(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE)) { - relationType = "RPC Request to Device"; - } else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_FROM_TENANT)) { - relationType = "Entity Assigned From Tenant"; - } else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_TO_TENANT)) { - relationType = "Entity Assigned To Tenant"; - } else if (msg.getType().equals(DataConstants.TIMESERIES_UPDATED)) { - relationType = "Timeseries Updated"; - } else if (msg.getType().equals(DataConstants.TIMESERIES_DELETED)) { - relationType = "Timeseries Deleted"; - } else if (msg.getType().equals(DataConstants.RPC_QUEUED)) { - relationType = "RPC Queued"; - } else if (msg.getType().equals(DataConstants.RPC_SENT)) { - relationType = "RPC Sent"; - } else if (msg.getType().equals(DataConstants.RPC_DELIVERED)) { - relationType = "RPC Delivered"; - } else if (msg.getType().equals(DataConstants.RPC_SUCCESSFUL)) { - relationType = "RPC Successful"; - } else if (msg.getType().equals(DataConstants.RPC_TIMEOUT)) { - relationType = "RPC Timeout"; - } else if (msg.getType().equals(DataConstants.RPC_EXPIRED)) { - relationType = "RPC Expired"; - } else if (msg.getType().equals(DataConstants.RPC_FAILED)) { - relationType = "RPC Failed"; - } else if (msg.getType().equals(DataConstants.RPC_DELETED)) { - relationType = "RPC Deleted"; - } else if (msg.getType().equals(DataConstants.RELATION_ADD_OR_UPDATE)) { - relationType = "Relation Added or Updated"; - } else if (msg.getType().equals(DataConstants.RELATION_DELETED)) { - relationType = "Relation Deleted"; - } else if (msg.getType().equals(DataConstants.RELATIONS_DELETED)) { - relationType = "All Relations Deleted"; - } else { - relationType = "Other"; - } - ctx.tellNext(msg, relationType); + ctx.tellNext(msg, TbMsgType.getNodeConnection(msg.getType())); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java index f4e13d761e..8c32d8a1c9 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java @@ -21,6 +21,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -31,9 +32,10 @@ import org.thingsboard.server.common.msg.TbMsg; type = ComponentType.FILTER, name = "entity type", configClazz = TbOriginatorTypeFilterNodeConfiguration.class, - relationTypes = {"True", "False"}, + relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE}, nodeDescription = "Filter incoming messages by the type of message originator entity", - nodeDetails = "Checks that the entity type of the incoming message originator matches one of the values specified in the filter.", + nodeDetails = "Checks that the entity type of the incoming message originator matches one of the values specified in the filter.

" + + "Output connection types: True, False, Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeOriginatorTypeConfig") public class TbOriginatorTypeFilterNode implements TbNode { @@ -48,7 +50,7 @@ public class TbOriginatorTypeFilterNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { EntityType originatorType = msg.getOriginator().getEntityType(); - ctx.tellNext(msg, config.getOriginatorTypes().contains(originatorType) ? "True" : "False"); + ctx.tellNext(msg, config.getOriginatorTypes().contains(originatorType) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java index a920af5066..11365a2b1d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java @@ -19,8 +19,6 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -29,55 +27,17 @@ import org.thingsboard.server.common.data.plugin.ComponentType; type = ComponentType.FILTER, name = "entity type switch", configClazz = EmptyNodeConfiguration.class, - relationTypes = {"Device", "Asset", "Alarm", "Entity View", "Tenant", "Customer", "User", "Dashboard", "Rule chain", "Rule node", "Edge"}, + relationTypes = {}, // should always be empty. We add the relation types for this node in AnnotationComponentDiscoveryService. nodeDescription = "Route incoming messages by Message Originator Type", - nodeDetails = "Routes messages to chain according to the entity type ('Device', 'Asset', etc.).", + nodeDetails = "Routes messages to chain according to the entity type ('Device', 'Asset', etc.).

" + + "Output connection types: entityType of the message originator or Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") public class TbOriginatorTypeSwitchNode extends TbAbstractTypeSwitchNode { @Override - protected String getRelationType(TbContext ctx, EntityId originator) throws TbNodeException { - String relationType; - EntityType originatorType = originator.getEntityType(); - switch (originatorType) { - case TENANT: - relationType = "Tenant"; - break; - case CUSTOMER: - relationType = "Customer"; - break; - case USER: - relationType = "User"; - break; - case DASHBOARD: - relationType = "Dashboard"; - break; - case ASSET: - relationType = "Asset"; - break; - case DEVICE: - relationType = "Device"; - break; - case ENTITY_VIEW: - relationType = "Entity View"; - break; - case EDGE: - relationType = "Edge"; - break; - case RULE_CHAIN: - relationType = "Rule chain"; - break; - case RULE_NODE: - relationType = "Rule node"; - break; - case ALARM: - relationType = "Alarm"; - break; - default: - throw new TbNodeException("Unsupported originator type: " + originatorType); - } - return relationType; + protected String getRelationType(TbContext ctx, EntityId originator) { + return originator.getEntityType().getNormalName(); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java index 35baaf461b..e0ffc564db 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNode.java @@ -21,7 +21,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -48,7 +48,7 @@ public class TbCheckpointNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - ctx.enqueueForTellNext(msg, queueName, TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error)); + ctx.enqueueForTellNext(msg, queueName, TbNodeConnectionType.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error)); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java index 373118ebdd..b4d217d799 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -30,7 +31,7 @@ import org.thingsboard.server.common.msg.TbMsg; type = ComponentType.FILTER, name = "gps geofencing filter", configClazz = TbGpsGeofencingFilterNodeConfiguration.class, - relationTypes = {"True", "False"}, + relationTypes = {TbNodeConnectionType.TRUE, TbNodeConnectionType.FALSE}, nodeDescription = "Filter incoming messages by GPS based geofencing", nodeDetails = "Extracts latitude and longitude parameters from the incoming message and checks them according to configured perimeter.
" + "Configuration:

" + @@ -57,14 +58,15 @@ import org.thingsboard.server.common.msg.TbMsg; "

" + "{\"latitude\": 48.198618758582384, \"longitude\": 24.65322245153503, \"radius\": 100.0, \"radiusUnit\": \"METER\" }" + "

" + - "Available radius units: METER, KILOMETER, FOOT, MILE, NAUTICAL_MILE;", + "Available radius units: METER, KILOMETER, FOOT, MILE, NAUTICAL_MILE;

" + + "Output connection types: True, False, Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeGpsGeofencingConfig") public class TbGpsGeofencingFilterNode extends AbstractGeofencingNode { @Override public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException { - ctx.tellNext(msg, checkMatches(msg) ? "True" : "False"); + ctx.tellNext(msg, checkMatches(msg) ? TbNodeConnectionType.TRUE : TbNodeConnectionType.FALSE); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java index de1abea224..7afd61da2d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java @@ -31,7 +31,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.exception.ThingsboardKafkaClientError; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -165,7 +165,7 @@ public class TbKafkaNode implements TbNode { private void processRecord(TbContext ctx, TbMsg msg, RecordMetadata metadata, Exception e) { if (e == null) { TbMsg next = processResponse(ctx, msg, metadata); - ctx.tellNext(next, TbRelationTypes.SUCCESS); + ctx.tellNext(next, TbNodeConnectionType.SUCCESS); } else { TbMsg next = processException(ctx, msg, e); ctx.tellFailure(next, e); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java index 2af4978766..d56b0d6890 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java @@ -27,7 +27,6 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -35,7 +34,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; -import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; +import static org.thingsboard.rule.engine.api.TbNodeConnectionType.SUCCESS; import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE; @Slf4j diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java index 14227cadc4..5707d64071 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java @@ -49,7 +49,7 @@ public abstract class TbAbstractGetEntityDetailsNode detailsList) throws TbNodeException { if (detailsList == null || detailsList.isEmpty()) { - throw new TbNodeException("No entity details selected!"); + throw new TbNodeException("At least one entity detail should be selected!"); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java index 31f661417b..4397200fe4 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java @@ -40,7 +40,6 @@ import org.thingsboard.server.common.data.query.EntityKey; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.rule.RuleNodeState; import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.dao.sql.query.EntityKeyMapping; @@ -55,6 +54,18 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; +import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_ACK; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_CLEAR; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UNASSIGNED; +import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; + @Slf4j class DeviceState { @@ -136,24 +147,24 @@ class DeviceState { latestValues = fetchLatestValues(ctx, deviceId); } boolean stateChanged = false; - if (msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())) { + if (msg.getType().equals(POST_TELEMETRY_REQUEST.name())) { stateChanged = processTelemetry(ctx, msg); - } else if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) { + } else if (msg.getType().equals(POST_ATTRIBUTES_REQUEST.name())) { stateChanged = processAttributesUpdateRequest(ctx, msg); - } else if (msg.getType().equals(DataConstants.ACTIVITY_EVENT) || msg.getType().equals(DataConstants.INACTIVITY_EVENT)) { + } else if (msg.getType().equals(ACTIVITY_EVENT.name()) || msg.getType().equals(INACTIVITY_EVENT.name())) { stateChanged = processDeviceActivityEvent(ctx, msg); - } else if (msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) { + } else if (msg.getType().equals(ATTRIBUTES_UPDATED.name())) { stateChanged = processAttributesUpdateNotification(ctx, msg); - } else if (msg.getType().equals(DataConstants.ATTRIBUTES_DELETED)) { + } else if (msg.getType().equals(ATTRIBUTES_DELETED.name())) { stateChanged = processAttributesDeleteNotification(ctx, msg); - } else if (msg.getType().equals(DataConstants.ALARM_CLEAR)) { + } else if (msg.getType().equals(ALARM_CLEAR.name())) { stateChanged = processAlarmClearNotification(ctx, msg); - } else if (msg.getType().equals(DataConstants.ALARM_ACK)) { + } else if (msg.getType().equals(ALARM_ACK.name())) { processAlarmAckNotification(ctx, msg); - } else if (msg.getType().equals(DataConstants.ALARM_DELETE)) { + } else if (msg.getType().equals(ALARM_DELETE.name())) { processAlarmDeleteNotification(ctx, msg); } else { - if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED) || msg.getType().equals(DataConstants.ENTITY_UNASSIGNED)) { + if (msg.getType().equals(ENTITY_ASSIGNED.name()) || msg.getType().equals(ENTITY_UNASSIGNED.name())) { dynamicPredicateValueCtx.resetCustomer(); } ctx.tellSuccess(msg); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index ba987678f3..a8b3ef4f5f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -26,7 +26,6 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityType; @@ -46,6 +45,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_DELETED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UPDATED; + @Slf4j @RuleNode( type = ComponentType.ACTION, @@ -123,10 +125,10 @@ public class TbDeviceProfileNode implements TbNode { } else { if (EntityType.DEVICE.equals(originatorType)) { DeviceId deviceId = new DeviceId(msg.getOriginator().getId()); - if (msg.getType().equals(DataConstants.ENTITY_UPDATED)) { + if (msg.getType().equals(ENTITY_UPDATED.name())) { invalidateDeviceProfileCache(deviceId, msg.getData()); ctx.tellSuccess(msg); - } else if (msg.getType().equals(DataConstants.ENTITY_DELETED)) { + } else if (msg.getType().equals(ENTITY_DELETED.name())) { removeDeviceState(deviceId); ctx.tellSuccess(msg); } else { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 6f9541f5b1..c7580fb7d3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -43,7 +43,7 @@ import org.springframework.web.util.UriComponentsBuilder; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.credentials.BasicCredentials; import org.thingsboard.rule.engine.credentials.ClientCredentials; @@ -212,7 +212,7 @@ public class TbHttpClient { ctx.tellSuccess(next); } else { TbMsg next = processFailureResponse(ctx, msg, responseEntity); - ctx.tellNext(next, TbRelationTypes.FAILURE); + ctx.tellNext(next, TbNodeConnectionType.FAILURE); } } }); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java index 79bd6f9bf9..936b192c85 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java @@ -27,12 +27,13 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -76,7 +77,7 @@ public class TbSendRPCRequestNode implements TbNode { ctx.tellFailure(msg, new RuntimeException("Params are not present in the message!")); } else { int requestId = json.has("requestId") ? json.get("requestId").getAsInt() : random.nextInt(); - boolean restApiCall = msg.getType().equals(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE); + boolean restApiCall = msg.getType().equals(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.name()); tmp = msg.getMetaData().getValue("oneway"); boolean oneway = !StringUtils.isEmpty(tmp) && Boolean.parseBoolean(tmp); @@ -117,7 +118,7 @@ public class TbSendRPCRequestNode implements TbNode { ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> { if (ruleEngineDeviceRpcResponse.getError().isEmpty()) { TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}")); - ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS); + ctx.enqueueForTellNext(next, TbNodeConnectionType.SUCCESS); } else { TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name())); ctx.enqueueForTellFailure(next, ruleEngineDeviceRpcResponse.getError().get().name()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java index 7bf08e8647..d96060ffc2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbAbstractTransformNode.java @@ -22,7 +22,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.queue.RuleEngineException; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -75,7 +75,7 @@ public abstract class TbAbstractTransformNode implements TbNode { ctx.tellFailure(msg, e); } }); - msgs.forEach(newMsg -> ctx.enqueueForTellNext(newMsg, TbRelationTypes.SUCCESS, wrapper::onSuccess, wrapper::onFailure)); + msgs.forEach(newMsg -> ctx.enqueueForTellNext(newMsg, TbNodeConnectionType.SUCCESS, wrapper::onSuccess, wrapper::onFailure)); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java index ae7ceade97..9c86891bc0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java @@ -25,7 +25,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -79,7 +79,7 @@ public class TbSplitArrayMsgNode implements TbNode { }); data.forEach(msgNode -> { TbMsg outMsg = TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(msgNode)); - ctx.enqueueForTellNext(outMsg, TbRelationTypes.SUCCESS, wrapper::onSuccess, wrapper::onFailure); + ctx.enqueueForTellNext(outMsg, TbNodeConnectionType.SUCCESS, wrapper::onSuccess, wrapper::onFailure); }); } } else { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java index 22df15631e..3b8a8c9193 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java @@ -28,8 +28,8 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ListeningExecutor; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbRelationTypes; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; @@ -54,6 +54,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED; @RunWith(MockitoJUnitRunner.class) public class TbCreateRelationNodeTest { @@ -111,7 +112,7 @@ public class TbCreateRelationNodeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("name", "AssetName"); metaData.putValue("type", "AssetType"); - msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg(ENTITY_CREATED.name(), deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(false)); @@ -119,7 +120,7 @@ public class TbCreateRelationNodeTest { .thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); - verify(ctx).tellNext(msg, TbRelationTypes.SUCCESS); + verify(ctx).tellNext(msg, TbNodeConnectionType.SUCCESS); } @Test @@ -138,7 +139,7 @@ public class TbCreateRelationNodeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("name", "AssetName"); metaData.putValue("type", "AssetType"); - msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg(ENTITY_CREATED.name(), deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); EntityRelation relation = new EntityRelation(); when(ctx.getRelationService().findByToAndTypeAsync(any(), eq(msg.getOriginator()), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) @@ -150,7 +151,7 @@ public class TbCreateRelationNodeTest { .thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); - verify(ctx).tellNext(msg, TbRelationTypes.SUCCESS); + verify(ctx).tellNext(msg, TbNodeConnectionType.SUCCESS); } @Test @@ -169,7 +170,7 @@ public class TbCreateRelationNodeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("name", "AssetName"); metaData.putValue("type", "AssetType"); - msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg(ENTITY_CREATED.name(), deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(false)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java index 84deafe7e4..98c0c62231 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java @@ -49,10 +49,18 @@ import java.util.UUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; +import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; +import static org.thingsboard.server.common.data.msg.TbMsgType.CONNECT_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.DISCONNECT_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; @RunWith(MockitoJUnitRunner.class) public class TbMsgPushToEdgeNodeTest { + private static final List MISC_EVENTS = List.of(CONNECT_EVENT.name(), DISCONNECT_EVENT.name(), + ACTIVITY_EVENT.name(), INACTIVITY_EVENT.name()); + TbMsgPushToEdgeNode node; private final TenantId tenantId = TenantId.fromUUID(UUID.randomUUID()); @@ -102,7 +110,7 @@ public class TbMsgPushToEdgeNodeTest { PageData edgePageData = new PageData<>(List.of(edgeId), 1, 1, false); Mockito.when(edgeService.findRelatedEdgeIdsByEntityId(tenantId, userId, new PageLink(TbMsgPushToEdgeNode.DEFAULT_PAGE_SIZE))).thenReturn(edgePageData); - TbMsg msg = TbMsg.newMsg(DataConstants.ATTRIBUTES_UPDATED, userId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(ATTRIBUTES_UPDATED.name(), userId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", null, null); node.onMsg(ctx, msg); @@ -112,9 +120,7 @@ public class TbMsgPushToEdgeNodeTest { @Test public void testMiscEventsProcessedAsAttributesUpdated() { - List miscEvents = List.of(DataConstants.CONNECT_EVENT, DataConstants.DISCONNECT_EVENT, - DataConstants.ACTIVITY_EVENT, DataConstants.INACTIVITY_EVENT); - for (String event : miscEvents) { + for (String event : MISC_EVENTS) { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue(DataConstants.SCOPE, DataConstants.SERVER_SCOPE); testEvent(event, metaData, EdgeEventActionType.ATTRIBUTES_UPDATED, "kv"); @@ -123,9 +129,7 @@ public class TbMsgPushToEdgeNodeTest { @Test public void testMiscEventsProcessedAsTimeseriesUpdated() { - List miscEvents = List.of(DataConstants.CONNECT_EVENT, DataConstants.DISCONNECT_EVENT, - DataConstants.ACTIVITY_EVENT, DataConstants.INACTIVITY_EVENT); - for (String event : miscEvents) { + for (String event : MISC_EVENTS) { testEvent(event, new TbMsgMetaData(), EdgeEventActionType.TIMESERIES_UPDATED, "data"); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java index 4cfe38f3fc..81e4c70ce0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java @@ -27,6 +27,8 @@ import org.thingsboard.rule.engine.api.ScriptEngine; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.script.ScriptLanguage; @@ -55,21 +57,21 @@ public class TbJsFilterNodeTest { private RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); @Test - public void falseEvaluationDoNotSendMsg() throws TbNodeException, ScriptException { + public void falseEvaluationDoNotSendMsg() throws TbNodeException { initWithScript(); - TbMsg msg = TbMsg.newMsg("USER", null, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(false)); node.onMsg(ctx, msg); verify(ctx).getDbCallbackExecutor(); - verify(ctx).tellNext(msg, "False"); + verify(ctx).tellNext(msg, TbNodeConnectionType.FALSE); } @Test public void exceptionInJsThrowsException() throws TbNodeException { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg("USER", null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFailedFuture(new ScriptException("error"))); @@ -81,12 +83,12 @@ public class TbJsFilterNodeTest { public void metadataConditionCanBeTrue() throws TbNodeException { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg("USER", null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); verify(ctx).getDbCallbackExecutor(); - verify(ctx).tellNext(msg, "True"); + verify(ctx).tellNext(msg, TbNodeConnectionType.TRUE); } private void initWithScript() throws TbNodeException { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java index d33b2af030..b480719f64 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java @@ -22,7 +22,6 @@ import org.mockito.ArgumentCaptor; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleEngineAlarmService; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; @@ -64,6 +63,10 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_CLEAR; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; public class DeviceStateTest { @@ -115,11 +118,11 @@ public class DeviceStateTest { verify(ctx).enqueueForTellNext(resultMsgCaptor.capture(), eq("Alarm Created")); Alarm alarm = JacksonUtil.fromString(resultMsgCaptor.getValue().getData(), Alarm.class); - deviceState.process(ctx, TbMsg.newMsg(DataConstants.ALARM_CLEAR, deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm))); + deviceState.process(ctx, TbMsg.newMsg(ALARM_CLEAR.name(), deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm))); reset(ctx); String deletedAttributes = "{ \"attributes\": [ \"other\" ] }"; - deviceState.process(ctx, TbMsg.newMsg(DataConstants.ATTRIBUTES_DELETED, deviceId, new TbMsgMetaData(), deletedAttributes)); + deviceState.process(ctx, TbMsg.newMsg(ATTRIBUTES_DELETED.name(), deviceId, new TbMsgMetaData(), deletedAttributes)); verify(ctx, never()).enqueueForTellNext(any(), anyString()); } @@ -129,7 +132,7 @@ public class DeviceStateTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); DeviceState deviceState = createDeviceState(deviceId, alarmConfig); - TbMsg attributeUpdateMsg = TbMsg.newMsg(SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), + TbMsg attributeUpdateMsg = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), deviceId, new TbMsgMetaData(), "{ \"enabled\": false }"); deviceState.process(ctx, attributeUpdateMsg); @@ -137,9 +140,9 @@ public class DeviceStateTest { verify(ctx).enqueueForTellNext(resultMsgCaptor.capture(), eq("Alarm Created")); Alarm alarm = JacksonUtil.fromString(resultMsgCaptor.getValue().getData(), Alarm.class); - deviceState.process(ctx, TbMsg.newMsg(DataConstants.ALARM_CLEAR, deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm))); + deviceState.process(ctx, TbMsg.newMsg(ALARM_CLEAR.name(), deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm))); - TbMsg alarmDeleteNotification = TbMsg.newMsg(DataConstants.ALARM_DELETE, deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm)); + TbMsg alarmDeleteNotification = TbMsg.newMsg(ALARM_DELETE.name(), deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm)); assertDoesNotThrow(() -> { deviceState.process(ctx, alarmDeleteNotification); }); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java index 7bfa5c8bfc..f48a9f670c 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java @@ -30,7 +30,7 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.TbNodeConnectionType; import org.thingsboard.rule.engine.deduplication.DeduplicationStrategy; import org.thingsboard.rule.engine.deduplication.TbMsgDeduplicationNode; import org.thingsboard.rule.engine.deduplication.TbMsgDeduplicationNodeConfiguration; @@ -173,7 +173,7 @@ public class TbMsgDeduplicationNodeTest { verify(ctx, times(msgCount)).ack(any()); verify(ctx, times(1)).tellFailure(eq(msgToReject), any()); verify(node, times(msgCount + wantedNumberOfTellSelfInvocation + 1)).onMsg(eq(ctx), any()); - verify(ctx, times(1)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbRelationTypes.SUCCESS), successCaptor.capture(), failureCaptor.capture()); + verify(ctx, times(1)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.SUCCESS), successCaptor.capture(), failureCaptor.capture()); TbMsg firstMsg = inputMsgs.get(0); TbMsg actualMsg = newMsgCaptor.getValue(); @@ -221,7 +221,7 @@ public class TbMsgDeduplicationNodeTest { verify(ctx, times(msgCount)).ack(any()); verify(ctx, times(1)).tellFailure(eq(msgToReject), any()); verify(node, times(msgCount + wantedNumberOfTellSelfInvocation + 1)).onMsg(eq(ctx), any()); - verify(ctx, times(1)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbRelationTypes.SUCCESS), successCaptor.capture(), failureCaptor.capture()); + verify(ctx, times(1)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.SUCCESS), successCaptor.capture(), failureCaptor.capture()); TbMsg actualMsg = newMsgCaptor.getValue(); // msg ids should be different because we create new msg before enqueueForTellNext @@ -263,7 +263,7 @@ public class TbMsgDeduplicationNodeTest { verify(ctx, times(msgCount)).ack(any()); verify(node, times(msgCount + wantedNumberOfTellSelfInvocation)).onMsg(eq(ctx), any()); - verify(ctx, times(1)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbRelationTypes.SUCCESS), successCaptor.capture(), failureCaptor.capture()); + verify(ctx, times(1)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.SUCCESS), successCaptor.capture(), failureCaptor.capture()); Assertions.assertEquals(1, newMsgCaptor.getAllValues().size()); TbMsg outMessage = newMsgCaptor.getAllValues().get(0); @@ -309,7 +309,7 @@ public class TbMsgDeduplicationNodeTest { verify(ctx, times(msgCount)).ack(any()); verify(node, times(msgCount + wantedNumberOfTellSelfInvocation)).onMsg(eq(ctx), any()); - verify(ctx, times(2)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbRelationTypes.SUCCESS), successCaptor.capture(), failureCaptor.capture()); + verify(ctx, times(2)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.SUCCESS), successCaptor.capture(), failureCaptor.capture()); List resultMsgs = newMsgCaptor.getAllValues(); Assertions.assertEquals(2, resultMsgs.size()); @@ -363,7 +363,7 @@ public class TbMsgDeduplicationNodeTest { verify(ctx, times(msgCount)).ack(any()); verify(node, times(msgCount + wantedNumberOfTellSelfInvocation)).onMsg(eq(ctx), any()); - verify(ctx, times(2)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbRelationTypes.SUCCESS), successCaptor.capture(), failureCaptor.capture()); + verify(ctx, times(2)).enqueueForTellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.SUCCESS), successCaptor.capture(), failureCaptor.capture()); List resultMsgs = newMsgCaptor.getAllValues(); Assertions.assertEquals(2, resultMsgs.size()); From 014497cd89a2a3d8731548bf1a0bfdaf12c0d204 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 26 May 2023 15:04:23 +0300 Subject: [PATCH 131/421] User-level notification settings --- .../controller/NotificationController.java | 9 +++ .../DefaultNotificationCenter.java | 11 ++++ .../NotificationSettingsService.java | 7 ++ .../NotificationDeliveryMethod.java | 6 ++ .../settings/UserNotificationSettings.java | 64 +++++++++++++++++++ .../DefaultNotificationSettingsService.java | 26 ++++++++ 6 files changed, 123 insertions(+) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java index 0f4a288e33..0d9319ffa5 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.notification.NotificationRequest; import org.thingsboard.server.common.data.notification.NotificationRequestInfo; import org.thingsboard.server.common.data.notification.NotificationRequestPreview; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; +import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings; import org.thingsboard.server.common.data.notification.targets.NotificationRecipient; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.NotificationTargetType; @@ -437,4 +438,12 @@ public class NotificationController extends BaseController { return notificationCenter.getAvailableDeliveryMethods(user.getTenantId()); } + + @PostMapping("/notification/settings/user") + public UserNotificationSettings saveUserNotificationSettings(@RequestBody @Valid UserNotificationSettings settings, + @AuthenticationPrincipal SecurityUser user) { + notificationSettingsService.saveUserNotificationSettings(user.getTenantId(), user.getId(), settings); + return settings; + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index cb77cc0948..71a842b441 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -37,8 +37,10 @@ import org.thingsboard.server.common.data.notification.NotificationRequestConfig import org.thingsboard.server.common.data.notification.NotificationRequestStats; import org.thingsboard.server.common.data.notification.NotificationRequestStatus; import org.thingsboard.server.common.data.notification.NotificationStatus; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.info.RuleOriginatedNotificationInfo; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; +import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings; import org.thingsboard.server.common.data.notification.targets.NotificationRecipient; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; @@ -238,6 +240,15 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple if (ctx.getStats().contains(deliveryMethod, recipient.getId())) { throw new AlreadySentException(); } + if (recipient instanceof User) { + NotificationType notificationType = ctx.getNotificationTemplate().getNotificationType(); + UserNotificationSettings settings = notificationSettingsService.getUserNotificationSettings(ctx.getTenantId(), (User) recipient); + Set enabledDeliveryMethods = settings.getEnabledDeliveryMethods(notificationType); + if (!enabledDeliveryMethods.contains(deliveryMethod)) { + throw new RuntimeException("User disabled " + deliveryMethod.getName() + " notifications of this type"); + } + } + NotificationChannel notificationChannel = channels.get(deliveryMethod); DeliveryMethodNotificationTemplate processedTemplate = ctx.getProcessedTemplate(deliveryMethod, recipient); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java index a5433915b3..bb53b1a828 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java @@ -15,8 +15,11 @@ */ package org.thingsboard.server.dao.notification; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; +import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings; public interface NotificationSettingsService { @@ -24,6 +27,10 @@ public interface NotificationSettingsService { NotificationSettings findNotificationSettings(TenantId tenantId); + void saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings); + + UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user); + void createDefaultNotificationConfigs(TenantId tenantId); void updateDefaultNotificationConfigs(TenantId tenantId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java index 4a2c4657d5..ac878adac6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java @@ -18,6 +18,10 @@ package org.thingsboard.server.common.data.notification; import lombok.Getter; import lombok.RequiredArgsConstructor; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + @RequiredArgsConstructor public enum NotificationDeliveryMethod { @@ -29,4 +33,6 @@ public enum NotificationDeliveryMethod { @Getter private final String name; + public static final Set values = Arrays.stream(values()).collect(Collectors.toSet()); + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java new file mode 100644 index 0000000000..efe5194585 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java @@ -0,0 +1,64 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.notification.settings; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; +import org.thingsboard.server.common.data.notification.NotificationType; +import org.thingsboard.server.common.data.util.CollectionsUtil; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +@Data +public class UserNotificationSettings { + + private final Map prefs; + + @JsonCreator + public UserNotificationSettings(@JsonProperty("prefs") Map prefs) { + this.prefs = prefs; + } + + public static final UserNotificationSettings DEFAULT = new UserNotificationSettings(Collections.emptyMap()); + + public Set getEnabledDeliveryMethods(NotificationType notificationType) { + NotificationTypePrefs prefs; + if (this.prefs == null || (prefs = this.prefs.get(notificationType)) == null) { + return NotificationDeliveryMethod.values; + } + if (prefs.isEnabled()) { + Set deliveryMethods = prefs.getEnabledDeliveryMethods(); + if (CollectionsUtil.isNotEmpty(deliveryMethods)) { + return deliveryMethods; + } else { + return NotificationDeliveryMethod.values; + } + } else { + return Collections.emptySet(); + } + } + + @Data + public static class NotificationTypePrefs { + private boolean enabled; + private Set enabledDeliveryMethods; + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java index 4262decfed..90ccd095d6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.dao.notification; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; @@ -24,9 +26,12 @@ import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; +import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.platform.AffectedTenantAdministratorsFilter; import org.thingsboard.server.common.data.notification.targets.platform.AffectedUserFilter; @@ -39,6 +44,7 @@ import org.thingsboard.server.common.data.notification.targets.platform.UsersFil import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.settings.AdminSettingsService; +import org.thingsboard.server.dao.user.UserService; import java.util.Collections; import java.util.List; @@ -52,6 +58,7 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS private final NotificationTargetService notificationTargetService; private final NotificationTemplateService notificationTemplateService; private final DefaultNotifications defaultNotifications; + private final UserService userService; private static final String SETTINGS_KEY = "notifications"; @@ -81,6 +88,25 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS }); } + @Override + public void saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings) { + User user = userService.findUserById(tenantId, userId); + ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(user.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); + additionalInfo.set("notificationSettings", JacksonUtil.valueToTree(settings)); + user.setAdditionalInfo(additionalInfo); + userService.saveUser(user); + } + + @Override + public UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user) { + // TODO: decide whether to use user_settings or store it in the additionalInfo not to make more DB requests + JsonNode notificationSettings = user.getAdditionalInfo().get("notificationSettings"); + if (notificationSettings == null || notificationSettings.isNull()) { + return UserNotificationSettings.DEFAULT; + } + return JacksonUtil.treeToValue(notificationSettings, UserNotificationSettings.class); + } + @Transactional(propagation = Propagation.NOT_SUPPORTED) // so that parent transaction is not aborted on method failure @Override public void createDefaultNotificationConfigs(TenantId tenantId) { From ab93f6266d714d7247785a756cf0c274f1c5338b Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 20 Jun 2023 12:10:28 +0300 Subject: [PATCH 132/421] Add getUserNotificationSettings api --- .../server/controller/NotificationController.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java index 0d9319ffa5..a7072f6a9d 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -440,10 +440,18 @@ public class NotificationController extends BaseController { @PostMapping("/notification/settings/user") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public UserNotificationSettings saveUserNotificationSettings(@RequestBody @Valid UserNotificationSettings settings, @AuthenticationPrincipal SecurityUser user) { notificationSettingsService.saveUserNotificationSettings(user.getTenantId(), user.getId(), settings); return settings; } + @GetMapping("/notification/settings/user") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") + public UserNotificationSettings getUserNotificationSettings(@AuthenticationPrincipal SecurityUser user) { + return notificationSettingsService.getUserNotificationSettings(user.getTenantId(), + userService.findUserById(user.getTenantId(), user.getId())); + } + } From bbcf4b1ff122b67e38949911fcd7e52c51459970 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 20 Jun 2023 18:07:37 +0300 Subject: [PATCH 133/421] Fix MockNotificationSettingsService --- .../service/notification/MockNotificationSettingsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java b/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java index a49f8dc8cb..860596961e 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java @@ -26,7 +26,7 @@ import org.thingsboard.server.dao.settings.AdminSettingsService; public class MockNotificationSettingsService extends DefaultNotificationSettingsService { public MockNotificationSettingsService(AdminSettingsService adminSettingsService) { - super(adminSettingsService, null, null, null); + super(adminSettingsService, null, null, null, null); } @Override From 1ec37d7685b3fe47e86a49d231a5cb26e5e64f82 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 20 Jun 2023 18:52:13 +0300 Subject: [PATCH 134/421] UI: Improve data keys config. Fix datasource type processing. --- ui-ngx/src/app/core/api/alias-controller.ts | 10 +- ui-ngx/src/app/core/services/utils.service.ts | 10 +- ui-ngx/src/app/core/ws/websocket.service.ts | 4 +- ...entities-table-basic-config.component.html | 1 + .../basic/common/data-key-row.component.html | 16 +++ .../basic/common/data-key-row.component.scss | 16 +++ .../basic/common/data-key-row.component.ts | 29 +++- .../common/data-keys-panel.component.html | 20 ++- .../common/data-keys-panel.component.scss | 17 +-- .../basic/common/data-keys-panel.component.ts | 7 + .../data-key-config-dialog.component.html | 7 +- .../data-key-config-dialog.component.ts | 38 ++++- .../config/data-key-config.component.html | 134 ++++++++++-------- .../config/data-key-config.component.scss | 23 +-- .../config/data-key-config.component.ts | 17 ++- ...entities-table-key-settings.component.html | 99 +++++++------ .../widget/lib/settings/widget-settings.scss | 4 + ui-ngx/src/app/shared/models/widget.models.ts | 5 + .../assets/locale/locale.constant-en_US.json | 2 + ui-ngx/src/styles.scss | 22 +++ 20 files changed, 305 insertions(+), 176 deletions(-) diff --git a/ui-ngx/src/app/core/api/alias-controller.ts b/ui-ngx/src/app/core/api/alias-controller.ts index be08d50d69..971f238d83 100644 --- a/ui-ngx/src/app/core/api/alias-controller.ts +++ b/ui-ngx/src/app/core/api/alias-controller.ts @@ -252,10 +252,9 @@ export class AliasController implements IAliasController { private resolveDatasource(datasource: Datasource, forceFilter = false): Observable { const newDatasource = deepClone(datasource); - if (newDatasource.type === DatasourceType.device) { - newDatasource.type = DatasourceType.entity; - } - if (newDatasource.type === DatasourceType.entity || newDatasource.type === DatasourceType.entityCount + if (newDatasource.type === DatasourceType.entity + || newDatasource.type === DatasourceType.device + || newDatasource.type === DatasourceType.entityCount || newDatasource.type === DatasourceType.alarmCount) { if (newDatasource.filterId) { newDatasource.keyFilters = this.getKeyFilters(newDatasource.filterId); @@ -263,7 +262,8 @@ export class AliasController implements IAliasController { if (newDatasource.type === DatasourceType.alarmCount) { newDatasource.alarmFilter = this.entityService.resolveAlarmFilter(newDatasource.alarmFilterConfig, false); } - if (newDatasource.deviceId) { + if (newDatasource.type === DatasourceType.device) { + newDatasource.type = DatasourceType.entity; newDatasource.entityFilter = singleEntityFilterFromDeviceId(newDatasource.deviceId); if (forceFilter) { return this.entityService.findSingleEntityInfoByEntityFilter(newDatasource.entityFilter, diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index f82c6c3072..09a0a08d58 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -282,13 +282,9 @@ export class UtilsService { public validateDatasources(datasources: Array): Array { datasources.forEach((datasource) => { - // @ts-ignore - if (datasource.type === 'device') { - datasource.type = DatasourceType.entity; - datasource.entityType = EntityType.DEVICE; - if (datasource.deviceId) { - datasource.entityId = datasource.deviceId; - } else if (datasource.deviceAliasId) { + if (datasource.type === DatasourceType.device) { + if (datasource.deviceAliasId) { + datasource.type = DatasourceType.entity; datasource.entityAliasId = datasource.deviceAliasId; } if (datasource.deviceName) { diff --git a/ui-ngx/src/app/core/ws/websocket.service.ts b/ui-ngx/src/app/core/ws/websocket.service.ts index 51545a6d54..2d2162267d 100644 --- a/ui-ngx/src/app/core/ws/websocket.service.ts +++ b/ui-ngx/src/app/core/ws/websocket.service.ts @@ -97,7 +97,9 @@ export abstract class WebsocketService implements WsServ this.dataStream.next(this.cmdWrapper.preparePublishCommands(MAX_PUBLISH_COMMANDS)); this.checkToClose(); } - this.tryOpenSocket(); + if (this.subscribersCount > 0) { + this.tryOpenSocket(); + } } private checkToClose() { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html index ee76bdf472..65b08c6798 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html @@ -28,6 +28,7 @@
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss index 5b3d4f1a80..8bb8d720f3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss @@ -51,3 +51,19 @@ align-items: center; } } + +.tb-data-keys-table-row-buttons { + display: flex; + flex-direction: row; + button.mat-mdc-icon-button.mat-mdc-button-base { + padding: 7px; + width: 38px; + height: 38px; + .mat-icon { + color: rgba(0, 0, 0, 0.38); + } + &.tb-hidden { + visibility: hidden; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts index d434ef74e3..750abd3a8a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts @@ -18,10 +18,12 @@ import { ChangeDetectorRef, Component, ElementRef, + EventEmitter, forwardRef, Input, OnChanges, OnInit, + Output, SimpleChanges, ViewChild, ViewEncapsulation @@ -37,7 +39,14 @@ import { } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; -import { DataKey, DatasourceType, JsonSettingsSchema, Widget, widgetType } from '@shared/models/widget.models'; +import { + DataKey, + DataKeyConfigMode, + DatasourceType, + JsonSettingsSchema, + Widget, + widgetType +} from '@shared/models/widget.models'; import { DataKeysPanelComponent } from '@home/components/widget/config/basic/common/data-keys-panel.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { AggregationType } from '@shared/models/time/time.models'; @@ -104,6 +113,9 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan @Input() deviceId: string; + @Output() + keyRemoved = new EventEmitter(); + keyFormControl: UntypedFormControl; keyRowFormGroup: UntypedFormGroup; @@ -169,6 +181,18 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan return this.modelValue.type && ![ DataKeyType.alarm, DataKeyType.entityField, DataKeyType.count ].includes(this.modelValue.type); } + get keySettingsTitle(): string { + return this.dataKeysPanelComponent.keySettingsTitle; + } + + get removeKeyTitle(): string { + return this.dataKeysPanelComponent.removeKeyTitle; + } + + get dragEnabled(): boolean { + return this.dataKeysPanelComponent.dragEnabled; + } + private propagateChange = (_val: any) => {}; constructor(private fb: UntypedFormBuilder, @@ -291,13 +315,14 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan } } - editKey() { + editKey(advanced = false) { this.dialog.open(DataKeyConfigDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { dataKey: deepClone(this.modelValue), + dataKeyConfigMode: advanced ? DataKeyConfigMode.advanced : DataKeyConfigMode.general, dataKeySettingsSchema: this.datakeySettingsSchema, dataKeySettingsDirective: this.dataKeySettingsDirective, dashboard: this.dashboard, diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html index 754f0052c9..6960e57ee1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html @@ -26,27 +26,25 @@
widget-config.decimals-short
-
-
+
+ [entityAliasId]="entityAliasId" + (keyRemoved)="removeKey($index)">
- - + + {{notificationSettingsFormGroup.get('ruleName').value}} + +
+
+
+ +
+
+
+ diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.scss b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.scss new file mode 100644 index 0000000000..ee37181a09 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.scss @@ -0,0 +1,24 @@ +/** + * Copyright © 2016-2023 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 { + .notification-type { + font-size: 14px; + + &-disabled { + color: rgba(0, 0, 0, 0.38) + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts new file mode 100644 index 0000000000..7e79419969 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts @@ -0,0 +1,139 @@ +/// +/// Copyright © 2016-2023 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, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { UtilsService } from '@core/services/utils.service'; +import { isDefinedAndNotNull } from '@core/utils'; +import { Subscription } from 'rxjs'; +import { NotificationDeliveryMethod, NotificationUserSetting } from '@shared/models/notification.models'; + +@Component({ + selector: 'tb-notification-setting-form', + templateUrl: './notification-setting-form.component.html', + styleUrls: ['./notification-setting-form.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => NotificationSettingFormComponent), + multi: true + } + ] +}) +export class NotificationSettingFormComponent implements ControlValueAccessor, OnInit, OnDestroy { + + @Input() + disabled: boolean; + + @Input() + allowDeliveryMethods = []; + + notificationSettingsFormGroup: UntypedFormGroup; + + notificationDeliveryMethod = NotificationDeliveryMethod; + notificationDeliveryMethodMap = Object.keys(NotificationDeliveryMethod) as NotificationDeliveryMethod[]; + + private modelValue; + private propagateChange = null; + private propagateChangePending = false; + private valueChange$: Subscription = null; + + constructor(private utils: UtilsService, + private fb: UntypedFormBuilder) { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + if (this.propagateChangePending) { + this.propagateChangePending = false; + setTimeout(() => { + this.propagateChange(this.modelValue); + }, 0); + } + } + + registerOnTouched(fn: any): void { + } + + ngOnInit() { + this.notificationSettingsFormGroup = this.fb.group( + { + ruleId: [], + ruleName: [''], + enabled: [true], + enabledDeliveryMethods: [] + }); + this.valueChange$ = this.notificationSettingsFormGroup.valueChanges.subscribe(() => { + this.updateModel(); + }); + } + + ngOnDestroy() { + if (this.valueChange$) { + this.valueChange$.unsubscribe(); + this.valueChange$ = null; + } + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.notificationSettingsFormGroup.disable({emitEvent: false}); + } else { + this.notificationSettingsFormGroup.enable({emitEvent: false}); + } + } + + toggleEnabled() { + this.notificationSettingsFormGroup.get('enabled').patchValue(!this.notificationSettingsFormGroup.get('enabled').value, + {emitEvent: true}); + } + + getChecked(deliveryMethod: NotificationDeliveryMethod): boolean { + return this.notificationSettingsFormGroup.get('enabledDeliveryMethods').value.includes(deliveryMethod); + } + + toggleDeliviryMethod(deliveryMethod: NotificationDeliveryMethod) { + const enabledDeliveryMethods = this.notificationSettingsFormGroup.get('enabledDeliveryMethods').value; + if (enabledDeliveryMethods.includes(deliveryMethod)) { + enabledDeliveryMethods.splice(enabledDeliveryMethods.indexOf(deliveryMethod), 1); + } else { + enabledDeliveryMethods.push(deliveryMethod); + } + this.notificationSettingsFormGroup.get('enabledDeliveryMethods').patchValue(enabledDeliveryMethods); + } + + writeValue(value: NotificationUserSetting): void { + this.propagateChangePending = false; + this.modelValue = value; + if (isDefinedAndNotNull(this.modelValue)) { + this.notificationSettingsFormGroup.patchValue(this.modelValue, {emitEvent: false}); + if (!this.disabled && !this.notificationSettingsFormGroup.valid) { + this.updateModel(); + } + } + } + + private updateModel() { + const value = this.notificationSettingsFormGroup.value; + this.modelValue = {...this.modelValue, ...value}; + if (this.propagateChange) { + this.propagateChange(this.modelValue); + } else { + this.propagateChangePending = true; + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts new file mode 100644 index 0000000000..346d67649d --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts @@ -0,0 +1,63 @@ +/// +/// Copyright © 2016-2023 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 { Resolve, RouterModule, Routes } from '@angular/router'; +import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; +import { Authority } from '@shared/models/authority.enum'; +import { Injectable, NgModule } from '@angular/core'; +import { NotificationSettingsComponent } from '@home/pages/notification/settings/notification-settings.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Observable } from 'rxjs'; +import { NotificationService } from '@core/http/notification.service'; + +@Injectable() +export class NotificationUserSettingsResolver implements Resolve { + + constructor(private store: Store, + private notificationService: NotificationService) { + } + + resolve(): Observable { + return this.notificationService.getNotificationUserSettings(); + } +} + +const routes: Routes = [ + { + path: 'notificationSettings', + component: NotificationSettingsComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN, Authority.CUSTOMER_USER], + title: 'account.notification-settings', + breadcrumb: { + label: 'account.notification-settings', + icon: 'settings' + } + }, + resolve: { + userSettings: NotificationUserSettingsResolver + } + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], + providers: [NotificationUserSettingsResolver] +}) +export class NotificationSettingsRoutingModules { } diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html new file mode 100644 index 0000000000..ed1b9e3d52 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html @@ -0,0 +1,80 @@ + +
+ + +
+
+ notification.settings.notification-settings +
+
+ +
+
+
+ + +
+ +
+
+
+
+
+ + notification.settings.type + +
+
+
+ + {{ notificationDeliveryMethodTranslateMap.get(deliveryMethods) | translate }} + +
+
+
+ +
+ + +
+
+
+
+ +
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss new file mode 100644 index 0000000000..12263158d1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss @@ -0,0 +1,37 @@ +/** + * Copyright © 2016-2023 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 { + .mat-mdc-card.settings-card { + margin: 8px; + @media #{$mat-gt-sm} { + width: 60%; + } + .mat-headline-5 { + margin: 0; + } + .notification-section { + margin-bottom: 16px; + border: 1px solid rgba(0, 0, 0, 0.12); + overflow-y: hidden; + overflow-x: scroll; + &-block { + min-width: 700px; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts new file mode 100644 index 0000000000..183ebb9a99 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts @@ -0,0 +1,167 @@ +/// +/// Copyright © 2016-2023 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, OnInit } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard'; +import { TranslateService } from '@ngx-translate/core'; +import { ActivatedRoute } from '@angular/router'; +import { deepClone, isDefinedAndNotNull } from '@core/utils'; +import { + NotificationDeliveryMethod, + NotificationDeliveryMethodTranslateMap, + NotificationUserSettings +} from '@shared/models/notification.models'; +import { NotificationService } from '@core/http/notification.service'; +import { DialogService } from '@core/services/dialog.service'; + +@Component({ + selector: 'tb-notification-settings', + templateUrl: './notification-settings.component.html', + styleUrls: ['./notification-settings.component.scss'] +}) +export class NotificationSettingsComponent extends PageComponent implements OnInit, HasConfirmForm { + + notificationSettings: UntypedFormGroup; + + notificationDeliveryMethods = Object.keys(NotificationDeliveryMethod) as NotificationDeliveryMethod[]; + notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap; + + allowNotificationDeliveryMethods: Array; + + constructor(protected store: Store, + private route: ActivatedRoute, + private translate: TranslateService, + private dialogService: DialogService, + private notificationService: NotificationService, + private fb: UntypedFormBuilder,) { + super(store); + } + + ngOnInit() { + + this.notificationService.getAvailableDeliveryMethods({ignoreLoading: true}).subscribe(allowMethods => { + this.allowNotificationDeliveryMethods = allowMethods; + }); + + this.buildNotificationSettingsForm(); + this.patchNotificationSettings(this.route.snapshot.data.userSettings); + } + + private buildNotificationSettingsForm() { + this.notificationSettings = this.fb.group({ + prefs: this.fb.array([]) + }); + } + + private patchNotificationSettings(settings: NotificationUserSettings) { + const notificationSettingsControls: Array = []; + if (settings.prefs) { + settings.prefs.forEach((setting) => { + notificationSettingsControls.push(this.fb.control(setting, [Validators.required])); + }); + } + this.notificationSettings.setControl('prefs', this.fb.array(notificationSettingsControls), {emitEvent: false}); + } + + resetSettings() { + this.dialogService.confirm( + this.translate.instant('notification.settings.reset-all-title'), + this.translate.instant('notification.settings.reset-all-text'), + this.translate.instant('action.no'), + this.translate.instant('action.yes'), + true + ).subscribe( + result => { + if (result) { + const settings = this.route.snapshot.data.userSettings; + const notificationSettingsControls: Array = []; + this.notificationSettings.reset({}); + if (settings.prefs) { + settings.prefs.forEach((setting) => { + setting.enabled = true; + setting.enabledDeliveryMethods = this.notificationDeliveryMethods; + notificationSettingsControls.push(this.fb.control(setting, [Validators.required])); + }); + } + this.notificationSettings.setControl('prefs', this.fb.array(notificationSettingsControls), {emitEvent: false}); + this.save(); + } + } + ); + } + + getChecked = (method: NotificationDeliveryMethod = null): boolean => { + const type = this.notificationSettings.get('prefs').value; + if (isDefinedAndNotNull(method)) { + return isDefinedAndNotNull(type) && type.every(resource => resource.enabledDeliveryMethods.includes(method)); + } + return isDefinedAndNotNull(type) && type.every(resource => resource.enabled); + }; + + getSomeChecked = () => { + const type = this.notificationSettings.get('prefs').value; + return isDefinedAndNotNull(type) && type.some(resource => resource.enabled); + }; + + getIndeterminate = (deliveryMethod: NotificationDeliveryMethod = null): boolean => { + const type = this.notificationSettings.get('prefs').value; + if (isDefinedAndNotNull(type)) { + const checkedResource = isDefinedAndNotNull(deliveryMethod) ? + type.filter(resource => resource.enabledDeliveryMethods.includes(deliveryMethod)) : + type.filter(resource => resource.enabled); + return checkedResource.length !== 0 && checkedResource.length !== type.length; + } + return false; + }; + + changeInstanceTypeCheckBox = (value: boolean, deliveryMethod: NotificationDeliveryMethod = null): void => { + const type = deepClone(this.notificationSettings.get('prefs').value); + if (isDefinedAndNotNull(deliveryMethod)) { + type.forEach(notificationType => { + if (value && !notificationType.enabledDeliveryMethods.includes(deliveryMethod)) { + notificationType.enabledDeliveryMethods.push(deliveryMethod); + } else if (!value && notificationType.enabledDeliveryMethods.includes(deliveryMethod)) { + notificationType.enabledDeliveryMethods.splice(notificationType.enabledDeliveryMethods.indexOf(deliveryMethod), 1); + } + }); + } else { + type.forEach(notificationType => notificationType.enabled = value); + } + this.notificationSettings.get('prefs').patchValue(type); + this.notificationSettings.markAsDirty(); + }; + + get notificationSettingsFormArray(): UntypedFormArray { + return this.notificationSettings.get('prefs') as UntypedFormArray; + } + + save(): void { + this.notificationService.saveNotificationUserSettings(this.notificationSettings.getRawValue()).subscribe( + (userSettings) => { + this.notificationSettings.get('prefs').reset({}); + this.patchNotificationSettings(userSettings); + } + ); + } + + confirmForm(): UntypedFormGroup { + return this.notificationSettings; + } +} diff --git a/ui-ngx/src/app/shared/components/user-menu.component.html b/ui-ngx/src/app/shared/components/user-menu.component.html index a25a0fec25..5d032d83ba 100644 --- a/ui-ngx/src/app/shared/components/user-menu.component.html +++ b/ui-ngx/src/app/shared/components/user-menu.component.html @@ -30,12 +30,12 @@
- + + + + - - - - -
{{alarmSeverityTranslations.get(notification.info.alarmSeverity) | translate}} diff --git a/ui-ngx/src/app/shared/components/notification/notification.component.ts b/ui-ngx/src/app/shared/components/notification/notification.component.ts index ad543c43c1..6e1ff508a7 100644 --- a/ui-ngx/src/app/shared/components/notification/notification.component.ts +++ b/ui-ngx/src/app/shared/components/notification/notification.component.ts @@ -139,7 +139,7 @@ export class NotificationComponent implements OnInit { } notificationColor(): string { - if (this.notification.type === NotificationType.ALARM) { + if (this.notification.type === NotificationType.ALARM && !this.notification.info.cleared) { return AlarmSeverityNotificationColors.get(this.notification.info.alarmSeverity); } return 'transparent'; diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 2cef7c6cc2..4d8a9cffcd 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -48,6 +48,8 @@ export interface NotificationInfo { alarmStatus?: AlarmStatus; alarmType?: string; stateEntityId?: EntityId; + acknowledged?: boolean; + cleared?: boolean; } export interface NotificationRequest extends Omit, 'label'> { From 7ff353a4d9758f40314f7e991ef87f1f94dcac34 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 27 Jun 2023 17:54:02 +0300 Subject: [PATCH 167/421] swagger_device_controller: fix bug example request - X509, MQTT_BASIC --- .../controller/ControllerConstants.java | 81 ++++++++++++++++++- .../server/controller/DeviceController.java | 13 ++- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index 6fe53516ed..bbd2773e6b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -15,6 +15,16 @@ */ package org.thingsboard.server.controller; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.thingsboard.server.common.msg.EncryptionUtil.certTrimNewLinesForChainInDeviceProfile; + public class ControllerConstants { protected static final String NEW_LINE = "\n\n"; @@ -236,7 +246,59 @@ public class ControllerConstants { " }\n" + "}"; - protected static final String CREDENTIALS_VALUE_LVM2M_RPK_DESCRIPTION = + protected static final String[] getCertificateValue() { + String filePath = "src/test/resources/provision/x509ChainProvisionTest.pem"; + try { + String certificateChain = Files.readString(Paths.get(filePath)); + certificateChain = certTrimNewLinesForChainInDeviceProfile(certificateChain); + return fetchLeafCertificateFromChain(certificateChain); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected static final String certificateValue = "\"-----BEGIN CERTIFICATE----- " + + "MIICMTCCAdegAwIBAgIUI9dBuwN6pTtK6uZ03rkiCwV4wEYwCgYIKoZIzj0EAwIwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlQ2VydGlmaWNhdGVAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MB4XDTIzMDMyOTE0NTYxN1oXDTI0MDMyODE0NTYxN1owbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlQ2VydGlmaWNhdGVAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9Zo791qKQiGNBm11r4ZGxh+w+ossZL3xc46ufq5QckQHP7zkD2XDAcmP5GvdkM1sBFN9AWaCkQfNnWmfERsOOKNTMFEwHQYDVR0OBBYEFFFc5uyCyglQoZiKhzXzMcQ3BKORMB8GA1UdIwQYMBaAFFFc5uyCyglQoZiKhzXzMcQ3BKORMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhANbA9CuhoOifZMMmqkpuld+65CR+ItKdXeRAhLMZuccuAiB0FSQB34zMutXrZj1g8Gl5OkE7YryFHbei1z0SveHR8g== " + + "-----END CERTIFICATE-----\""; + + protected static final String certificateId = "\"84f5911765abba1f96bf4165604e9e90338fc6214081a8e623b6ff9669aedb27\""; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_X509_CERTIFICATE_PARAM_DESCRIPTION = + "{\n" + + " \"device\": {\n" + + " \"name\":\"Name_DeviceWithCredantial_X509_Certificate\",\n" + + " \"label\":\"Label_DeviceWithCredantial_X509_Certificate\",\n" + + " \"deviceProfileId\":{\n" + + " \"id\":\"9d9588c0-06c9-11ee-b618-19be30fdeb60\",\n" + + " \"entityType\":\"DEVICE_PROFILE\"\n" + + " }\n" + + " },\n" + + " \"credentials\": {\n" + + " \"credentialsType\": \"X509_CERTIFICATE\",\n" + + " \"credentialsId\": " + certificateId + ",\n" + + " \"credentialsValue\": " + certificateValue + "\n" + + " }\n" + + "}"; + + protected static final String MQTT_BASIC_VALUE = "\"{\\\"clientId\\\":\\\"5euh5nzm34bjjh1efmlt\\\",\\\"userName\\\":\\\"onasd1lgwasmjl7v2v7h\\\",\\\"password\\\":\\\"b9xtm4ny8kt9zewaga5o\\\"}\""; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_MQTT_BASIC_PARAM_DESCRIPTION = + "{\n" + + " \"device\": {\n" + + " \"name\":\"Name_DeviceWithCredantial_MQTT_Basic\",\n" + + " \"label\":\"Label_DeviceWithCredantial_MQTT_Basic\",\n" + + " \"deviceProfileId\":{\n" + + " \"id\":\"9d9588c0-06c9-11ee-b618-19be30fdeb60\",\n" + + " \"entityType\":\"DEVICE_PROFILE\"\n" + + " }\n" + + " },\n" + + " \"credentials\": {\n" + + " \"credentialsType\": \"MQTT_BASIC\",\n" + + " \"credentialsValue\": " + MQTT_BASIC_VALUE + "\n" + + " }\n" + + "}"; + + protected static final String CREDENTIALS_VALUE_LVM2M_RPK_DESCRIPTION = " \"{" + "\\\"client\\\":{ " + "\\\"endpoint\\\":\\\"LwRpk00000000\\\", " + @@ -279,6 +341,12 @@ public class ControllerConstants { protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN = MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_ACCESS_TOKEN_DEFAULT_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_X509_CERTIFICATE_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_MQTT_BASIC_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN = MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; @@ -1594,4 +1662,15 @@ public class ControllerConstants { MARKDOWN_CODE_BLOCK_START + "[{\"ts\":1634712287000,\"values\":{\"temperature\":26, \"humidity\":87}}, {\"ts\":1634712588000,\"values\":{\"temperature\":25, \"humidity\":88}}]" + MARKDOWN_CODE_BLOCK_END ; + + private static String[] fetchLeafCertificateFromChain(String value) { + List chain = new ArrayList<>(); + String regex = "-----BEGIN CERTIFICATE-----\\s*.*?\\s*-----END CERTIFICATE-----"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(value); + while (matcher.find()) { + chain.add(matcher.group(0)); + } + return chain.toArray(new String[0]); + } } diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 842e47756d..f033b2758f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -96,6 +96,8 @@ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TYPE_ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_ASYNC_FIRST_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ASSIGN_RECEIVE_STEP_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.EDGE_ID_PARAM_DESCRIPTION; @@ -185,13 +187,18 @@ public class DeviceController extends BaseController { @ApiOperation(value = "Create Device (saveDevice) with credentials ", notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK + "Requires to provide the Device Credentials object as well as an existing device profile ID or use \"default\".\n" + - "Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" + "You may find the example of device with different type of credentials below: \n\n" + - "- Credentials type: \"Access token\" with Device profile ID below: \n\n" + + "- Credentials type: \"Access token\" with device profile ID below: \n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" + - "- Credentials type: \"Access token\" with Device profile default below: \n\n" + + "- Credentials type: \"Access token\" with device profile default below: \n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN + "\n\n" + + "- Credentials type: \"X509\" with device profile ID below: \n\n" + + "Note: credentialsId - format Sha3Hash, certificateValue - format PEM (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" + + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" + + "- Credentials type: \"MQTT_BASIC\" with device profile ID below: \n\n" + + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" + "- You may find the example of LwM2M device and RPK credentials below: \n\n" + + "Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" + "Remove 'id', 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) From 1cb74577d510bf971c57507c24156fa618e5d213 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 27 Jun 2023 18:09:21 +0300 Subject: [PATCH 168/421] swagger_device_controller: refactoring fix bug example request - X509, MQTT_BASIC --- .../controller/ControllerConstants.java | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index bbd2773e6b..7701a19f02 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -15,16 +15,6 @@ */ package org.thingsboard.server.controller; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static org.thingsboard.server.common.msg.EncryptionUtil.certTrimNewLinesForChainInDeviceProfile; - public class ControllerConstants { protected static final String NEW_LINE = "\n\n"; @@ -246,17 +236,6 @@ public class ControllerConstants { " }\n" + "}"; - protected static final String[] getCertificateValue() { - String filePath = "src/test/resources/provision/x509ChainProvisionTest.pem"; - try { - String certificateChain = Files.readString(Paths.get(filePath)); - certificateChain = certTrimNewLinesForChainInDeviceProfile(certificateChain); - return fetchLeafCertificateFromChain(certificateChain); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - protected static final String certificateValue = "\"-----BEGIN CERTIFICATE----- " + "MIICMTCCAdegAwIBAgIUI9dBuwN6pTtK6uZ03rkiCwV4wEYwCgYIKoZIzj0EAwIwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlQ2VydGlmaWNhdGVAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MB4XDTIzMDMyOTE0NTYxN1oXDTI0MDMyODE0NTYxN1owbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlQ2VydGlmaWNhdGVAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9Zo791qKQiGNBm11r4ZGxh+w+ossZL3xc46ufq5QckQHP7zkD2XDAcmP5GvdkM1sBFN9AWaCkQfNnWmfERsOOKNTMFEwHQYDVR0OBBYEFFFc5uyCyglQoZiKhzXzMcQ3BKORMB8GA1UdIwQYMBaAFFFc5uyCyglQoZiKhzXzMcQ3BKORMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhANbA9CuhoOifZMMmqkpuld+65CR+ItKdXeRAhLMZuccuAiB0FSQB34zMutXrZj1g8Gl5OkE7YryFHbei1z0SveHR8g== " + "-----END CERTIFICATE-----\""; @@ -1662,15 +1641,4 @@ public class ControllerConstants { MARKDOWN_CODE_BLOCK_START + "[{\"ts\":1634712287000,\"values\":{\"temperature\":26, \"humidity\":87}}, {\"ts\":1634712588000,\"values\":{\"temperature\":25, \"humidity\":88}}]" + MARKDOWN_CODE_BLOCK_END ; - - private static String[] fetchLeafCertificateFromChain(String value) { - List chain = new ArrayList<>(); - String regex = "-----BEGIN CERTIFICATE-----\\s*.*?\\s*-----END CERTIFICATE-----"; - Pattern pattern = Pattern.compile(regex); - Matcher matcher = pattern.matcher(value); - while (matcher.find()) { - chain.add(matcher.group(0)); - } - return chain.toArray(new String[0]); - } } From 987d41f329cd941dc43e6c917bcd10e36bf95acc Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 27 Jun 2023 18:17:15 +0300 Subject: [PATCH 169/421] UI: Timeseries table basic config --- .../json/system/widget_bundles/cards.json | 4 +- .../dashboard-page.component.ts | 4 +- .../basic/basic-widget-config.module.ts | 8 +- .../entities-table-basic-config.component.ts | 9 +- ...meseries-table-basic-config.component.html | 94 +++++++++ ...timeseries-table-basic-config.component.ts | 181 ++++++++++++++++++ .../basic/common/data-key-row.component.html | 6 + .../basic/common/data-key-row.component.scss | 4 + .../basic/common/data-key-row.component.ts | 38 +++- .../common/data-keys-panel.component.html | 2 + .../common/data-keys-panel.component.scss | 3 + .../basic/common/data-keys-panel.component.ts | 29 ++- ...meseries-table-key-settings.component.html | 87 +++++---- ...s-table-latest-key-settings.component.html | 104 +++++----- ...eries-table-widget-settings.component.html | 109 +++++------ .../shared/components/tb-error.component.ts | 7 +- .../assets/locale/locale.constant-en_US.json | 8 +- 17 files changed, 538 insertions(+), 159 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 9ab33665e6..473d3d215b 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -64,7 +64,9 @@ "settingsDirective": "tb-timeseries-table-widget-settings", "dataKeySettingsDirective": "tb-timeseries-table-key-settings", "latestDataKeySettingsDirective": "tb-timeseries-table-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true}" + "hasBasicMode": true, + "basicModeDirective": "tb-timeseries-table-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true,\"configMode\":\"basic\"}" } }, { diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index d6518d0007..39940546c2 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -1152,7 +1152,9 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.widgetComponentService.getWidgetInfo(widget.bundleAlias, widget.typeAlias, widget.isSystemType).subscribe( (widgetTypeInfo) => { const config: WidgetConfig = this.dashboardUtils.widgetConfigFromWidgetType(widgetTypeInfo); - config.title = 'New ' + widgetTypeInfo.widgetName; + if (!config.title) { + config.title = 'New ' + widgetTypeInfo.widgetName; + } let newWidget: Widget = { isSystemType: widget.isSystemType, bundleAlias: widget.bundleAlias, diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 73ebfb37c7..f292198f1e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -30,12 +30,16 @@ import { } from '@home/components/widget/config/basic/cards/entities-table-basic-config.component'; import { DataKeysPanelComponent } from '@home/components/widget/config/basic/common/data-keys-panel.component'; import { DataKeyRowComponent } from '@home/components/widget/config/basic/common/data-key-row.component'; +import { + TimeseriesTableBasicConfigComponent +} from '@home/components/widget/config/basic/cards/timeseries-table-basic-config.component'; @NgModule({ declarations: [ WidgetActionsPanelComponent, SimpleCardBasicConfigComponent, EntitiesTableBasicConfigComponent, + TimeseriesTableBasicConfigComponent, DataKeyRowComponent, DataKeysPanelComponent ], @@ -48,6 +52,7 @@ import { DataKeyRowComponent } from '@home/components/widget/config/basic/common WidgetActionsPanelComponent, SimpleCardBasicConfigComponent, EntitiesTableBasicConfigComponent, + TimeseriesTableBasicConfigComponent, DataKeyRowComponent, DataKeysPanelComponent ] @@ -57,5 +62,6 @@ export class BasicWidgetConfigModule { export const basicWidgetConfigComponentsMap: {[key: string]: Type} = { 'tb-simple-card-basic-config': SimpleCardBasicConfigComponent, - 'tb-entities-table-basic-config': EntitiesTableBasicConfigComponent + 'tb-entities-table-basic-config': EntitiesTableBasicConfigComponent, + 'tb-timeseries-table-basic-config': TimeseriesTableBasicConfigComponent }; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts index f7211d6a54..b0897f05bc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts @@ -28,6 +28,7 @@ import { } from '@shared/models/widget.models'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { isUndefined } from '@core/utils'; @Component({ selector: 'tb-entities-table-basic-config', @@ -75,7 +76,7 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen this.entitiesTableWidgetConfigForm = this.fb.group({ timewindowConfig: [{ useDashboardTimewindow: configData.config.useDashboardTimewindow, - displayTimewindow: configData.config.useDashboardTimewindow, + displayTimewindow: configData.config.displayTimewindow, timewindow: configData.config.timewindow }, []], datasources: [configData.config.datasources, []], @@ -155,13 +156,13 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen private getCardButtons(config: WidgetConfig): string[] { const buttons: string[] = []; - if (config.settings?.enableSearch) { + if (isUndefined(config.settings?.enableSearch) || config.settings?.enableSearch) { buttons.push('search'); } - if (config.settings?.enableSelectColumnDisplay) { + if (isUndefined(config.settings?.enableSelectColumnDisplay) || config.settings?.enableSelectColumnDisplay) { buttons.push('columnsToDisplay'); } - if (config.enableFullscreen) { + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { buttons.push('fullscreen'); } return buttons; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html new file mode 100644 index 0000000000..158b734a4a --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html @@ -0,0 +1,94 @@ + + + + + + + + +
+
widget-config.appearance
+
+ + {{ 'widget-config.card-title' | translate }} + + + + +
+
+ + {{ 'widget-config.card-icon' | translate }} + +
+ + + + + +
+
+
+
widgets.table.show-card-buttons
+ + {{ 'action.search' | translate }} + {{ 'widgets.table.columns-to-display' | translate }} + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.text-color' | translate }}
+
+ + + +
+
+
+
{{ 'widget-config.background-color' | translate }}
+
+ + + +
+
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts new file mode 100644 index 0000000000..e650f9a344 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts @@ -0,0 +1,181 @@ +/// +/// Copyright © 2016-2023 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 } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { + DataKey, + Datasource, + datasourcesHasAggregation, + datasourcesHasOnlyComparisonAggregation, WidgetConfig +} from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { deepClone, isUndefined } from '@core/utils'; + +@Component({ + selector: 'tb-timeseries-table-basic-config', + templateUrl: './timeseries-table-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigComponent { + + public get datasource(): Datasource { + const datasources: Datasource[] = this.timeseriesTableWidgetConfigForm.get('datasources').value; + if (datasources && datasources.length) { + return datasources[0]; + } else { + return null; + } + } + + timeseriesTableWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.timeseriesTableWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + this.setupDefaultDatasource(configData, + [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }]); + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + this.timeseriesTableWidgetConfigForm = this.fb.group({ + timewindowConfig: [{ + useDashboardTimewindow: configData.config.useDashboardTimewindow, + displayTimewindow: configData.config.displayTimewindow, + timewindow: configData.config.timewindow + }, []], + datasources: [configData.config.datasources, []], + columns: [this.getColumns(configData.config.datasources), []], + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + showTitleIcon: [configData.config.showTitleIcon, []], + titleIcon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + color: [configData.config.color, []], + backgroundColor: [configData.config.backgroundColor, []], + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; + this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; + this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + this.widgetConfig.config.datasources = config.datasources; + this.setColumns(config.columns, this.widgetConfig.config.datasources); + this.widgetConfig.config.actions = config.actions; + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.widgetConfig.config.settings.entitiesTitle = config.title; + this.widgetConfig.config.showTitleIcon = config.showTitleIcon; + this.widgetConfig.config.titleIcon = config.titleIcon; + this.widgetConfig.config.iconColor = config.iconColor; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.color = config.color; + this.widgetConfig.config.backgroundColor = config.backgroundColor; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showTitleIcon']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.timeseriesTableWidgetConfigForm.get('showTitle').value; + const showTitleIcon: boolean = this.timeseriesTableWidgetConfigForm.get('showTitleIcon').value; + if (showTitle) { + this.timeseriesTableWidgetConfigForm.get('title').enable(); + this.timeseriesTableWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); + if (showTitleIcon) { + this.timeseriesTableWidgetConfigForm.get('titleIcon').enable(); + this.timeseriesTableWidgetConfigForm.get('iconColor').enable(); + } else { + this.timeseriesTableWidgetConfigForm.get('titleIcon').disable(); + this.timeseriesTableWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.timeseriesTableWidgetConfigForm.get('title').disable(); + this.timeseriesTableWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); + this.timeseriesTableWidgetConfigForm.get('titleIcon').disable(); + this.timeseriesTableWidgetConfigForm.get('iconColor').disable(); + } + this.timeseriesTableWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.timeseriesTableWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); + this.timeseriesTableWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); + this.timeseriesTableWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); + } + + private getColumns(datasources?: Datasource[]): DataKey[] { + if (datasources && datasources.length) { + const dataKeys = deepClone(datasources[0].dataKeys) || []; + dataKeys.forEach(k => { + (k as any).latest = false; + }); + const latestDataKeys = deepClone(datasources[0].latestDataKeys) || []; + latestDataKeys.forEach(k => { + (k as any).latest = true; + }); + return dataKeys.concat(latestDataKeys); + } + return []; + } + + private setColumns(columns: DataKey[], datasources?: Datasource[]) { + if (datasources && datasources.length) { + const dataKeys = deepClone(columns.filter(c => !(c as any).latest)); + dataKeys.forEach(k => delete (k as any).latest); + const latestDataKeys = deepClone(columns.filter(c => (c as any).latest)); + latestDataKeys.forEach(k => delete (k as any).latest); + datasources[0].dataKeys = dataKeys; + datasources[0].latestDataKeys = latestDataKeys; + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.settings?.enableSearch) || config.settings?.enableSearch) { + buttons.push('search'); + } + if (isUndefined(config.settings?.enableSelectColumnDisplay) || config.settings?.enableSelectColumnDisplay) { + buttons.push('columnsToDisplay'); + } + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.settings.enableSearch = buttons.includes('search'); + config.settings.enableSelectColumnDisplay = buttons.includes('columnsToDisplay'); + config.enableFullscreen = buttons.includes('fullscreen'); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html index ee7adc3df2..7bfa1e59b1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html @@ -16,6 +16,12 @@ -->
+ + + {{ 'datakey.timeseries' | translate }} + {{ 'datakey.latest' | translate }} + + {}; constructor(private fb: UntypedFormBuilder, @@ -212,6 +229,12 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan units: [null, []], decimals: [null, []], }); + if (this.hasAdditionalLatestDataKeys) { + this.keyRowFormGroup.addControl('latest', this.fb.control(false)); + this.keyRowFormGroup.valueChanges.subscribe( + () => this.clearKeySearchCache() + ); + } this.keyRowFormGroup.valueChanges.subscribe( () => this.updateModel() ); @@ -286,6 +309,11 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan decimals: value?.decimals }, {emitEvent: false} ); + if (this.hasAdditionalLatestDataKeys) { + this.keyRowFormGroup.patchValue({ + latest: (value as any)?.latest + }, {emitEvent: false}); + } this.cd.markForCheck(); } @@ -323,8 +351,8 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan data: { dataKey: deepClone(this.modelValue), dataKeyConfigMode: advanced ? DataKeyConfigMode.advanced : DataKeyConfigMode.general, - dataKeySettingsSchema: this.datakeySettingsSchema, - dataKeySettingsDirective: this.dataKeySettingsDirective, + dataKeySettingsSchema: this.isLatestDataKeys ? this.latestDataKeySettingsSchema : this.dataKeySettingsSchema, + dataKeySettingsDirective: this.isLatestDataKeys ? this.latestDataKeySettingsDirective : this.dataKeySettingsDirective, dashboard: this.dashboard, aliasController: this.aliasController, widget: this.widget, @@ -399,7 +427,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan } else if (this.datasourceType === DatasourceType.entity && this.entityAliasId || this.datasourceType === DatasourceType.device && this.deviceId) { const dataKeyTypes = [DataKeyType.timeseries]; - if (this.widgetType === widgetType.latest || this.widgetType === widgetType.alarm) { + if (this.isLatestDataKeys || this.widgetType === widgetType.latest || this.widgetType === widgetType.alarm) { dataKeyTypes.push(DataKeyType.attribute); dataKeyTypes.push(DataKeyType.entityField); if (this.widgetType === widgetType.alarm) { @@ -428,7 +456,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan } private addKeyFromChipValue(chip: DataKey) { - this.modelValue = this.callbacks.generateDataKey(chip.name, chip.type, this.datakeySettingsSchema); + this.modelValue = this.callbacks.generateDataKey(chip.name, chip.type, this.dataKeySettingsSchema); if (!this.keyRowFormGroup.get('label').value) { this.keyRowFormGroup.get('label').patchValue(this.modelValue.label, {emitEvent: false}); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html index 6960e57ee1..23aab3c720 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html @@ -19,6 +19,7 @@
{{ panelTitle }}
+
datakey.source
datakey.key
datakey.label
datakey.color
@@ -52,6 +53,7 @@
+
+
- - - + + {{ 'widgets.table.use-cell-content-function' | translate }} - + widget-config.advanced-settings @@ -65,30 +95,5 @@ - - - widgets.table.default-column-visibility - - - {{ 'widgets.table.column-visibility-visible' | translate }} - - - {{ 'widgets.table.column-visibility-hidden' | translate }} - - - {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} - - - - - widgets.table.column-selection-to-display - - - {{ 'widgets.table.column-selection-to-display-enabled' | translate }} - - - {{ 'widgets.table.column-selection-to-display-disabled' | translate }} - - - - +
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html index 8fb1629b13..dcdc8c2904 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html @@ -15,25 +15,58 @@ limitations under the License. --> -
- - {{ 'widgets.table.show-latest-data-column' | translate }} - - - widgets.table.latest-data-column-order - - -
- widgets.table.cell-style + +
+
widgets.table.column-settings
+ + {{ 'widgets.table.show-latest-data-column' | translate }} + +
+
widgets.table.latest-data-column-order
+ + + +
+
+
{{ 'widgets.table.default-column-visibility' | translate }}
+ + + + {{ 'widgets.table.column-visibility-visible' | translate }} + + + {{ 'widgets.table.column-visibility-hidden' | translate }} + + + {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} + + + +
+
+
{{ 'widgets.table.column-selection-to-display' | translate }}
+ + + + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} + + + {{ 'widgets.table.column-selection-to-display-disabled' | translate }} + + + +
+
+
- - - + + {{ 'widgets.table.use-cell-style-function' | translate }} - + widget-config.advanced-settings @@ -47,18 +80,17 @@ -
-
- widgets.table.cell-content +
+
- - - + + {{ 'widgets.table.use-cell-content-function' | translate }} - + widget-config.advanced-settings @@ -72,30 +104,6 @@ - - - widgets.table.default-column-visibility - - - {{ 'widgets.table.column-visibility-visible' | translate }} - - - {{ 'widgets.table.column-visibility-hidden' | translate }} - - - {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} - - - - - widgets.table.column-selection-to-display - - - {{ 'widgets.table.column-selection-to-display-enabled' | translate }} - - - {{ 'widgets.table.column-selection-to-display-disabled' | translate }} - - - - +
+ + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index ed4428fe45..b2743142a4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -15,28 +15,31 @@ limitations under the License. --> -
-
- widgets.table.common-table-settings -
-
- - {{ 'widgets.table.enable-search' | translate }} - - - {{ 'widgets.table.enable-select-column-display' | translate }} - -
-
- - {{ 'widgets.table.enable-sticky-header' | translate }} - - - {{ 'widgets.table.enable-sticky-action' | translate }} - -
-
- + +
+
widgets.table.table-header
+ + {{ 'widgets.table.enable-sticky-header' | translate }} + + + {{ 'widgets.table.enable-search' | translate }} + + + {{ 'widgets.table.enable-select-column-display' | translate }} + +
+
+
widgets.table.columns
+ + {{ 'widgets.table.display-timestamp' | translate }} + + + {{ 'widgets.table.display-milliseconds' | translate }} + + + {{ 'widgets.table.enable-sticky-action' | translate }} + + widgets.table.hidden-cell-button-display-mode @@ -47,41 +50,39 @@ -
- - {{ 'widgets.table.display-timestamp' | translate }} - - - {{ 'widgets.table.display-milliseconds' | translate }} - -
- - {{ 'widgets.table.display-pagination' | translate }} - - - widgets.table.default-page-size - - -
- - {{ 'widgets.table.use-entity-label-tab-name' | translate }} - - - {{ 'widgets.table.hide-empty-lines' | translate }} - -
-
-
- widgets.table.row-style +
+
+
widgets.table.pagination
+ + {{ 'widgets.table.display-pagination' | translate }} + +
+
widgets.table.default-page-size
+ + + +
+
+
+
widgets.table.table-tabs
+ + {{ 'widgets.table.use-entity-label-tab-name' | translate }} + +
+
+
widgets.table.rows
+ + {{ 'widgets.table.hide-empty-lines' | translate }} + - - - + + {{ 'widgets.table.use-row-style-function' | translate }} - + widget-config.advanced-settings @@ -95,5 +96,5 @@ - - +
+ diff --git a/ui-ngx/src/app/shared/components/tb-error.component.ts b/ui-ngx/src/app/shared/components/tb-error.component.ts index 08959e2949..5ddd2d7896 100644 --- a/ui-ngx/src/app/shared/components/tb-error.component.ts +++ b/ui-ngx/src/app/shared/components/tb-error.component.ts @@ -16,11 +16,12 @@ import { Component, Input } from '@angular/core'; import { animate, state, style, transition, trigger } from '@angular/animations'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-error', template: ` -
+
{{message}} @@ -51,6 +52,10 @@ export class TbErrorComponent { state: any; message; + @Input() + @coerceBoolean() + noMargin = false; + @Input() set error(value) { if (value && !this.message) { 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 341408a615..3fca1fad78 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1188,7 +1188,9 @@ "delta-calculation-result": "Delta calculation result", "delta-calculation-result-previous-value": "Previous value", "delta-calculation-result-delta-absolute": "Delta (absolute)", - "delta-calculation-result-delta-percent": "Delta (percent)" + "delta-calculation-result-delta-percent": "Delta (percent)", + "source": "Source", + "latest": "Latest" }, "datasource": { "type": "Datasource type", @@ -5240,7 +5242,9 @@ "table-header": "Table header", "header-buttons": "Header buttons", "pagination": "Pagination", - "rows": "Rows" + "rows": "Rows", + "timeseries-column-error": "At least one timeseries column should be specified", + "table-tabs": "Table tabs" }, "value-source": { "value-source": "Value source", From 0d661ba6cc9326ee9a9008da2e537183d6f6d330 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 27 Jun 2023 18:53:34 +0300 Subject: [PATCH 170/421] UI: Timeseries table config improvement --- .../cards/timeseries-table-widget-settings.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index b2743142a4..5cbed7da88 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -69,8 +69,8 @@ {{ 'widgets.table.use-entity-label-tab-name' | translate }}
-
-
widgets.table.rows
+
+
widgets.table.rows
{{ 'widgets.table.hide-empty-lines' | translate }} From e3867486b5b7e6548b0751c1ecb97a6702d91984 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 28 Jun 2023 10:18:18 +0200 Subject: [PATCH 171/421] fixed update inactivity timeout attribute --- .../server/service/state/DefaultDeviceStateService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 554359fd6d..57765b613d 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -231,7 +231,6 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService Date: Wed, 28 Jun 2023 11:35:54 +0300 Subject: [PATCH 172/421] added cache for TBResourceInfo --- .../src/main/resources/thingsboard.yml | 3 ++ .../resourceinfo/ResourceInfoCacheKey.java | 45 +++++++++++++++++++ .../ResourceInfoCaffeineCache.java | 34 ++++++++++++++ .../resourceinfo/ResourceInfoEvictEvent.java | 23 ++++++++++ .../resourceinfo/ResourceInfoRedisCache.java | 35 +++++++++++++++ .../server/common/data/CacheConstants.java | 1 + .../dao/resource/BaseResourceService.java | 28 +++++++----- 7 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java create mode 100644 common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 81654e3033..ba49ae5b23 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -497,6 +497,9 @@ cache: entityCount: timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_COUNT_TTL:1440}" maxSize: "${CACHE_SPECS_ENTITY_COUNT_MAX_SIZE:100000}" + resourceInfo: + timeToLiveInMinutes: "${CACHE_SPECS_RESOURCE_INFO_TTL:1440}" + maxSize: "${CACHE_SPECS_USER_SETTINGS_MAX_SIZE:100000}" # deliberately placed outside 'specs' group above notificationRules: diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java new file mode 100644 index 0000000000..670866e54b --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache.resourceinfo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.TbResourceId; +import org.thingsboard.server.common.data.id.TenantId; + +import java.io.Serializable; +import java.util.UUID; + +@Getter +@EqualsAndHashCode +@RequiredArgsConstructor +@Builder +public class ResourceInfoCacheKey implements Serializable { + + private final TenantId tenantId; + private final TbResourceId tbResourceId; + + @Override + public String toString() { + return tenantId + "_" + tbResourceId; + } +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java new file mode 100644 index 0000000000..371f2012cc --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java @@ -0,0 +1,34 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache.resourceinfo; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CaffeineTbTransactionalCache; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.TbResourceInfo; + + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) +@Service("ResourceInfoCache") +public class ResourceInfoCaffeineCache extends CaffeineTbTransactionalCache { + + public ResourceInfoCaffeineCache(CacheManager cacheManager) { + super(cacheManager, CacheConstants.RESOURCE_INFO_CACHE); + } + +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java new file mode 100644 index 0000000000..002510b314 --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache.resourceinfo; + +import lombok.Data; + +@Data +public class ResourceInfoEvictEvent { + private final ResourceInfoCacheKey key; +} diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java new file mode 100644 index 0000000000..617367fb80 --- /dev/null +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java @@ -0,0 +1,35 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.cache.resourceinfo; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CacheSpecsMap; +import org.thingsboard.server.cache.RedisTbTransactionalCache; +import org.thingsboard.server.cache.TBRedisCacheConfiguration; +import org.thingsboard.server.cache.TbFSTRedisSerializer; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.TbResourceInfo; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") +@Service("ResourceInfoCache") +public class ResourceInfoRedisCache extends RedisTbTransactionalCache { + + public ResourceInfoRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { + super(CacheConstants.RESOURCE_INFO_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>()); + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java index ff0032f435..f21b13a674 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java @@ -44,4 +44,5 @@ public class CacheConstants { public static final String USER_SETTINGS_CACHE = "userSettings"; public static final String DASHBOARD_TITLES_CACHE = "dashboardTitles"; public static final String ENTITY_COUNT_CACHE = "entityCount"; + public static final String RESOURCE_INFO_CACHE = "resourceInfo"; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 974e3665f1..016b9c9d9a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -20,7 +20,10 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.stereotype.Service; +import org.springframework.transaction.event.TransactionalEventListener; +import org.thingsboard.server.cache.resourceinfo.ResourceInfoEvictEvent; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.cache.resourceinfo.ResourceInfoCacheKey; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResourceInfo; @@ -31,6 +34,7 @@ import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -45,7 +49,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; @Service("TbResourceDaoService") @Slf4j @AllArgsConstructor -public class BaseResourceService implements ResourceService { +public class BaseResourceService extends AbstractCachedEntityService implements ResourceService { public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId "; private final TbResourceDao resourceDao; @@ -55,10 +59,12 @@ public class BaseResourceService implements ResourceService { @Override public TbResource saveResource(TbResource resource) { resourceValidator.validate(resource, TbResourceInfo::getTenantId); - try { - return resourceDao.save(resource.getTenantId(), resource); + TbResource saved = resourceDao.save(resource.getTenantId(), resource); + publishEvictEvent(new ResourceInfoEvictEvent(new ResourceInfoCacheKey(resource.getTenantId(), resource.getId()))); + return saved; } catch (Exception t) { + publishEvictEvent(new ResourceInfoEvictEvent(new ResourceInfoCacheKey(resource.getTenantId(), resource.getId()))); ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("resource_unq_key")) { String field = ResourceType.LWM2M_MODEL.equals(resource.getResourceType()) ? "resourceKey" : "fileName"; @@ -86,7 +92,9 @@ public class BaseResourceService implements ResourceService { public TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId) { log.trace("Executing findResourceInfoById [{}] [{}]", tenantId, resourceId); Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId); - return resourceInfoDao.findById(tenantId, resourceId.getId()); + + return cache.getAndPutInTransaction(new ResourceInfoCacheKey(tenantId, resourceId), + () -> resourceInfoDao.findById(tenantId, resourceId.getId()), true); } @Override @@ -169,13 +177,9 @@ public class BaseResourceService implements ResourceService { } }; - protected Optional extractConstraintViolationException(Exception t) { - if (t instanceof ConstraintViolationException) { - return Optional.of((ConstraintViolationException) t); - } else if (t.getCause() instanceof ConstraintViolationException) { - return Optional.of((ConstraintViolationException) (t.getCause())); - } else { - return Optional.empty(); - } + @TransactionalEventListener(classes = ResourceInfoCacheKey.class) + @Override + public void handleEvictEvent(ResourceInfoEvictEvent event) { + cache.evict(event.getKey()); } } From 0c4c8353deccb765f1bf233576beff1887ac149a Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 28 Jun 2023 12:43:49 +0300 Subject: [PATCH 173/421] refactoring & added tests for alarm status filter node & entity and msg type switch nodes & check field presence --- .../actors/ruleChain/DefaultTbContext.java | 13 +- .../DefaultSystemDataLoaderService.java | 3 +- .../server/common/data/DataConstants.java | 1 + .../server/common/data/StringUtils.java | 2 +- .../AbstractGatewaySessionHandler.java | 2 +- .../external/TbAbstractExternalNode.java | 12 +- .../filter/TbAssetTypeSwitchNodeTest.java | 1 + .../filter/TbCheckAlarmStatusNodeTest.java | 3 +- .../engine/filter/TbCheckMessageNodeTest.java | 206 ++++++++++++++++++ .../filter/TbMsgTypeSwitchNodeTest.java | 97 +++++++++ .../TbOriginatorTypeSwitchNodeTest.java | 98 +++++++++ 11 files changed, 413 insertions(+), 25 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 2d087de74e..f9d1940714 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -852,17 +852,10 @@ class DefaultTbContext implements TbContext { } private static String getFailureMessage(Throwable th) { - String failureMessage; - if (th != null) { - if (!StringUtils.isEmpty(th.getMessage())) { - failureMessage = th.getMessage(); - } else { - failureMessage = th.getClass().getSimpleName(); - } - } else { - failureMessage = null; + if (th == null) { + return null; } - return failureMessage; + return StringUtils.isNotEmpty(th.getMessage()) ? th.getMessage() : th.getClass().getSimpleName(); } private class SimpleTbQueueCallback implements TbQueueCallback { diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 7965824274..1087990c4e 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -114,13 +114,14 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE; + @Service @Profile("install") @Slf4j public class DefaultSystemDataLoaderService implements SystemDataLoaderService { public static final String CUSTOMER_CRED = "customer"; - public static final String DEFAULT_DEVICE_TYPE = "default"; public static final String ACTIVITY_STATE = "active"; @Autowired diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java index 6e7341fa24..ed4431f445 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java @@ -65,6 +65,7 @@ public class DataConstants { public static final String PROVISION_KEY = "provisionDeviceKey"; public static final String PROVISION_SECRET = "provisionDeviceSecret"; + public static final String DEFAULT_DEVICE_TYPE = "default"; public static final String DEVICE_NAME = "deviceName"; public static final String DEVICE_TYPE = "deviceType"; public static final String CERT_PUB_KEY = "x509CertPubKey"; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java index a7671f4327..6b70dfc09c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java @@ -42,7 +42,7 @@ public class StringUtils { } public static boolean isNotEmpty(String source) { - return source != null && !source.isEmpty(); + return !isEmpty(source); } public static boolean isNotBlank(String source) { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java index 95603e751c..5cd6ba9145 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/AbstractGatewaySessionHandler.java @@ -71,6 +71,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import static org.springframework.util.ConcurrentReferenceHashMap.ReferenceType; +import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE; import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED; import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN; import static org.thingsboard.server.common.transport.service.DefaultTransportService.SUBSCRIBE_TO_ATTRIBUTE_UPDATES_ASYNC_MSG; @@ -85,7 +86,6 @@ import static org.thingsboard.server.transport.mqtt.util.sparkplug.SparkplugMess @Slf4j public abstract class AbstractGatewaySessionHandler { - protected static final String DEFAULT_DEVICE_TYPE = "default"; private static final String CAN_T_PARSE_VALUE = "Can't parse value: "; private static final String DEVICE_PROPERTY = "device"; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java index d9d25bc4cd..8402e87076 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java @@ -38,17 +38,9 @@ public abstract class TbAbstractExternalNode implements TbNode { protected void tellFailure(TbContext ctx, TbMsg tbMsg, Throwable t) { if (forceAck) { - if (t == null) { - ctx.enqueueForTellNext(tbMsg.copyWithNewCtx(), TbNodeConnectionType.FAILURE); - } else { - ctx.enqueueForTellFailure(tbMsg.copyWithNewCtx(), t); - } + ctx.enqueueForTellFailure(tbMsg.copyWithNewCtx(), t); } else { - if (t == null) { - ctx.tellNext(tbMsg, TbNodeConnectionType.FAILURE); - } else { - ctx.tellFailure(tbMsg, t); - } + ctx.tellFailure(tbMsg, t); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java index 3e4dd21fd2..7ef2f87845 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java @@ -124,4 +124,5 @@ class TbAssetTypeSwitchNodeTest { private TbMsg getTbMsg(EntityId entityId) { return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(), "{}", callback); } + } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java index 0677f0b0c9..4212af2ade 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java @@ -163,5 +163,4 @@ class TbCheckAlarmStatusNodeTest { return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(), msgData); } - -} \ No newline at end of file +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java new file mode 100644 index 0000000000..dd25363aed --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java @@ -0,0 +1,206 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.filter; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE; +import static org.thingsboard.server.common.data.DataConstants.DEVICE_NAME; +import static org.thingsboard.server.common.data.DataConstants.DEVICE_TYPE; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; + +class TbCheckMessageNodeTest { + + private static final DeviceId DEVICE_ID = new DeviceId(UUID.randomUUID()); + private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); + private static final String EMPTY_DATA = "{}"; + private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, EMPTY_METADATA, EMPTY_DATA); + + private static TbCheckMessageNode node; + + private static TbContext ctx; + + @BeforeEach + void setUp() { + ctx = mock(TbContext.class); + node = new TbCheckMessageNode(); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenDefaultConfig_whenOnMsg_then_True() throws TbNodeException { + // GIVEN + var configuration = new TbCheckMessageNodeConfiguration().defaultConfiguration(); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(configuration))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + + @Test + void givenCustomConfigWithoutCheckAllKeysAndWithEmptyLists_whenOnMsg_then_False() throws TbNodeException { + // GIVEN + var configuration = new TbCheckMessageNodeConfiguration().defaultConfiguration(); + configuration.setCheckAllKeys(false); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(configuration))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + + @Test + void givenCustomConfigWithCheckAllKeys_whenOnMsg_then_True() throws TbNodeException { + // GIVEN + var configuration = new TbCheckMessageNodeConfiguration().defaultConfiguration(); + configuration.setMessageNames(List.of("temperature-0")); + configuration.setMetadataNames(List.of("deviceName", "deviceType", "ts")); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(configuration))); + + TbMsg tbMsg = getTbMsg(); + + // WHEN + node.onMsg(ctx, tbMsg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(tbMsg); + } + + @Test + void givenCustomConfigWithCheckAllKeys_whenOnMsg_then_False() throws TbNodeException { + // GIVEN + var configuration = new TbCheckMessageNodeConfiguration().defaultConfiguration(); + configuration.setMessageNames(List.of("temperature-0", "temperature-1")); + configuration.setMetadataNames(List.of("deviceName", "deviceType", "ts")); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(configuration))); + + TbMsg tbMsg = getTbMsg(); + + // WHEN + node.onMsg(ctx, tbMsg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(tbMsg); + } + + @Test + void givenCustomConfigWithoutCheckAllKeys_whenOnMsg_then_True() throws TbNodeException { + // GIVEN + var configuration = new TbCheckMessageNodeConfiguration().defaultConfiguration(); + configuration.setMessageNames(List.of("temperature-0", "temperature-1")); + configuration.setCheckAllKeys(false); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(configuration))); + + TbMsg tbMsg = getTbMsg(); + + // WHEN + node.onMsg(ctx, tbMsg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(tbMsg); + } + + @Test + void givenCustomConfigWithoutCheckAllKeysAndEmptyMsg_whenOnMsg_then_False() throws TbNodeException { + // GIVEN + var configuration = new TbCheckMessageNodeConfiguration().defaultConfiguration(); + configuration.setMessageNames(List.of("temperature-0", "temperature-1")); + configuration.setCheckAllKeys(false); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(configuration))); + + TbMsg tbMsg = getTbMsg(true); + + // WHEN + node.onMsg(ctx, tbMsg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(tbMsg); + } + + private TbMsg getTbMsg() { + return getTbMsg(false); + } + + private TbMsg getTbMsg(boolean emptyData) { + String data = emptyData ? EMPTY_DATA : "{\"temperature-0\": 25}"; + var metadata = new TbMsgMetaData(); + metadata.putValue(DEVICE_NAME, "Test Device"); + metadata.putValue(DEVICE_TYPE, DEFAULT_DEVICE_TYPE); + metadata.putValue("ts", String.valueOf(System.currentTimeMillis())); + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, metadata, data); + } + +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java new file mode 100644 index 0000000000..51155688e6 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java @@ -0,0 +1,97 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.filter; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +class TbMsgTypeSwitchNodeTest { + + private static final DeviceId DEVICE_ID = new DeviceId(UUID.randomUUID()); + private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); + private static final String EMPTY_DATA = "{}"; + + private static TbMsgTypeSwitchNode node; + + private static TbContext ctx; + + @BeforeEach + void setUp() { + ctx = mock(TbContext.class); + node = new TbMsgTypeSwitchNode(); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenAllTypes_whenOnMsg_then_allTypesSupported() throws TbNodeException { + // GIVEN + List tbMsgList = new ArrayList<>(); + var tbMsgTypes = TbMsgType.values(); + for (var msgType : tbMsgTypes) { + tbMsgList.add(getTbMsg(msgType)); + } + + // WHEN + for (TbMsg tbMsg : tbMsgList) { + node.onMsg(ctx, tbMsg); + } + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + ArgumentCaptor nodeConnectionCapture = ArgumentCaptor.forClass(String.class); + verify(ctx, times(tbMsgList.size())).tellNext(newMsgCaptor.capture(), nodeConnectionCapture.capture()); + verify(ctx, never()).tellFailure(any(), any()); + var resultMsgs = newMsgCaptor.getAllValues(); + var resultNodeConnections = nodeConnectionCapture.getAllValues(); + for (int i = 0; i < resultMsgs.size(); i++) { + var msg = resultMsgs.get(i); + assertThat(msg).isNotNull(); + assertThat(msg.getType()).isNotNull(); + assertThat(msg).isSameAs(tbMsgList.get(i)); + // todo add additional validation that types like ALARM or PROVISION returns OTHER for backward-compatibility. + assertThat(resultNodeConnections.get(i)) + .isEqualTo(TbMsgType.getRuleNodeConnection(msg.getType())); + } + } + + private TbMsg getTbMsg(TbMsgType msgType) { + return TbMsg.newMsg(msgType.name(), DEVICE_ID, EMPTY_METADATA, EMPTY_DATA); + } + +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java new file mode 100644 index 0000000000..09e67e45ef --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java @@ -0,0 +1,98 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.filter; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; + +class TbOriginatorTypeSwitchNodeTest { + + private static final UUID RANDOM_UUID = UUID.randomUUID(); + private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); + private static final String EMPTY_DATA = "{}"; + + private static TbOriginatorTypeSwitchNode node; + + private static TbContext ctx; + + @BeforeEach + void setUp() { + ctx = mock(TbContext.class); + node = new TbOriginatorTypeSwitchNode(); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenAllTypes_whenOnMsg_then_allTypesSupported() throws TbNodeException { + // GIVEN + List tbMsgList = new ArrayList<>(); + var entityTypes = EntityType.values(); + for (var entityType : entityTypes) { + var entityId = EntityIdFactory.getByTypeAndUuid(entityType, RANDOM_UUID); + tbMsgList.add(getTbMsg(entityId)); + } + + // WHEN + for (TbMsg tbMsg : tbMsgList) { + node.onMsg(ctx, tbMsg); + } + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + ArgumentCaptor nodeConnectionCapture = ArgumentCaptor.forClass(String.class); + verify(ctx, times(tbMsgList.size())).tellNext(newMsgCaptor.capture(), nodeConnectionCapture.capture()); + verify(ctx, never()).tellFailure(any(), any()); + var resultMsgs = newMsgCaptor.getAllValues(); + var resultNodeConnections = nodeConnectionCapture.getAllValues(); + for (int i = 0; i < resultMsgs.size(); i++) { + var msg = resultMsgs.get(i); + assertThat(msg).isNotNull(); + assertThat(msg).isSameAs(tbMsgList.get(i)); + assertThat(resultNodeConnections.get(i)) + .isEqualTo(msg.getOriginator().getEntityType().getNormalName()); + } + } + + private TbMsg getTbMsg(EntityId entityId) { + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, EMPTY_METADATA, EMPTY_DATA); + } + +} From 27b1d3f5d56a84ac1c90fd59004eba49c96a6459 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 28 Jun 2023 12:49:17 +0300 Subject: [PATCH 174/421] fix typo in NashornJsInvokeServiceTest --- .../server/service/script/NashornJsInvokeServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java b/application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java index 8d7de23303..5cd54a24eb 100644 --- a/application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/script/NashornJsInvokeServiceTest.java @@ -122,7 +122,7 @@ class NashornJsInvokeServiceTest extends AbstractControllerTest { } private String invokeScript(UUID scriptId, String msg) throws ExecutionException, InterruptedException { - return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.getRuleNodeConnection()).get().toString(); + return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get().toString(); } } From f01b2d6595dbf997da1cf4b4004560481fec19a3 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 28 Jun 2023 12:59:27 +0300 Subject: [PATCH 175/421] fix typo in TbelInvokeServiceTest --- .../server/service/script/TbelInvokeServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java index 2895c97c90..62af9cb16e 100644 --- a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java @@ -217,7 +217,7 @@ class TbelInvokeServiceTest extends AbstractControllerTest { private String invokeScript(UUID scriptId, String str) throws ExecutionException, InterruptedException { var msg = JacksonUtil.fromString(str, Map.class); - return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.getRuleNodeConnection()).get().toString(); + return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get().toString(); } } From e2ba34bbf33a70d6b3307a7284e9c5890da711f3 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 28 Jun 2023 13:48:46 +0300 Subject: [PATCH 176/421] refactoring --- application/src/main/resources/thingsboard.yml | 2 +- .../ResourceInfoCacheKey.java | 7 +------ .../ResourceInfoCaffeineCache.java | 2 +- .../ResourceInfoEvictEvent.java | 7 +++++-- .../ResourceInfoRedisCache.java | 2 +- .../server/dao/resource/BaseResourceService.java | 15 +++++++++------ 6 files changed, 18 insertions(+), 17 deletions(-) rename common/cache/src/main/java/org/thingsboard/server/cache/{resourceinfo => resourceInfo}/ResourceInfoCacheKey.java (84%) rename common/cache/src/main/java/org/thingsboard/server/cache/{resourceinfo => resourceInfo}/ResourceInfoCaffeineCache.java (96%) rename common/cache/src/main/java/org/thingsboard/server/cache/{resourceinfo => resourceInfo}/ResourceInfoEvictEvent.java (73%) rename common/cache/src/main/java/org/thingsboard/server/cache/{resourceinfo => resourceInfo}/ResourceInfoRedisCache.java (97%) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index ba49ae5b23..c8dfd1b029 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -499,7 +499,7 @@ cache: maxSize: "${CACHE_SPECS_ENTITY_COUNT_MAX_SIZE:100000}" resourceInfo: timeToLiveInMinutes: "${CACHE_SPECS_RESOURCE_INFO_TTL:1440}" - maxSize: "${CACHE_SPECS_USER_SETTINGS_MAX_SIZE:100000}" + maxSize: "${CACHE_SPECS_RESOURCE_INFO_MAX_SIZE:100000}" # deliberately placed outside 'specs' group above notificationRules: diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCacheKey.java similarity index 84% rename from common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java rename to common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCacheKey.java index 670866e54b..9db53f86c6 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCacheKey.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCacheKey.java @@ -13,21 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.cache.resourceinfo; +package org.thingsboard.server.cache.resourceInfo; -import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; -import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import java.io.Serializable; -import java.util.UUID; @Getter @EqualsAndHashCode diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCaffeineCache.java similarity index 96% rename from common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java rename to common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCaffeineCache.java index 371f2012cc..95754d891a 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoCaffeineCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoCaffeineCache.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.cache.resourceinfo; +package org.thingsboard.server.cache.resourceInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.CacheManager; diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoEvictEvent.java similarity index 73% rename from common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java rename to common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoEvictEvent.java index 002510b314..11272a5e24 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoEvictEvent.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoEvictEvent.java @@ -13,11 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.cache.resourceinfo; +package org.thingsboard.server.cache.resourceInfo; import lombok.Data; +import org.thingsboard.server.common.data.id.TbResourceId; +import org.thingsboard.server.common.data.id.TenantId; @Data public class ResourceInfoEvictEvent { - private final ResourceInfoCacheKey key; + private final TenantId tenantId; + private final TbResourceId resourceId; } diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoRedisCache.java similarity index 97% rename from common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java rename to common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoRedisCache.java index 617367fb80..fee14e1ca1 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/resourceinfo/ResourceInfoRedisCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/resourceInfo/ResourceInfoRedisCache.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.cache.resourceinfo; +package org.thingsboard.server.cache.resourceInfo; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.data.redis.connection.RedisConnectionFactory; diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 016b9c9d9a..bc4f47040b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -21,9 +21,10 @@ import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.event.TransactionalEventListener; -import org.thingsboard.server.cache.resourceinfo.ResourceInfoEvictEvent; +import org.thingsboard.server.cache.device.DeviceCacheKey; +import org.thingsboard.server.cache.resourceInfo.ResourceInfoEvictEvent; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.cache.resourceinfo.ResourceInfoCacheKey; +import org.thingsboard.server.cache.resourceInfo.ResourceInfoCacheKey; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResourceInfo; @@ -61,10 +62,10 @@ public class BaseResourceService extends AbstractCachedEntityService Date: Wed, 28 Jun 2023 14:50:17 +0300 Subject: [PATCH 177/421] added cache config properties --- dao/src/test/resources/application-test.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties index d89211cb2f..98f9091318 100644 --- a/dao/src/test/resources/application-test.properties +++ b/dao/src/test/resources/application-test.properties @@ -74,6 +74,9 @@ cache.specs.dashboardTitles.maxSize=10000 cache.specs.entityCount.timeToLiveInMinutes=1440 cache.specs.entityCount.maxSize=10000 +cache.specs.resourceInfo.timeToLiveInMinutes=1440 +cache.specs.resourceInfo.maxSize=10000 + redis.connection.host=localhost redis.connection.port=6379 redis.connection.db=0 From aa814b86286998b4ac10c7cf77b980c66d70c2c9 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 28 Jun 2023 22:33:03 +0200 Subject: [PATCH 178/421] added corresponding tests --- .../state/DefaultDeviceStateServiceTest.java | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index 52f2ec5c9d..5a69702405 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -22,20 +22,33 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceIdInfo; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.TsValue; +import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; +import org.thingsboard.server.common.msg.queue.ServiceType; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.sql.query.EntityQueryRepository; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.service.partition.AbstractPartitionBasedService; +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import static org.hamcrest.CoreMatchers.is; @@ -62,6 +75,8 @@ public class DefaultDeviceStateServiceTest { PartitionService partitionService; @Mock DeviceStateData deviceStateDataMock; + @Mock + EntityQueryRepository entityQueryRepository; DeviceId deviceId = DeviceId.fromString("00797a3b-7aeb-4b5b-b57a-c2a810d0f112"); @@ -69,7 +84,7 @@ public class DefaultDeviceStateServiceTest { @Before public void setUp() { - service = spy(new DefaultDeviceStateService(deviceService, attributesService, tsService, clusterService, partitionService, null, null, null, mock(NotificationRuleProcessor.class))); + service = spy(new DefaultDeviceStateService(deviceService, attributesService, tsService, clusterService, partitionService, entityQueryRepository, null, null, mock(NotificationRuleProcessor.class))); } @Test @@ -125,4 +140,56 @@ public class DefaultDeviceStateServiceTest { Assert.assertEquals(5000L, deviceStateData.getState().getInactivityTimeout()); } + @Test + public void givenUpdateInactivityTimeoutAndThenNoStateChange() throws Exception { + TelemetrySubscriptionService telemetrySubscriptionService = Mockito.mock(TelemetrySubscriptionService.class); + ReflectionTestUtils.setField(service, "tsSubService", telemetrySubscriptionService); + ReflectionTestUtils.setField(service, "defaultStateCheckIntervalInSec", 60); + ReflectionTestUtils.setField(service, "defaultActivityStatsIntervalInSec", 60); + ReflectionTestUtils.setField(service, "defaultInactivityTimeoutMs", 60000); + ReflectionTestUtils.setField(service, "initFetchPackSize", 10); + + Mockito.when(entityQueryRepository.findEntityDataByQueryInternal(Mockito.any())).thenReturn(new PageData<>()); + + service.init(); + var tenantId = new TenantId(UUID.randomUUID()); + var tpi = TopicPartitionInfo.builder().myPartition(true).build(); + Mockito.when(partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId)).thenReturn(tpi); + + var deviceIdInfo = new DeviceIdInfo(tenantId.getId(), null, deviceId.getId()); + + Mockito.when(deviceService.findDeviceIdInfos(Mockito.any())) + .thenReturn(new PageData<>(List.of(deviceIdInfo), 0, 1, false)); + + Method method = AbstractPartitionBasedService.class.getDeclaredMethod("initStateFromDB", Set.class); + method.setAccessible(true); + method.invoke(service, Collections.singleton(tpi)); + + service.onAddedPartitions(Collections.singleton(tpi)); + + DeviceState deviceState = DeviceState.builder().build(); + + DeviceStateData deviceStateData = DeviceStateData.builder() + .tenantId(tenantId) + .deviceId(deviceId) + .state(deviceState) + .metaData(new TbMsgMetaData()) + .build(); + + service.deviceStates.put(deviceId, deviceStateData); + + service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); + + Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + + Mockito.reset(telemetrySubscriptionService); + + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, 1); + + Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(false), Mockito.any()); + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, 60000); + + Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + } + } \ No newline at end of file From 66ec7e523fa2b7d74816bcfe332047129bbd7140 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 29 Jun 2023 18:33:51 +0300 Subject: [PATCH 179/421] swagger_device_controller: refactoring device credentials with 4 mode security --- .../controller/ControllerConstants.java | 151 ++++++++++++++---- .../server/controller/DeviceController.java | 29 +++- 2 files changed, 148 insertions(+), 32 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index 7701a19f02..a6a49f6b3c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -223,6 +223,19 @@ public class ControllerConstants { " }\n" + "}"; + protected static final String DEVICE_UPDATE_CREDENTIALS_ACCESS_TOKEN_PARAM_DESCRIPTION = + "{\n" + + " \"id\": {\n" + + " \"id\":\"c886a090-168d-11ee-87c9-6f157dbc816a\"\n" + + " },\n" + + " \"deviceId\": {\n" + + " \"id\":\"c5fb3ac0-168d-11ee-87c9-6f157dbc816a\",\n" + + " \"entityType\":\"DEVICE\"\n" + + " },\n" + + " \"credentialsType\": \"ACCESS_TOKEN\",\n" + + " \"credentialsId\": \"6hmxew8pmmzng4e3une4\"\n" + + "}"; + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_ACCESS_TOKEN_DEFAULT_PARAM_DESCRIPTION = "{\n" + " \"device\": {\n" + @@ -242,40 +255,75 @@ public class ControllerConstants { protected static final String certificateId = "\"84f5911765abba1f96bf4165604e9e90338fc6214081a8e623b6ff9669aedb27\""; + protected static final String certificateValueUpdate = "\"-----BEGIN CERTIFICATE----- " + + "MIICMTCCAdegAwIBAgIUUEKxS9hTz4l+oLUMF0LV6TC/gCIwCgYIKoZIzj0EAwIwbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlUHJvZmlsZUNlcnRAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MB4XDTIzMDMyOTE0NTczNloXDTI0MDMyODE0NTczNlowbjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRowGAYDVQQKDBFUaGluZ3NCb2FyZCwgSW5jLjEwMC4GA1UEAwwnZGV2aWNlUHJvZmlsZUNlcnRAWDUwOVByb3Zpc2lvblN0cmF0ZWd5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECMlWO72krDoUL9FQjUmSCetkhaEGJUfQkdSfkLSNa0GyAEIMbfmzI4zITeapunu4rGet3EMyLydQzuQanBicp6NTMFEwHQYDVR0OBBYEFHpZ78tPnztNii4Da/yCw6mhEIL3MB8GA1UdIwQYMBaAFHpZ78tPnztNii4Da/yCw6mhEIL3MA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgJ7qyMFqNcwSYkH6o+UlQXzLWfwZbNjVk+aR7foAZNGsCIQDsd7v3WQIGHiArfZeDs1DLEDuV/2h6L+ZNoGNhEKL+1A== " + + "-----END CERTIFICATE-----\""; + + protected static final String certificateIdUpdate = "\"6b8adb49015500e51a527acd332b51684ab9b49b4ade03a9582a44c455e2e9b6\""; + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_X509_CERTIFICATE_PARAM_DESCRIPTION = "{\n" + - " \"device\": {\n" + - " \"name\":\"Name_DeviceWithCredantial_X509_Certificate\",\n" + - " \"label\":\"Label_DeviceWithCredantial_X509_Certificate\",\n" + - " \"deviceProfileId\":{\n" + - " \"id\":\"9d9588c0-06c9-11ee-b618-19be30fdeb60\",\n" + - " \"entityType\":\"DEVICE_PROFILE\"\n" + - " }\n" + - " },\n" + - " \"credentials\": {\n" + - " \"credentialsType\": \"X509_CERTIFICATE\",\n" + - " \"credentialsId\": " + certificateId + ",\n" + - " \"credentialsValue\": " + certificateValue + "\n" + - " }\n" + - "}"; + " \"device\": {\n" + + " \"name\":\"Name_DeviceWithCredantial_X509_Certificate\",\n" + + " \"label\":\"Label_DeviceWithCredantial_X509_Certificate\",\n" + + " \"deviceProfileId\":{\n" + + " \"id\":\"9d9588c0-06c9-11ee-b618-19be30fdeb60\",\n" + + " \"entityType\":\"DEVICE_PROFILE\"\n" + + " }\n" + + " },\n" + + " \"credentials\": {\n" + + " \"credentialsType\": \"X509_CERTIFICATE\",\n" + + " \"credentialsId\": " + certificateId + ",\n" + + " \"credentialsValue\": " + certificateValue + "\n" + + " }\n" + + "}"; + + protected static final String DEVICE_UPDATE_CREDENTIALS_X509_CERTIFICATE_PARAM_DESCRIPTION = + "{\n" + + " \"id\": {\n" + + " \"id\":\"309bd9c0-14f4-11ee-9fc9-d9b7463abb63\"\n" + + " },\n" + + " \"deviceId\": {\n" + + " \"id\":\"3092b200-14f4-11ee-9fc9-d9b7463abb63\",\n" + + " \"entityType\":\"DEVICE\"\n" + + " },\n" + + " \"credentialsType\": \"X509_CERTIFICATE\",\n" + + " \"credentialsId\": " + certificateIdUpdate + ",\n" + + " \"credentialsValue\": " + certificateValueUpdate + "\n" + + "}"; protected static final String MQTT_BASIC_VALUE = "\"{\\\"clientId\\\":\\\"5euh5nzm34bjjh1efmlt\\\",\\\"userName\\\":\\\"onasd1lgwasmjl7v2v7h\\\",\\\"password\\\":\\\"b9xtm4ny8kt9zewaga5o\\\"}\""; + protected static final String MQTT_BASIC_VALUE_UPDATE = "\"{\\\"clientId\\\":\\\"juy03yv4owqxcmqhqtvk\\\",\\\"userName\\\":\\\"ov19fxca0cyjn7lm7w7u\\\",\\\"password\\\":\\\"twy94he114dfi9usyk1o\\\"}\""; + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_MQTT_BASIC_PARAM_DESCRIPTION = "{\n" + - " \"device\": {\n" + - " \"name\":\"Name_DeviceWithCredantial_MQTT_Basic\",\n" + - " \"label\":\"Label_DeviceWithCredantial_MQTT_Basic\",\n" + - " \"deviceProfileId\":{\n" + - " \"id\":\"9d9588c0-06c9-11ee-b618-19be30fdeb60\",\n" + - " \"entityType\":\"DEVICE_PROFILE\"\n" + - " }\n" + - " },\n" + - " \"credentials\": {\n" + - " \"credentialsType\": \"MQTT_BASIC\",\n" + - " \"credentialsValue\": " + MQTT_BASIC_VALUE + "\n" + - " }\n" + - "}"; + " \"device\": {\n" + + " \"name\":\"Name_DeviceWithCredantial_MQTT_Basic\",\n" + + " \"label\":\"Label_DeviceWithCredantial_MQTT_Basic\",\n" + + " \"deviceProfileId\":{\n" + + " \"id\":\"9d9588c0-06c9-11ee-b618-19be30fdeb60\",\n" + + " \"entityType\":\"DEVICE_PROFILE\"\n" + + " }\n" + + " },\n" + + " \"credentials\": {\n" + + " \"credentialsType\": \"MQTT_BASIC\",\n" + + " \"credentialsValue\": " + MQTT_BASIC_VALUE + "\n" + + " }\n" + + "}"; + + protected static final String DEVICE_UPDATE_CREDENTIALS_MQTT_BASIC_PARAM_DESCRIPTION = + "{\n" + + " \"id\": {\n" + + " \"id\":\"d877ffb0-14f5-11ee-9fc9-d9b7463abb63\"\n" + + " },\n" + + " \"deviceId\": {\n" + + " \"id\":\"d875dcd0-14f5-11ee-9fc9-d9b7463abb63\",\n" + + " \"entityType\":\"DEVICE\"\n" + + " },\n" + + " \"credentialsType\": \"MQTT_BASIC\",\n" + + " \"credentialsValue\": " + MQTT_BASIC_VALUE_UPDATE + "\n" + + "}"; protected static final String CREDENTIALS_VALUE_LVM2M_RPK_DESCRIPTION = " \"{" + @@ -297,6 +345,26 @@ public class ControllerConstants { "} " + "}\""; + protected static final String CREDENTIALS_VALUE_UPDATE_LVM2M_RPK_DESCRIPTION = + " \"{" + + "\\\"client\\\":{ " + + "\\\"endpoint\\\":\\\"LwRpk00000000\\\", " + + "\\\"securityConfigClientMode\\\":\\\"RPK\\\", " + + "\\\"key\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdvBZZ2vQRK9wgDhctj6B1c7bxR3Z0wYg1+YdoYFnVUKWb+rIfTTyYK9tmQJx5Vlb5fxdLnVv1RJOPiwsLIQbAA==\\\"" + + " }, " + + "\\\"bootstrap\\\":{ " + + "\\\"bootstrapServer\\\":{ " + + "\\\"securityMode\\\":\\\"RPK\\\", " + + "\\\"clientPublicKeyOrId\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\\\", " + + "\\\"clientSecretKey\\\":\\\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\\\"" + + "}, " + + "\\\"lwm2mServer\\\":{ \\\"securityMode\\\":\\\"RPK\\\", " + + "\\\"clientPublicKeyOrId\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUEBxNl/RcYJNm8mk91CyVXoIJiROYDlXcSSqK6e5bDHwOW4ZiN2lNnXalyF0Jxw8MbAytnDMERXyAja5VEMeVQ==\\\", " + + "\\\"clientSecretKey\\\":\\\"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgd9GAx7yZW37autew5KZykn4IgRpge/tZSjnudnZJnMahRANCAARQQHE2X9Fxgk2byaT3ULJVeggmJE5gOVdxJKorp7lsMfA5bhmI3aU2ddqXIXQnHDwxsDK2cMwRFfICNrlUQx5V\\\"" + + "}" + + "} " + + "}\""; + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION = "{\n" + " \"device\": {\n" + @@ -314,6 +382,20 @@ public class ControllerConstants { " }\n" + "}"; + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION = + "{\n" + + " \"id\": {\n" + + " \"id\":\"e238d4d0-1689-11ee-98c6-1713c1be5a8e\"\n" + + " },\n" + + " \"deviceId\": {\n" + + " \"id\":\"e232e160-1689-11ee-98c6-1713c1be5a8e\",\n" + + " \"entityType\":\"DEVICE\"\n" + + " },\n" + + " \"credentialsType\": \"LWM2M_CREDENTIALS\",\n" + + " \"credentialsId\": \"LwRpk00000000\",\n" + + " \"credentialsValue\":\n" + CREDENTIALS_VALUE_UPDATE_LVM2M_RPK_DESCRIPTION + "\n" + + "}"; + protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN = MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_ACCESS_TOKEN_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; @@ -329,8 +411,21 @@ public class ControllerConstants { protected static final String DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN = MARKDOWN_CODE_BLOCK_START + DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_UPDATE_CREDENTIALS_ACCESS_TOKEN_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_UPDATE_CREDENTIALS_X509_CERTIFICATE_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_UPDATE_CREDENTIALS_MQTT_BASIC_PARAM_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + protected static final String DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN = + MARKDOWN_CODE_BLOCK_START + DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION + MARKDOWN_CODE_BLOCK_END; + + - protected static final String FILTER_VALUE_TYPE = NEW_LINE + "## Value Type and Operations" + NEW_LINE + + protected static final String FILTER_VALUE_TYPE = NEW_LINE + "## Value Type and Operations" + NEW_LINE + "Provides a hint about the data type of the entity field that is defined in the filter key. " + "The value type impacts the list of possible operations that you may use in the corresponding predicate. For example, you may use 'STARTS_WITH' or 'END_WITH', but you can't use 'GREATER_OR_EQUAL' for string values." + "The following filter value types and corresponding predicate operations are supported: " + NEW_LINE + diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index f033b2758f..8be76856a4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -93,6 +93,10 @@ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFI import static org.thingsboard.server.controller.ControllerConstants.DEVICE_SORT_PROPERTY_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TEXT_SEARCH_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_TYPE_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DEFAULT_DESCRIPTION_MARKDOWN; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_WITH_DEVICE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN; @@ -292,10 +296,27 @@ public class DeviceController extends BaseController { return tbDeviceService.getDeviceCredentialsByDeviceId(device, getCurrentUser()); } - @ApiOperation(value = "Update device credentials (updateDeviceCredentials)", notes = "During device creation, platform generates random 'ACCESS_TOKEN' credentials. " + - "Use this method to update the device credentials. First use 'getDeviceCredentialsByDeviceId' to get the credentials id and value. " + - "Then use current method to update the credentials type and value. It is not possible to create multiple device credentials for the same device. " + - "The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'." + TENANT_AUTHORITY_PARAGRAPH) + @ApiOperation(value = "Update device credentials (updateDeviceCredentials)", + notes = "During device creation, platform generates random 'ACCESS_TOKEN' credentials. \" +\n" + + "Use this method to update the device credentials. First use 'getDeviceCredentialsByDeviceId' to get the credentials id and value.\n" + + "Then use current method to update the credentials type and value. It is not possible to create multiple device credentials for the same device.\n" + + "The structure of device credentials id and value is simple for the 'ACCESS_TOKEN' but is much more complex for the 'MQTT_BASIC' or 'LWM2M_CREDENTIALS'.\n" + + "You may find the example of device with different type of credentials below: \n\n" + + "- Credentials type: \"Access token\" with device ID and with device ID below: \n\n" + + DEVICE_UPDATE_CREDENTIALS_PARAM_ACCESS_TOKEN_DESCRIPTION_MARKDOWN + "\n\n" + + "- Credentials type: \"X509\" with device profile ID below: \n\n" + + "Note: credentialsId - format Sha3Hash, certificateValue - format PEM (with \"--BEGIN CERTIFICATE----\" and -\"----END CERTIFICATE-\").\n\n" + + DEVICE_UPDATE_CREDENTIALS_PARAM_X509_CERTIFICATE_DESCRIPTION_MARKDOWN + "\n\n" + + "- Credentials type: \"MQTT_BASIC\" with device profile ID below: \n\n" + + DEVICE_UPDATE_CREDENTIALS_PARAM_MQTT_BASIC_DESCRIPTION_MARKDOWN + "\n\n" + + "- You may find the example of LwM2M device and RPK credentials below: \n\n" + + "Note: LwM2M device - only existing device profile ID (Transport configuration -> Transport type: \"LWM2M\".\n\n" + + DEVICE_UPDATE_CREDENTIALS_PARAM_LVM2M_RPK_DESCRIPTION_MARKDOWN + "\n\n" + + "Update to real value:\n" + + " - 'id' (this is id of Device Credentials -> \"Get Device Credentials (getDeviceCredentialsByDeviceId)\",\n" + + " - 'deviceId.id' (this is id of Device).\n" + + "Remove 'tenantId' and optionally 'customerId' from the request body example (below) to create new Device entity." + + TENANT_AUTHORITY_PARAGRAPH) @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/device/credentials", method = RequestMethod.POST) @ResponseBody From 8beb81cf8d5ff1d7fe652c3bd1bcb61a6c61402c Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 30 Jun 2023 13:35:03 +0300 Subject: [PATCH 180/421] added tests for check relation presence node & test for TbMsgType and ActionType & refactoring --- .../device/DeviceProvisionServiceImpl.java | 2 +- .../processor/device/DeviceEdgeProcessor.java | 3 +- .../server/common/data/msg/TbMsgType.java | 4 +- .../common/data/audit/ActionTypeTest.java | 63 ++++ .../server/common/data/msg/TbMsgTypeTest.java | 70 +++++ .../engine/filter/TbCheckRelationNode.java | 10 +- .../engine/filter/TbMsgTypeSwitchNode.java | 2 +- .../filter/TbAssetTypeSwitchNodeTest.java | 27 +- .../filter/TbCheckAlarmStatusNodeTest.java | 20 +- .../engine/filter/TbCheckMessageNodeTest.java | 4 +- .../filter/TbCheckRelationNodeTest.java | 297 ++++++++++++++++++ .../filter/TbDeviceTypeSwitchNodeTest.java | 22 +- .../engine/filter/TbJsFilterNodeTest.java | 4 +- .../engine/filter/TbJsSwitchNodeTest.java | 4 +- .../filter/TbMsgTypeSwitchNodeTest.java | 7 +- .../TbOriginatorTypeSwitchNodeTest.java | 4 +- .../TbGetCustomerAttributeNodeTest.java | 6 +- .../TbGetCustomerDetailsNodeTest.java | 2 +- .../TbGetOriginatorFieldsNodeTest.java | 8 +- .../TbGetRelatedAttributeNodeTest.java | 2 +- .../TbGetTenantAttributeNodeTest.java | 4 +- .../metadata/TbGetTenantDetailsNodeTest.java | 2 +- 22 files changed, 498 insertions(+), 69 deletions(-) create mode 100644 common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java create mode 100644 common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java index 3bed8a1905..d5614c2193 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java @@ -273,7 +273,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { TbMsg msg = TbMsg.newMsg(ENTITY_CREATED.name(), device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); sendToRuleEngine(device.getTenantId(), msg, null); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), ENTITY_CREATED, e); + log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), ENTITY_CREATED.name(), e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java index 3848828522..49f2e0ead2 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java @@ -63,6 +63,7 @@ import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg; import java.util.UUID; import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED; +import static org.thingsboard.server.common.data.msg.TbMsgType.TO_SERVER_RPC_REQUEST; @Component @Slf4j @@ -218,7 +219,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { ObjectNode data = JacksonUtil.newObjectNode(); data.put("method", deviceRpcCallMsg.getRequestMsg().getMethod()); data.put("params", deviceRpcCallMsg.getRequestMsg().getParams()); - TbMsg tbMsg = TbMsg.newMsg(TbMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, null, metaData, + TbMsg tbMsg = TbMsg.newMsg(TO_SERVER_RPC_REQUEST.name(), deviceId, null, metaData, TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(data)); tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java index a974d8adbd..1872fd676f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java @@ -42,7 +42,7 @@ public enum TbMsgType { ALARM(null), ALARM_ACK("Alarm Acknowledged"), ALARM_CLEAR("Alarm Cleared"), - ALARM_DELETE("Alarm Deleted"), + ALARM_DELETE(null), ALARM_ASSIGNED("Alarm Assigned"), ALARM_UNASSIGNED("Alarm Unassigned"), COMMENT_CREATED("Comment Created"), @@ -78,7 +78,7 @@ public enum TbMsgType { this.ruleNodeConnection = ruleNodeConnection; } - public static String getRuleNodeConnection(String msgType) { + public static String getRuleNodeConnectionOrElseOther(String msgType) { if (msgType == null) { return TbNodeConnectionType.OTHER; } else { diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java new file mode 100644 index 0000000000..b76b0fc2b7 --- /dev/null +++ b/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java @@ -0,0 +1,63 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.audit; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.thingsboard.server.common.data.audit.ActionType.ACTIVATED; +import static org.thingsboard.server.common.data.audit.ActionType.ATTRIBUTES_READ; +import static org.thingsboard.server.common.data.audit.ActionType.CREDENTIALS_READ; +import static org.thingsboard.server.common.data.audit.ActionType.CREDENTIALS_UPDATED; +import static org.thingsboard.server.common.data.audit.ActionType.DELETED_COMMENT; +import static org.thingsboard.server.common.data.audit.ActionType.LOCKOUT; +import static org.thingsboard.server.common.data.audit.ActionType.LOGIN; +import static org.thingsboard.server.common.data.audit.ActionType.LOGOUT; +import static org.thingsboard.server.common.data.audit.ActionType.RPC_CALL; +import static org.thingsboard.server.common.data.audit.ActionType.SMS_SENT; +import static org.thingsboard.server.common.data.audit.ActionType.SUSPENDED; + +class ActionTypeTest { + + private static final List typesWithNullRuleEngineMsgType = List.of( + RPC_CALL, + CREDENTIALS_UPDATED, + ACTIVATED, + SUSPENDED, + CREDENTIALS_READ, + ATTRIBUTES_READ, + LOGIN, + LOGOUT, + LOCKOUT, + DELETED_COMMENT, + SMS_SENT + ); + + // backward-compatibility tests + + @Test + void getRuleEngineMsgTypeTest() { + var types = ActionType.values(); + for (var type : types) { + if (typesWithNullRuleEngineMsgType.contains(type)) { + assertThat(type.getRuleEngineMsgType()).isEmpty(); + } + } + } + +} diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java new file mode 100644 index 0000000000..c1f9dffd17 --- /dev/null +++ b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java @@ -0,0 +1,70 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.msg; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED_TO_EDGE; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UNASSIGNED_FROM_EDGE; +import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_FAILURE; +import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_SUCCESS; + +class TbMsgTypeTest { + + private static final List typesWithNullRuleNodeConnection = List.of( + ALARM, + ALARM_DELETE, + ENTITY_ASSIGNED_TO_EDGE, + ENTITY_UNASSIGNED_FROM_EDGE, + PROVISION_FAILURE, + PROVISION_SUCCESS + ); + + + // backward-compatibility tests + + @Test + void getRuleNodeConnectionsTest() { + var tbMsgTypes = TbMsgType.values(); + for (var type : tbMsgTypes) { + if (typesWithNullRuleNodeConnection.contains(type)) { + assertThat(type.getRuleNodeConnection()).isNull(); + } + } + } + + @Test + void getRuleNodeConnectionOrElseOtherTest() { + assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(null)) + .isEqualTo(TbNodeConnectionType.OTHER); + var tbMsgTypes = TbMsgType.values(); + for (var type : tbMsgTypes) { + if (typesWithNullRuleNodeConnection.contains(type)) { + assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type.name())) + .isEqualTo(TbNodeConnectionType.OTHER); + } else { + assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type.name())).isNotNull() + .isNotEqualTo(TbNodeConnectionType.OTHER); + } + } + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java index 3dfa6cb233..2186378527 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java @@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; @@ -62,6 +63,9 @@ public class TbCheckRelationNode implements TbNode { public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbCheckRelationNodeConfiguration.class); if (config.isCheckForSingleEntity()) { + if (StringUtils.isEmpty(config.getEntityType()) || StringUtils.isEmpty(config.getEntityId())) { + throw new TbNodeException("Entity should be specified!"); + } this.singleEntityId = EntityIdFactory.getByTypeAndId(config.getEntityType(), config.getEntityId()); ctx.checkTenantEntity(singleEntityId); } @@ -90,9 +94,9 @@ public class TbCheckRelationNode implements TbNode { } private ListenableFuture processList(TbContext ctx, TbMsg msg) { - ListenableFuture> relationListFuture = EntitySearchDirection.FROM.name().equals(config.getDirection()) ? ctx.getRelationService() - .findByToAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON) : ctx.getRelationService() - .findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON); + ListenableFuture> relationListFuture = EntitySearchDirection.FROM.name().equals(config.getDirection()) ? + ctx.getRelationService().findByToAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON) : + ctx.getRelationService().findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON); return Futures.transformAsync(relationListFuture, this::isEmptyList, ctx.getDbCallbackExecutor()); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java index bd0d5d5160..2121e0c5fa 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java @@ -50,7 +50,7 @@ public class TbMsgTypeSwitchNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - ctx.tellNext(msg, TbMsgType.getRuleNodeConnection(msg.getType())); + ctx.tellNext(msg, TbMsgType.getRuleNodeConnectionOrElseOther(msg.getType())); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java index 7ef2f87845..a6b2433df4 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java @@ -50,34 +50,33 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R class TbAssetTypeSwitchNodeTest { - TenantId tenantId; - AssetId assetId; - AssetId assetIdDeleted; - AssetProfile assetProfile; - TbContext ctx; - TbAssetTypeSwitchNode node; - EmptyNodeConfiguration config; - TbMsgCallback callback; - RuleEngineAssetProfileCache assetProfileCache; + private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); + private static final String EMPTY_DATA = "{}"; + + private AssetId assetId; + private AssetId assetIdDeleted; + private TbContext ctx; + private TbAssetTypeSwitchNode node; + private TbMsgCallback callback; @BeforeEach void setUp() throws TbNodeException { - tenantId = new TenantId(UUID.randomUUID()); + TenantId tenantId = new TenantId(UUID.randomUUID()); assetId = new AssetId(UUID.randomUUID()); assetIdDeleted = new AssetId(UUID.randomUUID()); - assetProfile = new AssetProfile(); + AssetProfile assetProfile = new AssetProfile(); assetProfile.setTenantId(tenantId); assetProfile.setName("TestAssetProfile"); //node - config = new EmptyNodeConfiguration(); + EmptyNodeConfiguration config = new EmptyNodeConfiguration(); node = new TbAssetTypeSwitchNode(); node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); //init mock ctx = mock(TbContext.class); - assetProfileCache = mock(RuleEngineAssetProfileCache.class); + RuleEngineAssetProfileCache assetProfileCache = mock(RuleEngineAssetProfileCache.class); callback = mock(TbMsgCallback.class); when(ctx.getTenantId()).thenReturn(tenantId); @@ -122,7 +121,7 @@ class TbAssetTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(), "{}", callback); + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, EMPTY_METADATA, EMPTY_DATA, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java index 4212af2ade..a794b96620 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java @@ -29,7 +29,6 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.msg.TbMsg; @@ -53,14 +52,15 @@ class TbCheckAlarmStatusNodeTest { private static final DeviceId DEVICE_ID = new DeviceId(UUID.randomUUID()); private static final AlarmId ALARM_ID = new AlarmId(UUID.randomUUID()); private static final TestDbCallbackExecutor DB_EXECUTOR = new TestDbCallbackExecutor(); + private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); - private static TbCheckAlarmStatusNode node; + private TbCheckAlarmStatusNode node; - private static TbContext ctx; - private static RuleEngineAlarmService alarmService; + private TbContext ctx; + private RuleEngineAlarmService alarmService; @BeforeEach - public void setUp() throws TbNodeException { + void setUp() throws TbNodeException { var config = new TbCheckAlarmStatusNodeConfig().defaultConfiguration(); ctx = mock(TbContext.class); @@ -88,7 +88,7 @@ class TbCheckAlarmStatusNodeTest { alarm.setType("General Alarm"); String msgData = JacksonUtil.toString(alarm); - TbMsg msg = getTbMsg(DEVICE_ID, msgData); + TbMsg msg = getTbMsg(msgData); when(alarmService.findAlarmByIdAsync(TENANT_ID, ALARM_ID)).thenReturn(Futures.immediateFuture(alarm)); @@ -114,7 +114,7 @@ class TbCheckAlarmStatusNodeTest { alarm.setCleared(true); String msgData = JacksonUtil.toString(alarm); - TbMsg msg = getTbMsg(DEVICE_ID, msgData); + TbMsg msg = getTbMsg(msgData); when(alarmService.findAlarmByIdAsync(TENANT_ID, ALARM_ID)).thenReturn(Futures.immediateFuture(alarm)); @@ -140,7 +140,7 @@ class TbCheckAlarmStatusNodeTest { alarm.setCleared(true); String msgData = JacksonUtil.toString(alarm); - TbMsg msg = getTbMsg(DEVICE_ID, msgData); + TbMsg msg = getTbMsg(msgData); when(alarmService.findAlarmByIdAsync(TENANT_ID, ALARM_ID)).thenReturn(Futures.immediateFuture(null)); @@ -159,8 +159,8 @@ class TbCheckAlarmStatusNodeTest { assertThat(value).isInstanceOf(TbNodeException.class).hasMessage("No such alarm found."); } - private TbMsg getTbMsg(EntityId entityId, String msgData) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(), msgData); + private TbMsg getTbMsg(String msgData) { + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, EMPTY_METADATA, msgData); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java index dd25363aed..23d6711088 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java @@ -50,9 +50,9 @@ class TbCheckMessageNodeTest { private static final String EMPTY_DATA = "{}"; private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, EMPTY_METADATA, EMPTY_DATA); - private static TbCheckMessageNode node; + private TbCheckMessageNode node; - private static TbContext ctx; + private TbContext ctx; @BeforeEach void setUp() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java new file mode 100644 index 0000000000..b5cdb698a3 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java @@ -0,0 +1,297 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.filter; + +import com.google.common.util.concurrent.Futures; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.TestDbCallbackExecutor; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.dao.relation.RelationService; + +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; + +class TbCheckRelationNodeTest { + + private static final TenantId TENANT_ID = new TenantId(UUID.randomUUID()); + private static final DeviceId DEVICE_ID = new DeviceId(UUID.randomUUID()); + private static final TestDbCallbackExecutor DB_EXECUTOR = new TestDbCallbackExecutor(); + private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); + private static final String EMPTY_DATA = "{}"; + private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, EMPTY_METADATA, EMPTY_DATA); + + private TbCheckRelationNode node; + + private TbContext ctx; + private RelationService relationService; + + @BeforeEach + void setUp() { + ctx = mock(TbContext.class); + relationService = mock(RelationService.class); + + when(ctx.getTenantId()).thenReturn(TENANT_ID); + when(ctx.getRelationService()).thenReturn(relationService); + when(ctx.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); + + node = new TbCheckRelationNode(); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenDefaultConfig_whenInit_then_throwException() { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + + // WHEN + var exception = assertThrows(TbNodeException.class, () -> node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config)))); + + // THEN + assertThat(exception.getMessage()).isEqualTo("Entity should be specified!"); + } + + @Test + void givenCustomConfigWithCheckRelationToSpecificEntity_whenOnMsg_then_True() throws TbNodeException { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + + AssetId assetId = new AssetId(UUID.randomUUID()); + config.setEntityType(assetId.getEntityType().name()); + config.setEntityId(assetId.getId().toString()); + + when(relationService.checkRelationAsync(TENANT_ID, assetId, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(true)); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + + @Test + void givenCustomConfigWithCheckRelationToSpecificEntity_whenOnMsg_then_False() throws TbNodeException { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + + AssetId assetId = new AssetId(UUID.randomUUID()); + config.setEntityType(assetId.getEntityType().name()); + config.setEntityId(assetId.getId().toString()); + + when(relationService.checkRelationAsync(TENANT_ID, assetId, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(false)); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + + @Test + void givenCustomConfigWithCheckRelationToSpecificEntityAndDirectionTo_whenOnMsg_then_True() throws TbNodeException { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + + AssetId assetId = new AssetId(UUID.randomUUID()); + config.setEntityType(assetId.getEntityType().name()); + config.setEntityId(assetId.getId().toString()); + config.setDirection(EntitySearchDirection.TO.name()); + + when(relationService.checkRelationAsync(TENANT_ID, DEVICE_ID, assetId, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(true)); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + verify(relationService, never()).findByFromAndTypeAsync(any(), any(), anyString(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + + @Test + void givenCustomConfigWithCheckRelationToSpecificEntityAndDirectionTo_whenOnMsg_then_False() throws TbNodeException { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + + AssetId assetId = new AssetId(UUID.randomUUID()); + config.setEntityType(assetId.getEntityType().name()); + config.setEntityId(assetId.getId().toString()); + config.setDirection(EntitySearchDirection.TO.name()); + + when(relationService.checkRelationAsync(TENANT_ID, DEVICE_ID, assetId, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(false)); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + + @Test + void givenCustomConfig_whenOnMsg_then_True() throws TbNodeException { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + config.setCheckForSingleEntity(false); + var entityRelation = new EntityRelation(); + entityRelation.setTo(DEVICE_ID); + entityRelation.setFrom(new AssetId(UUID.randomUUID())); + entityRelation.setType(EntityRelation.CONTAINS_TYPE); + entityRelation.setTypeGroup(RelationTypeGroup.COMMON); + + when(relationService.findByToAndTypeAsync(TENANT_ID, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + verify(relationService, never()).findByFromAndTypeAsync(any(), any(), anyString(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + + @Test + void givenCustomConfig_whenOnMsg_then_False() throws TbNodeException { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + config.setCheckForSingleEntity(false); + + when(relationService.findByToAndTypeAsync(TENANT_ID, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(Collections.emptyList())); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + verify(relationService, never()).findByFromAndTypeAsync(any(), any(), anyString(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + + @Test + void givenCustomConfigDirectionTo_whenOnMsg_then_True() throws TbNodeException { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + config.setCheckForSingleEntity(false); + config.setDirection(EntitySearchDirection.TO.name()); + var entityRelation = new EntityRelation(); + entityRelation.setFrom(new AssetId(UUID.randomUUID())); + entityRelation.setTo(DEVICE_ID); + entityRelation.setType(EntityRelation.CONTAINS_TYPE); + entityRelation.setTypeGroup(RelationTypeGroup.COMMON); + + when(relationService.findByFromAndTypeAsync(TENANT_ID, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + verify(relationService, never()).findByToAndTypeAsync(any(), any(), anyString(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + + @Test + void givenCustomConfigDirectionTo_whenOnMsg_then_False() throws TbNodeException { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + config.setCheckForSingleEntity(false); + config.setDirection(EntitySearchDirection.TO.name()); + + when(relationService.findByFromAndTypeAsync(TENANT_ID, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(Collections.emptyList())); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + // WHEN + node.onMsg(ctx, EMPTY_POST_ATTRIBUTES_MSG); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + verify(relationService, never()).findByToAndTypeAsync(any(), any(), anyString(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); + } + +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java index fb77b5dc5d..ef76787f94 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java @@ -50,34 +50,30 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R class TbDeviceTypeSwitchNodeTest { - TenantId tenantId; - DeviceId deviceId; - DeviceId deviceIdDeleted; - DeviceProfile deviceProfile; - TbContext ctx; - TbDeviceTypeSwitchNode node; - EmptyNodeConfiguration config; - TbMsgCallback callback; - RuleEngineDeviceProfileCache deviceProfileCache; + private DeviceId deviceId; + private DeviceId deviceIdDeleted; + private TbContext ctx; + private TbDeviceTypeSwitchNode node; + private TbMsgCallback callback; @BeforeEach void setUp() throws TbNodeException { - tenantId = new TenantId(UUID.randomUUID()); + TenantId tenantId = new TenantId(UUID.randomUUID()); deviceId = new DeviceId(UUID.randomUUID()); deviceIdDeleted = new DeviceId(UUID.randomUUID()); - deviceProfile = new DeviceProfile(); + DeviceProfile deviceProfile = new DeviceProfile(); deviceProfile.setTenantId(tenantId); deviceProfile.setName("TestDeviceProfile"); //node - config = new EmptyNodeConfiguration(); + EmptyNodeConfiguration config = new EmptyNodeConfiguration(); node = new TbDeviceTypeSwitchNode(); node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); //init mock ctx = mock(TbContext.class); - deviceProfileCache = mock(RuleEngineDeviceProfileCache.class); + RuleEngineDeviceProfileCache deviceProfileCache = mock(RuleEngineDeviceProfileCache.class); callback = mock(TbMsgCallback.class); when(ctx.getTenantId()).thenReturn(tenantId); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java index 0b9b2ec143..b49dd4aac8 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java @@ -53,8 +53,8 @@ public class TbJsFilterNodeTest { @Mock private ScriptEngine scriptEngine; - private RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); - private RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); + private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); @Test public void falseEvaluationDoNotSendMsg() throws TbNodeException { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java index f4f852c6bd..763af2b1ee 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java @@ -47,8 +47,8 @@ public class TbJsSwitchNodeTest { @Mock private ScriptEngine scriptEngine; - private RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); - private RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); + private final RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); + private final RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); @Test public void multipleRoutesAreAllowed() throws TbNodeException { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java index 51155688e6..d43d309cda 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java @@ -43,9 +43,9 @@ class TbMsgTypeSwitchNodeTest { private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); private static final String EMPTY_DATA = "{}"; - private static TbMsgTypeSwitchNode node; + private TbMsgTypeSwitchNode node; - private static TbContext ctx; + private TbContext ctx; @BeforeEach void setUp() { @@ -84,9 +84,8 @@ class TbMsgTypeSwitchNodeTest { assertThat(msg).isNotNull(); assertThat(msg.getType()).isNotNull(); assertThat(msg).isSameAs(tbMsgList.get(i)); - // todo add additional validation that types like ALARM or PROVISION returns OTHER for backward-compatibility. assertThat(resultNodeConnections.get(i)) - .isEqualTo(TbMsgType.getRuleNodeConnection(msg.getType())); + .isEqualTo(TbMsgType.getRuleNodeConnectionOrElseOther(msg.getType())); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java index 09e67e45ef..28d8b55264 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java @@ -45,9 +45,9 @@ class TbOriginatorTypeSwitchNodeTest { private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); private static final String EMPTY_DATA = "{}"; - private static TbOriginatorTypeSwitchNode node; + private TbOriginatorTypeSwitchNode node; - private static TbContext ctx; + private TbContext ctx; @BeforeEach void setUp() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 27a13893c8..12385f6e28 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -208,7 +208,7 @@ public class TbGetCustomerAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -223,7 +223,7 @@ public class TbGetCustomerAttributeNodeTest { // GIVEN var userId = new UserId(UUID.randomUUID()); - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), userId, new TbMsgMetaData(), "{}"); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), userId, new TbMsgMetaData(), "{}"); when(ctxMock.getTenantId()).thenReturn(TENANT_ID); @@ -467,7 +467,7 @@ public class TbGetCustomerAttributeNodeTest { var msgData = "{\"temp\":42,\"humidity\":77,\"messageBodyPattern1\":\"targetKey2\",\"messageBodyPattern2\":\"sourceKey3\"}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), originator, msgMetaData, msgData); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), originator, msgMetaData, msgData); } @RequiredArgsConstructor diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java index d90d9eb767..540a260338 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java @@ -456,7 +456,7 @@ public class TbGetCustomerDetailsNodeTest { var msgData = "{\"dataKey1\":123,\"dataKey2\":\"dataValue2\"}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), originator, msgMetaData, msgData); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), originator, msgMetaData, msgData); } private void mockFindCustomer() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java index fc61bc4849..9c50e35f79 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java @@ -162,7 +162,7 @@ public class TbGetOriginatorFieldsNodeTest { node.fetchTo = FetchTo.DATA; var msgMetaData = new TbMsgMetaData(); var msgData = "{\"temp\":42,\"humidity\":77}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -205,7 +205,7 @@ public class TbGetOriginatorFieldsNodeTest { "testKey1", "testValue1", "testKey2", "123")); var msgData = "[\"value1\",\"value2\"]"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -253,7 +253,7 @@ public class TbGetOriginatorFieldsNodeTest { "testKey1", "testValue1", "testKey2", "123")); var msgData = "[\"value1\",\"value2\"]"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -311,7 +311,7 @@ public class TbGetOriginatorFieldsNodeTest { "testKey1", "testValue1", "testKey2", "123")); var msgData = "[\"value1\",\"value2\"]"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), new DashboardId(UUID.randomUUID()), msgMetaData, msgData); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), new DashboardId(UUID.randomUUID()), msgMetaData, msgData); when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index d2c452afd4..1a638eca39 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -222,7 +222,7 @@ public class TbGetRelatedAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index 0ee3512288..c163d68733 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -188,7 +188,7 @@ public class TbGetTenantAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -396,7 +396,7 @@ public class TbGetTenantAttributeNodeTest { var msgData = "{\"temp\":42,\"humidity\":77,\"messageBodyPattern1\":\"targetKey2\",\"messageBodyPattern2\":\"sourceKey3\"}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), originator, msgMetaData, msgData); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), originator, msgMetaData, msgData); } @RequiredArgsConstructor diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java index 0a756575e2..430a772269 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java @@ -287,7 +287,7 @@ public class TbGetTenantDetailsNodeTest { var msgData = "{\"dataKey1\":123,\"dataKey2\":\"dataValue2\"}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.getRuleNodeConnection(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); } private void mockFindTenant() { From 6eb4510e2a236091d76f9377e3d1825feb7a3a23 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 30 Jun 2023 13:46:19 +0300 Subject: [PATCH 181/421] User notification settings - by notification type --- .../DefaultNotificationCenter.java | 7 ++- .../NotificationProcessingContext.java | 4 ++ .../notification/NotificationApiTest.java | 59 +++++++++++++++++++ ...a => TestNotificationSettingsService.java} | 12 +++- .../resources/application-test.properties | 2 + .../NotificationRequestStats.java | 5 +- .../settings/UserNotificationSettings.java | 40 +++++++------ .../DefaultNotificationSettingsService.java | 48 ++++----------- 8 files changed, 118 insertions(+), 59 deletions(-) rename application/src/test/java/org/thingsboard/server/service/notification/{MockNotificationSettingsService.java => TestNotificationSettingsService.java} (61%) diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index 8f6a6dc177..b379957e0f 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -238,10 +238,13 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple private void processForRecipient(NotificationDeliveryMethod deliveryMethod, NotificationRecipient recipient, NotificationProcessingContext ctx) throws Exception { if (ctx.getStats().contains(deliveryMethod, recipient.getId())) { throw new AlreadySentException(); + } else { + ctx.getStats().reportProcessed(deliveryMethod, recipient.getId()); } + if (recipient instanceof User && ctx.getRequest().getRuleId() != null) { UserNotificationSettings settings = notificationSettingsService.getUserNotificationSettings(ctx.getTenantId(), (User) recipient, false); - Set enabledDeliveryMethods = settings.getEnabledDeliveryMethods(ctx.getRequest().getRuleId()); + Set enabledDeliveryMethods = settings.getEnabledDeliveryMethods(ctx.getNotificationType()); if (!enabledDeliveryMethods.contains(deliveryMethod)) { throw new RuntimeException("User disabled " + deliveryMethod.getName() + " notifications of this type"); } @@ -260,7 +263,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple Notification notification = Notification.builder() .requestId(request.getId()) .recipientId(recipient.getId()) - .type(ctx.getNotificationTemplate().getNotificationType()) + .type(ctx.getNotificationType()) .subject(processedTemplate.getSubject()) .text(processedTemplate.getBody()) .additionalConfig(processedTemplate.getAdditionalConfig()) diff --git a/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java b/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java index 27a9cabe43..c4d8895266 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/NotificationProcessingContext.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; import org.thingsboard.server.common.data.notification.NotificationRequest; import org.thingsboard.server.common.data.notification.NotificationRequestStats; +import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.settings.NotificationDeliveryMethodConfig; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.targets.NotificationRecipient; @@ -52,6 +53,8 @@ public class NotificationProcessingContext { private final Set deliveryMethods; @Getter private final NotificationTemplate notificationTemplate; + @Getter + private final NotificationType notificationType; private final Map templates; @Getter @@ -65,6 +68,7 @@ public class NotificationProcessingContext { this.deliveryMethods = deliveryMethods; this.settings = settings; this.notificationTemplate = template; + this.notificationType = template.getNotificationType(); this.templates = new EnumMap<>(NotificationDeliveryMethod.class); this.stats = new NotificationRequestStats(); init(); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java index 851550eee7..89b77fcf99 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.notification; +import com.google.common.util.concurrent.SettableFuture; import lombok.extern.slf4j.Slf4j; import org.assertj.core.data.Offset; import org.java_websocket.client.WebSocketClient; @@ -23,6 +24,7 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.rule.engine.api.NotificationCenter; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.id.NotificationTargetId; import org.thingsboard.server.common.data.notification.Notification; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; @@ -35,6 +37,7 @@ import org.thingsboard.server.common.data.notification.NotificationRequestStatus import org.thingsboard.server.common.data.notification.NotificationType; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig; +import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings; import org.thingsboard.server.common.data.notification.targets.NotificationTarget; import org.thingsboard.server.common.data.notification.targets.platform.CustomerUsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig; @@ -59,6 +62,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; @@ -470,6 +475,54 @@ public class NotificationApiTest extends AbstractNotificationApiTest { assertThat(stats.getSent().get(NotificationDeliveryMethod.WEB)).hasValue(1); } + @Test + public void testUserNotificationSettings() throws Exception { + var entityActionNotificationPref = new UserNotificationSettings.NotificationPref(); + entityActionNotificationPref.setEnabled(true); + entityActionNotificationPref.setEnabledDeliveryMethods(Set.of(NotificationDeliveryMethod.WEB)); + + var entitiesLimitNotificationPref = new UserNotificationSettings.NotificationPref(); + entitiesLimitNotificationPref.setEnabled(true); + entitiesLimitNotificationPref.setEnabledDeliveryMethods(Set.of(NotificationDeliveryMethod.SMS)); + + var apiUsageLimitNotificationPref = new UserNotificationSettings.NotificationPref(); + apiUsageLimitNotificationPref.setEnabled(false); + apiUsageLimitNotificationPref.setEnabledDeliveryMethods(Set.of(NotificationDeliveryMethod.WEB)); + + UserNotificationSettings settings = new UserNotificationSettings(Map.of( + NotificationType.ENTITY_ACTION, entityActionNotificationPref, + NotificationType.ENTITIES_LIMIT, entitiesLimitNotificationPref, + NotificationType.API_USAGE_LIMIT, apiUsageLimitNotificationPref + )); + doPost("/api/notification/settings/user", settings, UserNotificationSettings.class); + + var entityActionNotificationTemplate = createNotificationTemplate(NotificationType.ENTITY_ACTION, "Entity action", "Entity action", NotificationDeliveryMethod.WEB); + var entitiesLimitNotificationTemplate = createNotificationTemplate(NotificationType.ENTITIES_LIMIT, "Entities limit", "Entities limit", NotificationDeliveryMethod.WEB); + var apiUsageLimitNotificationTemplate = createNotificationTemplate(NotificationType.API_USAGE_LIMIT, "API usage limit", "API usage limit", NotificationDeliveryMethod.WEB); + NotificationTarget target = createNotificationTarget(tenantAdminUserId); + + NotificationRequest notificationRequest = NotificationRequest.builder() + .tenantId(tenantId) + .templateId(entityActionNotificationTemplate.getId()) + .originatorEntityId(tenantAdminUserId) + .targets(List.of(target.getUuidId())) + .ruleId(new NotificationRuleId(UUID.randomUUID())) // to trigger user settings check + .build(); + NotificationRequestStats stats = submitNotificationRequestAndWait(notificationRequest); + assertThat(stats.getErrors()).isEmpty(); + assertThat(stats.getSent().get(NotificationDeliveryMethod.WEB).get()).isOne(); + + notificationRequest.setTemplateId(entitiesLimitNotificationTemplate.getId()); + stats = submitNotificationRequestAndWait(notificationRequest); + assertThat(stats.getSent().get(NotificationDeliveryMethod.WEB)).matches(n -> n == null || n.get() == 0); + assertThat(stats.getErrors().get(NotificationDeliveryMethod.WEB).values()).first().asString().contains("disabled"); + + notificationRequest.setTemplateId(apiUsageLimitNotificationTemplate.getId()); + stats = submitNotificationRequestAndWait(notificationRequest); + assertThat(stats.getSent().get(NotificationDeliveryMethod.WEB)).matches(n -> n == null || n.get() == 0); + assertThat(stats.getErrors().get(NotificationDeliveryMethod.WEB).values()).first().asString().contains("disabled"); + } + @Test public void testSlackNotifications() throws Exception { NotificationSettings settings = new NotificationSettings(); @@ -524,6 +577,12 @@ public class NotificationApiTest extends AbstractNotificationApiTest { assertThat(stats.getErrors().get(NotificationDeliveryMethod.SLACK).values()).containsExactly(errorMessage); } + private NotificationRequestStats submitNotificationRequestAndWait(NotificationRequest notificationRequest) throws Exception { + SettableFuture future = SettableFuture.create(); + notificationCenter.processNotificationRequest(notificationRequest.getTenantId(), notificationRequest, future::set); + return future.get(30, TimeUnit.SECONDS); + } + private void checkFullNotificationsUpdate(UnreadNotificationsUpdate notificationsUpdate, String... expectedNotifications) { assertThat(notificationsUpdate.getNotifications()).extracting(Notification::getText).containsOnly(expectedNotifications); assertThat(notificationsUpdate.getNotifications()).extracting(Notification::getType).containsOnly(DEFAULT_NOTIFICATION_TYPE); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java b/application/src/test/java/org/thingsboard/server/service/notification/TestNotificationSettingsService.java similarity index 61% rename from application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java rename to application/src/test/java/org/thingsboard/server/service/notification/TestNotificationSettingsService.java index 6c3a02051e..3b21b35a73 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/MockNotificationSettingsService.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/TestNotificationSettingsService.java @@ -19,14 +19,20 @@ import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.notification.DefaultNotificationSettingsService; +import org.thingsboard.server.dao.notification.NotificationTargetService; +import org.thingsboard.server.dao.notification.NotificationTemplateService; import org.thingsboard.server.dao.settings.AdminSettingsService; +import org.thingsboard.server.dao.user.UserService; @Service @Primary -public class MockNotificationSettingsService extends DefaultNotificationSettingsService { +public class TestNotificationSettingsService extends DefaultNotificationSettingsService { - public MockNotificationSettingsService(AdminSettingsService adminSettingsService) { - super(adminSettingsService, null, null, null, null, null); + public TestNotificationSettingsService(AdminSettingsService adminSettingsService, + NotificationTargetService notificationTargetService, + NotificationTemplateService notificationTemplateService, + UserService userService) { + super(adminSettingsService, notificationTargetService, notificationTemplateService, null, userService); } @Override diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index ad86ff736b..28c13e33fb 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -67,3 +67,5 @@ sql.ttl.audit_logs.ttl=2592000 sql.edge_events.partition_size=168 sql.ttl.edge_events.edge_event_ttl=2592000 + +server.log_controller_error_stack_trace=false diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequestStats.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequestStats.java index 619e1ad38f..691ecf8bc1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequestStats.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationRequestStats.java @@ -54,7 +54,6 @@ public class NotificationRequestStats { public void reportSent(NotificationDeliveryMethod deliveryMethod, NotificationRecipient recipient) { sent.computeIfAbsent(deliveryMethod, k -> new AtomicInteger()).incrementAndGet(); - processedRecipients.computeIfAbsent(deliveryMethod, k -> ConcurrentHashMap.newKeySet()).add(recipient.getId()); } public void reportError(NotificationDeliveryMethod deliveryMethod, Throwable error, NotificationRecipient recipient) { @@ -68,6 +67,10 @@ public class NotificationRequestStats { errors.computeIfAbsent(deliveryMethod, k -> new ConcurrentHashMap<>()).put(recipient.getTitle(), errorMessage); } + public void reportProcessed(NotificationDeliveryMethod deliveryMethod, Object recipientId) { + processedRecipients.computeIfAbsent(deliveryMethod, k -> ConcurrentHashMap.newKeySet()).add(recipientId); + } + public boolean contains(NotificationDeliveryMethod deliveryMethod, Object recipientId) { Set processedRecipients = this.processedRecipients.get(deliveryMethod); return processedRecipients != null && processedRecipients.contains(recipientId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java index 9e2f2740ab..f24520bc32 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java @@ -16,57 +16,61 @@ package org.thingsboard.server.common.data.notification.settings; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; -import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; -import org.thingsboard.server.common.data.notification.rule.NotificationRule; +import org.thingsboard.server.common.data.notification.NotificationType; +import org.thingsboard.server.common.data.notification.targets.NotificationTargetType; import javax.validation.Valid; +import javax.validation.constraints.AssertTrue; import javax.validation.constraints.NotNull; import java.util.Collections; -import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.UUID; @Data public class UserNotificationSettings { @NotNull @Valid - private final List prefs; + private final Map prefs; - public static final UserNotificationSettings DEFAULT = new UserNotificationSettings(Collections.emptyList()); + public static final UserNotificationSettings DEFAULT = new UserNotificationSettings(Collections.emptyMap()); @JsonCreator - public UserNotificationSettings(@JsonProperty("prefs") List prefs) { + public UserNotificationSettings(@JsonProperty("prefs") Map prefs) { this.prefs = prefs; } - public Set getEnabledDeliveryMethods(NotificationRuleId ruleId) { - return prefs.stream() - .filter(pref -> pref.getRuleId().equals(ruleId.getId())).findFirst() - .map(pref -> pref.isEnabled() ? pref.getEnabledDeliveryMethods() : Collections.emptySet()) - .orElse(NotificationDeliveryMethod.values); + public Set getEnabledDeliveryMethods(NotificationType notificationType) { + NotificationPref pref = prefs.get(notificationType); + if (pref != null) { + return pref.isEnabled() ? pref.getEnabledDeliveryMethods() : Collections.emptySet(); + } else { + return NotificationDeliveryMethod.values; + } } @Data public static class NotificationPref { - @NotNull - private UUID ruleId; - private String ruleName; private boolean enabled; @NotNull private Set enabledDeliveryMethods; - public static NotificationPref createDefault(NotificationRule rule) { + public static NotificationPref createDefault() { NotificationPref pref = new NotificationPref(); - pref.setRuleId(rule.getUuidId()); - pref.setRuleName(rule.getName()); pref.setEnabled(true); pref.setEnabledDeliveryMethods(NotificationDeliveryMethod.values); return pref; } + + @JsonIgnore + @AssertTrue(message = "Only email, Web and SMS delivery methods are allowed") + public boolean isValid() { + return NotificationTargetType.PLATFORM_USERS.getSupportedDeliveryMethods().containsAll(enabledDeliveryMethods); + } } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java index af9687840a..8fd15e6cd0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -31,7 +30,6 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.NotificationType; -import org.thingsboard.server.common.data.notification.rule.NotificationRule; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings; import org.thingsboard.server.common.data.notification.settings.UserNotificationSettings.NotificationPref; @@ -46,17 +44,14 @@ import org.thingsboard.server.common.data.notification.targets.platform.TenantAd import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.user.UserService; -import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; +import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.UUID; import static java.util.function.Predicate.not; @@ -67,11 +62,11 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS private final AdminSettingsService adminSettingsService; private final NotificationTargetService notificationTargetService; private final NotificationTemplateService notificationTemplateService; - private final NotificationRuleService notificationRuleService; private final DefaultNotifications defaultNotifications; private final UserService userService; private static final String SETTINGS_KEY = "notifications"; + private static final String USER_SETTINGS_KEY = "notificationSettings"; @CacheEvict(cacheNames = CacheConstants.NOTIFICATION_SETTINGS_CACHE, key = "#tenantId") @Override @@ -103,47 +98,30 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS public void saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings) { User user = userService.findUserById(tenantId, userId); ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(user.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); - additionalInfo.set("notificationSettings", JacksonUtil.valueToTree(settings)); + additionalInfo.set(USER_SETTINGS_KEY, JacksonUtil.valueToTree(settings)); user.setAdditionalInfo(additionalInfo); userService.saveUser(user); } @Override public UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user, boolean format) { - UserNotificationSettings settings = Optional.ofNullable(user.getAdditionalInfo().get("notificationSettings")) + UserNotificationSettings settings = Optional.ofNullable(user.getAdditionalInfo().get(USER_SETTINGS_KEY)) .filter(not(JsonNode::isNull)) .map(json -> JacksonUtil.treeToValue(json, UserNotificationSettings.class)) .orElse(null); if (!format) { - if (settings != null) { - return settings; - } else { - return UserNotificationSettings.DEFAULT; - } + return Optional.ofNullable(settings).orElse(UserNotificationSettings.DEFAULT); } - Map rules = new HashMap<>(); - notificationRuleService.findNotificationRulesByTenantId(tenantId, new PageLink(Integer.MAX_VALUE, 0,null, SortOrder.byCreatedTimeDesc)) - .getData().forEach(rule -> rules.put(rule.getUuidId(), rule)); - - List prefs = new ArrayList<>(); - if (settings == null) { - rules.values().forEach(rule -> { - prefs.add(NotificationPref.createDefault(rule)); - }); - } else { - settings.getPrefs().forEach(pref -> { - NotificationRule rule = rules.remove(pref.getRuleId()); - if (rule == null) { - return; - } - pref.setRuleName(rule.getName()); - prefs.add(pref); - }); - rules.values().forEach(rule -> { - prefs.add(NotificationPref.createDefault(rule)); - }); + Map prefs = new EnumMap<>(NotificationType.class); + if (settings != null) { + prefs.putAll(settings.getPrefs()); + } + NotificationPref defaultPref = NotificationPref.createDefault(); + for (NotificationType notificationType : NotificationType.values()) { + prefs.putIfAbsent(notificationType, defaultPref); } + prefs.remove(NotificationType.GENERAL); return new UserNotificationSettings(prefs); } From e32dc47ea58b3f5e4ec92e3ec7e8b7294cc041c4 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 30 Jun 2023 17:42:53 +0300 Subject: [PATCH 182/421] added upgrade script for check field presence node && PROD-2217 --- .../engine/filter/TbCheckRelationNode.java | 44 ++++++++++++--- .../TbCheckRelationNodeConfiguration.java | 2 +- .../filter/TbCheckRelationNodeTest.java | 55 +++++++++++++------ ...nator_fields_node_fields_templatization.md | 2 +- 4 files changed, 74 insertions(+), 29 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java index 2186378527..ecc06f6303 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java @@ -15,23 +15,26 @@ */ package org.thingsboard.rule.engine.filter; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; -import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbVersionedNode; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import java.util.List; @@ -54,7 +57,9 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; "Output connections: True, False, Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeCheckRelationConfig") -public class TbCheckRelationNode implements TbNode { +public class TbCheckRelationNode implements TbVersionedNode { + + private static final String DIRECTION_PROPERTY_NAME = "direction"; private TbCheckRelationNodeConfiguration config; private EntityId singleEntityId; @@ -84,19 +89,19 @@ public class TbCheckRelationNode implements TbNode { EntityId from; EntityId to; if (EntitySearchDirection.FROM.name().equals(config.getDirection())) { - from = singleEntityId; - to = msg.getOriginator(); - } else { to = singleEntityId; from = msg.getOriginator(); + } else { + from = singleEntityId; + to = msg.getOriginator(); } return ctx.getRelationService().checkRelationAsync(ctx.getTenantId(), from, to, config.getRelationType(), RelationTypeGroup.COMMON); } private ListenableFuture processList(TbContext ctx, TbMsg msg) { ListenableFuture> relationListFuture = EntitySearchDirection.FROM.name().equals(config.getDirection()) ? - ctx.getRelationService().findByToAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON) : - ctx.getRelationService().findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON); + ctx.getRelationService().findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON) : + ctx.getRelationService().findByToAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON); return Futures.transformAsync(relationListFuture, this::isEmptyList, ctx.getDbCallbackExecutor()); } @@ -104,4 +109,25 @@ public class TbCheckRelationNode implements TbNode { return entityRelations.isEmpty() ? Futures.immediateFuture(false) : Futures.immediateFuture(true); } + @Override + public TbPair upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException { + if (fromVersion == 0) { + var newConfigObjectNode = (ObjectNode) oldConfiguration; + if (!newConfigObjectNode.has(DIRECTION_PROPERTY_NAME)) { + throw new TbNodeException("property to update: '" + DIRECTION_PROPERTY_NAME + "' doesn't exists in configuration!"); + } + String direction = newConfigObjectNode.get(DIRECTION_PROPERTY_NAME).asText(); + if ("TO".equals(direction)) { + newConfigObjectNode.put(DIRECTION_PROPERTY_NAME, EntitySearchDirection.FROM.name()); + return new TbPair<>(true, newConfigObjectNode); + } + if ("FROM".equals(direction)) { + newConfigObjectNode.put(DIRECTION_PROPERTY_NAME, EntitySearchDirection.TO.name()); + return new TbPair<>(true, newConfigObjectNode); + } + throw new TbNodeException("property to update: '" + DIRECTION_PROPERTY_NAME + "' has invalid value!"); + } + return new TbPair<>(false, oldConfiguration); + } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeConfiguration.java index ad5574ec8c..1a8ab7068d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeConfiguration.java @@ -34,7 +34,7 @@ public class TbCheckRelationNodeConfiguration implements NodeConfiguration newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); verify(ctx, never()).tellFailure(any(), any()); - verify(relationService, never()).findByFromAndTypeAsync(any(), any(), anyString(), any()); TbMsg newMsg = newMsgCaptor.getValue(); assertThat(newMsg).isNotNull(); assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); @@ -179,7 +183,7 @@ class TbCheckRelationNodeTest { config.setEntityId(assetId.getId().toString()); config.setDirection(EntitySearchDirection.TO.name()); - when(relationService.checkRelationAsync(TENANT_ID, DEVICE_ID, assetId, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(false)); + when(relationService.checkRelationAsync(TENANT_ID, assetId, ORIGINATOR_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(false)); node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); // WHEN @@ -200,12 +204,12 @@ class TbCheckRelationNodeTest { var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); config.setCheckForSingleEntity(false); var entityRelation = new EntityRelation(); - entityRelation.setTo(DEVICE_ID); - entityRelation.setFrom(new AssetId(UUID.randomUUID())); + entityRelation.setFrom(ORIGINATOR_ID); + entityRelation.setTo(new AssetId(UUID.randomUUID())); entityRelation.setType(EntityRelation.CONTAINS_TYPE); entityRelation.setTypeGroup(RelationTypeGroup.COMMON); - when(relationService.findByToAndTypeAsync(TENANT_ID, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + when(relationService.findByFromAndTypeAsync(TENANT_ID, ORIGINATOR_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(List.of(entityRelation))); node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); // WHEN @@ -215,7 +219,7 @@ class TbCheckRelationNodeTest { ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); verify(ctx, never()).tellFailure(any(), any()); - verify(relationService, never()).findByFromAndTypeAsync(any(), any(), anyString(), any()); + verify(relationService, never()).findByToAndTypeAsync(any(), any(), anyString(), any()); TbMsg newMsg = newMsgCaptor.getValue(); assertThat(newMsg).isNotNull(); assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); @@ -227,7 +231,7 @@ class TbCheckRelationNodeTest { var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); config.setCheckForSingleEntity(false); - when(relationService.findByToAndTypeAsync(TENANT_ID, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(Collections.emptyList())); + when(relationService.findByFromAndTypeAsync(TENANT_ID, ORIGINATOR_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(Collections.emptyList())); node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); // WHEN @@ -237,7 +241,7 @@ class TbCheckRelationNodeTest { ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); verify(ctx, never()).tellFailure(any(), any()); - verify(relationService, never()).findByFromAndTypeAsync(any(), any(), anyString(), any()); + verify(relationService, never()).findByToAndTypeAsync(any(), any(), anyString(), any()); TbMsg newMsg = newMsgCaptor.getValue(); assertThat(newMsg).isNotNull(); assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); @@ -251,11 +255,11 @@ class TbCheckRelationNodeTest { config.setDirection(EntitySearchDirection.TO.name()); var entityRelation = new EntityRelation(); entityRelation.setFrom(new AssetId(UUID.randomUUID())); - entityRelation.setTo(DEVICE_ID); + entityRelation.setTo(ORIGINATOR_ID); entityRelation.setType(EntityRelation.CONTAINS_TYPE); entityRelation.setTypeGroup(RelationTypeGroup.COMMON); - when(relationService.findByFromAndTypeAsync(TENANT_ID, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(List.of(entityRelation))); + when(relationService.findByToAndTypeAsync(TENANT_ID, ORIGINATOR_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(List.of(entityRelation))); node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); // WHEN @@ -265,7 +269,7 @@ class TbCheckRelationNodeTest { ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); verify(ctx, never()).tellFailure(any(), any()); - verify(relationService, never()).findByToAndTypeAsync(any(), any(), anyString(), any()); + verify(relationService, never()).findByFromAndTypeAsync(any(), any(), anyString(), any()); TbMsg newMsg = newMsgCaptor.getValue(); assertThat(newMsg).isNotNull(); assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); @@ -278,7 +282,7 @@ class TbCheckRelationNodeTest { config.setCheckForSingleEntity(false); config.setDirection(EntitySearchDirection.TO.name()); - when(relationService.findByFromAndTypeAsync(TENANT_ID, DEVICE_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(Collections.emptyList())); + when(relationService.findByToAndTypeAsync(TENANT_ID, ORIGINATOR_ID, config.getRelationType(), RelationTypeGroup.COMMON)).thenReturn(Futures.immediateFuture(Collections.emptyList())); node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); // WHEN @@ -288,10 +292,25 @@ class TbCheckRelationNodeTest { ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); verify(ctx, never()).tellFailure(any(), any()); - verify(relationService, never()).findByToAndTypeAsync(any(), any(), anyString(), any()); + verify(relationService, never()).findByFromAndTypeAsync(any(), any(), anyString(), any()); TbMsg newMsg = newMsgCaptor.getValue(); assertThat(newMsg).isNotNull(); assertThat(newMsg).isSameAs(EMPTY_POST_ATTRIBUTES_MSG); } + @Test + void givenOldConfig_whenUpgrade_thenShouldReturnTrueResultWithNewConfig() throws Exception { + // GIVEN + var config = new TbCheckRelationNodeConfiguration().defaultConfiguration(); + config.setEntityType(ORIGINATOR_ID.getEntityType().name()); + config.setEntityId(ORIGINATOR_ID.getId().toString()); + String oldConfig = "{\"checkForSingleEntity\":true,\"direction\":\"TO\",\"entityType\":\"" + config.getEntityType() + "\",\"entityId\":\"" + config.getEntityId() + "\",\"relationType\":\"Contains\"}"; + JsonNode configJson = JacksonUtil.toJsonNode(oldConfig); + // WHEN + TbPair upgrade = node.upgrade(0, configJson); + // THEN + assertTrue(upgrade.getFirst()); + assertEquals(config, JacksonUtil.treeToValue(upgrade.getSecond(), config.getClass())); + } + } diff --git a/ui-ngx/src/assets/help/en_US/rulenode/originator_fields_node_fields_templatization.md b/ui-ngx/src/assets/help/en_US/rulenode/originator_fields_node_fields_templatization.md index b21f450ae9..42f4ea6138 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/originator_fields_node_fields_templatization.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/originator_fields_node_fields_templatization.md @@ -12,7 +12,7 @@ Let's assume that we have two device types in our use case: - `smart_door_lock` - `motion_detector` -Let's assume that device of type `dock_lock_sensor` and name `SDL-001` publish next type of messages to the system: +Let's assume that device of type `smart_door_lock` and name `SDL-001` publish next type of messages to the system: ```json { From ea56b2a1681c7fc399131f15b940674a21c80d13 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 30 Jun 2023 19:59:13 +0300 Subject: [PATCH 183/421] UI: Timeseries line chart config. --- .../dashboard-page/edit-widget.component.html | 14 +- .../dashboard-page/edit-widget.component.scss | 10 +- .../basic/basic-widget-config.module.ts | 8 +- ...entities-table-basic-config.component.html | 4 +- .../entities-table-basic-config.component.ts | 7 +- .../simple-card-basic-config.component.html | 4 +- .../simple-card-basic-config.component.ts | 7 +- ...meseries-table-basic-config.component.html | 5 +- ...timeseries-table-basic-config.component.ts | 18 +- .../chart/flot-basic-config.component.html | 113 ++++ .../chart/flot-basic-config.component.ts | 167 ++++++ .../basic/common/data-key-row.component.html | 2 +- .../basic/common/data-key-row.component.ts | 3 +- .../basic/common/data-keys-panel.component.ts | 6 +- .../config/data-key-config.component.html | 20 +- .../config/data-key-config.component.scss | 107 ---- .../config/data-key-config.component.ts | 2 +- .../widget/config/datasources.component.ts | 17 +- .../timewindow-config-panel.component.ts | 11 +- .../widget/config/widget-units.component.html | 2 +- ...entities-table-key-settings.component.html | 8 +- ...ities-table-widget-settings.component.html | 14 +- ...meseries-table-key-settings.component.html | 4 +- ...s-table-latest-key-settings.component.html | 8 +- ...eries-table-widget-settings.component.html | 20 +- .../chart/flot-key-settings.component.html | 257 ++++----- .../chart/flot-key-settings.component.ts | 1 + .../chart/flot-threshold.component.html | 74 ++- .../chart/flot-threshold.component.scss | 62 ++- .../chart/flot-threshold.component.ts | 15 +- .../chart/flot-widget-settings.component.html | 496 ++++++++++-------- .../chart/flot-widget-settings.component.ts | 4 + .../chart/label-data-key.component.ts | 2 +- .../common/legend-config.component.html | 56 +- .../common/legend-config.component.ts | 57 +- .../widget/widget-config.component.html | 32 +- .../assets/locale/locale.constant-en_US.json | 38 +- ui-ngx/src/styles.scss | 41 +- 38 files changed, 1034 insertions(+), 682 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts delete mode 100644 ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.scss diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html index 837c0abcad..c3d4caca14 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html @@ -54,11 +54,13 @@ - - +
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss index 9777decdb0..c31f1d5791 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss @@ -14,9 +14,17 @@ * limitations under the License. */ :host { - .widget-preview-section { + .widget-preview-background { position: absolute; top: 72px; + left: 0; + right: 0; + bottom: 0; + background: #fff; + } + .widget-preview-section { + position: absolute; + top: 0; left: 16px; right: 16px; bottom: 16px; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index f292198f1e..8b90de1ef0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -33,6 +33,8 @@ import { DataKeyRowComponent } from '@home/components/widget/config/basic/common import { TimeseriesTableBasicConfigComponent } from '@home/components/widget/config/basic/cards/timeseries-table-basic-config.component'; +import { FlotBasicConfigComponent } from '@home/components/widget/config/basic/chart/flot-basic-config.component'; +import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widget-settings.module'; @NgModule({ declarations: [ @@ -40,12 +42,14 @@ import { SimpleCardBasicConfigComponent, EntitiesTableBasicConfigComponent, TimeseriesTableBasicConfigComponent, + FlotBasicConfigComponent, DataKeyRowComponent, DataKeysPanelComponent ], imports: [ CommonModule, SharedModule, + WidgetSettingsModule, WidgetConfigComponentsModule ], exports: [ @@ -53,6 +57,7 @@ import { SimpleCardBasicConfigComponent, EntitiesTableBasicConfigComponent, TimeseriesTableBasicConfigComponent, + FlotBasicConfigComponent, DataKeyRowComponent, DataKeysPanelComponent ] @@ -63,5 +68,6 @@ export class BasicWidgetConfigModule { export const basicWidgetConfigComponentsMap: {[key: string]: Type} = { 'tb-simple-card-basic-config': SimpleCardBasicConfigComponent, 'tb-entities-table-basic-config': EntitiesTableBasicConfigComponent, - 'tb-timeseries-table-basic-config': TimeseriesTableBasicConfigComponent + 'tb-timeseries-table-basic-config': TimeseriesTableBasicConfigComponent, + 'tb-flot-basic-config': FlotBasicConfigComponent }; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html index aca3394f8c..bc406895c7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html @@ -40,7 +40,7 @@
widget-config.appearance
- + {{ 'widget-config.card-title' | translate }} @@ -63,7 +63,7 @@
-
widgets.table.show-card-buttons
+
widget-config.show-card-buttons
{{ 'action.search' | translate }} {{ 'widgets.table.columns-to-display' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts index b0897f05bc..2061832918 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts @@ -29,6 +29,7 @@ import { import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { isUndefined } from '@core/utils'; +import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; @Component({ selector: 'tb-entities-table-basic-config', @@ -74,11 +75,7 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen protected onConfigSet(configData: WidgetConfigComponentData) { this.entitiesTableWidgetConfigForm = this.fb.group({ - timewindowConfig: [{ - useDashboardTimewindow: configData.config.useDashboardTimewindow, - displayTimewindow: configData.config.displayTimewindow, - timewindow: configData.config.timewindow - }, []], + timewindowConfig: [getTimewindowConfig(configData.config), []], datasources: [configData.config.datasources, []], columns: [this.getColumns(configData.config.datasources), []], showTitle: [configData.config.showTitle, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html index 28cd0aaa6e..5c16b9f195 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html @@ -31,7 +31,7 @@
widget-config.appearance
-
widgets.simple-card.label
+
widgets.simple-card.label
@@ -57,7 +57,7 @@
widget-config.decimals-short
- +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts index b59170fb89..b0e03d66d0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts @@ -27,6 +27,7 @@ import { } from '@shared/models/widget.models'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; @Component({ selector: 'tb-simple-card-basic-config', @@ -63,11 +64,7 @@ export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent { protected onConfigSet(configData: WidgetConfigComponentData) { this.simpleCardWidgetConfigForm = this.fb.group({ - timewindowConfig: [{ - useDashboardTimewindow: configData.config.useDashboardTimewindow, - displayTimewindow: configData.config.useDashboardTimewindow, - timewindow: configData.config.timewindow - }, []], + timewindowConfig: [getTimewindowConfig(configData.config), []], datasources: [configData.config.datasources, []], label: [this.getDataKeyLabel(configData.config.datasources), []], labelPosition: [configData.config.settings?.labelPosition, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html index 158b734a4a..a0c3d64e25 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html @@ -21,6 +21,7 @@
widget-config.appearance
- + {{ 'widget-config.card-title' | translate }} @@ -62,7 +63,7 @@
-
widgets.table.show-card-buttons
+
widget-config.show-card-buttons
{{ 'action.search' | translate }} {{ 'widgets.table.columns-to-display' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts index e650f9a344..ac1b12167c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts @@ -20,15 +20,11 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; -import { - DataKey, - Datasource, - datasourcesHasAggregation, - datasourcesHasOnlyComparisonAggregation, WidgetConfig -} from '@shared/models/widget.models'; +import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { deepClone, isUndefined } from '@core/utils'; +import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; @Component({ selector: 'tb-timeseries-table-basic-config', @@ -65,11 +61,7 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon protected onConfigSet(configData: WidgetConfigComponentData) { this.timeseriesTableWidgetConfigForm = this.fb.group({ - timewindowConfig: [{ - useDashboardTimewindow: configData.config.useDashboardTimewindow, - displayTimewindow: configData.config.displayTimewindow, - timewindow: configData.config.timewindow - }, []], + timewindowConfig: [getTimewindowConfig(configData.config), []], datasources: [configData.config.datasources, []], columns: [this.getColumns(configData.config.datasources), []], showTitle: [configData.config.showTitle, []], @@ -92,11 +84,11 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon this.setColumns(config.columns, this.widgetConfig.config.datasources); this.widgetConfig.config.actions = config.actions; this.widgetConfig.config.showTitle = config.showTitle; - this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; - this.widgetConfig.config.settings.entitiesTitle = config.title; + this.widgetConfig.config.title = config.title; this.widgetConfig.config.showTitleIcon = config.showTitleIcon; this.widgetConfig.config.titleIcon = config.titleIcon; this.widgetConfig.config.iconColor = config.iconColor; + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; this.setCardButtons(config.cardButtons, this.widgetConfig.config); this.widgetConfig.config.color = config.color; this.widgetConfig.config.backgroundColor = config.backgroundColor; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html new file mode 100644 index 0000000000..0fff9342fd --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html @@ -0,0 +1,113 @@ + + + + + + + + +
+
widget-config.card-appearance
+
+ + {{ 'widget-config.card-title' | translate }} + + + + +
+
+ + {{ 'widget-config.card-icon' | translate }} + +
+ + + + + +
+
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.background-color' | translate }}
+
+ + + +
+
+
+
+
widgets.chart.chart-appearance
+
+ + {{ 'widgets.chart.vertical-grid-lines' | translate }} + +
+
+ + {{ 'widgets.chart.horizontal-grid-lines' | translate }} + +
+
+ + + + + {{ 'widget-config.legend' | translate }} + + + + + + + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts new file mode 100644 index 0000000000..7f529c490f --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts @@ -0,0 +1,167 @@ +/// +/// Copyright © 2016-2023 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 } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { isUndefined } from '@core/utils'; +import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; + +@Component({ + selector: 'tb-flot-basic-config', + templateUrl: './flot-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { + + public get datasource(): Datasource { + const datasources: Datasource[] = this.flotWidgetConfigForm.get('datasources').value; + if (datasources && datasources.length) { + return datasources[0]; + } else { + return null; + } + } + + flotWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.flotWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + this.setupDefaultDatasource(configData, + [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }]); + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + this.flotWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + datasources: [configData.config.datasources, []], + series: [this.getSeries(configData.config.datasources), []], + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + showTitleIcon: [configData.config.showTitleIcon, []], + titleIcon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + color: [configData.config.color, []], + backgroundColor: [configData.config.backgroundColor, []], + verticalLines: [configData.config.settings?.grid?.verticalLines, []], + horizontalLines: [configData.config.settings?.grid?.horizontalLines, []], + showLegend: [configData.config.settings?.showLegend, []], + legendConfig: [configData.config.settings?.legendConfig, []], + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; + this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; + this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + this.widgetConfig.config.datasources = config.datasources; + this.setSeries(config.series, this.widgetConfig.config.datasources); + this.widgetConfig.config.actions = config.actions; + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.title = config.title; + this.widgetConfig.config.showTitleIcon = config.showTitleIcon; + this.widgetConfig.config.titleIcon = config.titleIcon; + this.widgetConfig.config.iconColor = config.iconColor; + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.backgroundColor = config.backgroundColor; + this.widgetConfig.config.settings.grid = this.widgetConfig.config.settings.grid || {}; + this.widgetConfig.config.settings.grid.verticalLines = config.verticalLines; + this.widgetConfig.config.settings.grid.horizontalLines = config.horizontalLines; + this.widgetConfig.config.settings.showLegend = config.showLegend; + this.widgetConfig.config.settings.legendConfig = config.legendConfig; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showTitleIcon', 'showLegend']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.flotWidgetConfigForm.get('showTitle').value; + const showTitleIcon: boolean = this.flotWidgetConfigForm.get('showTitleIcon').value; + const showLegend: boolean = this.flotWidgetConfigForm.get('showLegend').value; + if (showTitle) { + this.flotWidgetConfigForm.get('title').enable(); + this.flotWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); + if (showTitleIcon) { + this.flotWidgetConfigForm.get('titleIcon').enable(); + this.flotWidgetConfigForm.get('iconColor').enable(); + } else { + this.flotWidgetConfigForm.get('titleIcon').disable(); + this.flotWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.flotWidgetConfigForm.get('title').disable(); + this.flotWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); + this.flotWidgetConfigForm.get('titleIcon').disable(); + this.flotWidgetConfigForm.get('iconColor').disable(); + } + if (showLegend) { + this.flotWidgetConfigForm.get('legendConfig').enable(); + } else { + this.flotWidgetConfigForm.get('legendConfig').disable(); + } + this.flotWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.flotWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); + this.flotWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); + this.flotWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); + this.flotWidgetConfigForm.get('legendConfig').updateValueAndValidity({emitEvent}); + } + + private getSeries(datasources?: Datasource[]): DataKey[] { + if (datasources && datasources.length) { + return datasources[0].dataKeys || []; + } + return []; + } + + private setSeries(series: DataKey[], datasources?: Datasource[]) { + if (datasources && datasources.length) { + datasources[0].dataKeys = series; + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html index 7bfa1e59b1..e8bc229488 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html @@ -153,7 +153,7 @@
- +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts index 5765a9a64c..b0e52ee758 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts @@ -154,8 +154,7 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan } get hasAdditionalLatestDataKeys(): boolean { - return this.widgetConfigComponent.widgetType === widgetType.timeseries && - this.widgetConfigComponent.modelValue?.typeParameters?.hasAdditionalLatestDataKeys; + return this.dataKeysPanelComponent.hasAdditionalLatestDataKeys; } get widget(): Widget { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts index 171b872a0a..9091f6f895 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.ts @@ -100,6 +100,10 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC @coerceBoolean() hideDataKeyColor = false; + @Input() + @coerceBoolean() + hideSourceSelection = false; + dataKeyType: DataKeyType; alarmKeys: Array; functionTypeKeys: Array; @@ -117,7 +121,7 @@ export class DataKeysPanelComponent implements ControlValueAccessor, OnInit, OnC } get hasAdditionalLatestDataKeys(): boolean { - return this.widgetConfigComponent.widgetType === widgetType.timeseries && + return !this.hideSourceSelection && this.widgetConfigComponent.widgetType === widgetType.timeseries && this.widgetConfigComponent.modelValue?.typeParameters?.hasAdditionalLatestDataKeys; } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html index 6de3c70022..95427dc8db 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
@@ -54,7 +54,7 @@
widget-config.decimals-short
- +
@@ -182,14 +182,12 @@
-
-
- - -
+
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.scss deleted file mode 100644 index 46659e6f4b..0000000000 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.scss +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright © 2016-2023 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-datakey-config { - .fields-group { - padding: 0 16px 8px; - margin-bottom: 10px; - border: 1px groove rgba(0, 0, 0, .25); - border-radius: 4px; - - legend { - color: rgba(0, 0, 0, .7); - width: fit-content; - } - - legend + * { - display: block; - margin-top: 16px; - } - - &.fields-group-slider { - padding: 0; - - legend { - margin-left: 16px; - } - - > .tb-settings { - margin-top: 0; - padding: 0 16px 8px; - } - } - } - - .tb-hint.after-fields { - margin-top: -0.75em; - max-width: fit-content; - line-height: 15px; - } - } -} - -:host ::ng-deep { - .tb-datakey-config { - .mat-expansion-panel { - &.tb-settings { - box-shadow: none; - - .mat-content { - overflow: visible; - } - - .mat-expansion-panel-header { - padding: 0; - color: rgba(0, 0, 0, 0.87); - - &:hover { - background: none; - } - - .mat-expansion-indicator { - padding: 2px; - } - } - - &.comparison { - .mat-expansion-panel-header { - height: fit-content; - } - } - - .mat-expansion-panel-header-description { - align-items: center; - } - - > .mat-expansion-panel-content { - > .mat-expansion-panel-body { - padding: 0; - } - } - } - - .mat-expansion-panel-content { - font: inherit; - } - } - - .mat-slide { - margin: 8px 0; - } - } -} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.ts index e3047f637e..f37451d32d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.ts @@ -57,7 +57,7 @@ import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-data-key-config', templateUrl: './data-key-config.component.html', - styleUrls: ['./data-key-config.component.scss'], + styleUrls: [], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts index ae674a4d55..9900fe90f4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts @@ -69,7 +69,7 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid } public get maxDatasources(): number { - return this.widgetConfigComponent.modelValue?.typeParameters?.maxDatasources; + return this.forceSingleDatasource ? 1 : this.widgetConfigComponent.modelValue?.typeParameters?.maxDatasources; } public get singleDatasource(): boolean { @@ -108,6 +108,10 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid @coerceBoolean() hideDataKeys = false; + @Input() + @coerceBoolean() + forceSingleDatasource = false; + @Input() configMode: WidgetConfigMode; @@ -175,13 +179,20 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid this.datasourcesMode = this.detectDatasourcesMode(datasources); let changed = false; if (datasources) { - datasources.forEach((datasource) => { + let length; + if (this.maxDatasources === -1) { + length = datasources.length; + } else { + length = Math.min(this.maxDatasources, datasources.length); + } + for (let i = 0; i < length; i++) { + const datasource = datasources[i]; if (this.basicMode && datasource.type !== this.datasourcesMode) { datasource.type = this.datasourcesMode; changed = true; } this.datasourcesFormArray.push(this.fb.control(datasource, []), {emitEvent: false}); - }); + } } if (this.singleDatasource && !this.datasourcesFormArray.length) { this.addDatasource(false); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts index 31436c9415..410896dd74 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts @@ -17,10 +17,11 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; -import { widgetType } from '@shared/models/widget.models'; +import { WidgetConfig, widgetType } from '@shared/models/widget.models'; import { Timewindow } from '@shared/models/time/time.models'; import { TranslateService } from '@ngx-translate/core'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { isDefined } from '@core/utils'; export interface TimewindowConfigData { useDashboardTimewindow: boolean; @@ -28,6 +29,14 @@ export interface TimewindowConfigData { timewindow: Timewindow; } +export const getTimewindowConfig = (config: WidgetConfig): TimewindowConfigData => ({ + useDashboardTimewindow: isDefined(config.useDashboardTimewindow) ? + config.useDashboardTimewindow : true, + displayTimewindow: isDefined(config.displayTimewindow) ? + config.displayTimewindow : true, + timewindow: config.timewindow + }); + @Component({ selector: 'tb-timewindow-config-panel', templateUrl: './timewindow-config-panel.component.html', diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-units.component.html b/ui-ngx/src/app/modules/home/components/widget/config/widget-units.component.html index a2ed480388..1381ad31a8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-units.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-units.component.html @@ -15,6 +15,6 @@ limitations under the License. --> - + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html index 888c400b0f..4599a12472 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html @@ -19,20 +19,20 @@
widgets.table.column-settings
-
{{ 'widgets.table.custom-title' | translate }}
+
{{ 'widgets.table.custom-title' | translate }}
{{ 'widgets.table.column-width' | translate }}
- +
{{ 'widgets.table.default-column-visibility' | translate }}
- + {{ 'widgets.table.column-visibility-visible' | translate }} @@ -48,7 +48,7 @@
{{ 'widgets.table.column-selection-to-display' | translate }}
- + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html index e53693c900..266fa4725c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html @@ -19,7 +19,7 @@
widgets.table.table-header
-
{{ 'widgets.table.entities-table-title' | translate }}
+
{{ 'widgets.table.entities-table-title' | translate }}
@@ -31,10 +31,10 @@
widgets.table.header-buttons
- + {{ 'widgets.table.enable-search' | translate }} - + {{ 'widgets.table.enable-select-column-display' | translate }}
@@ -42,7 +42,7 @@
widgets.table.columns
- + {{ 'widgets.table.display-entity-name' | translate }} @@ -50,7 +50,7 @@
- + {{ 'widgets.table.display-entity-label' | translate }} @@ -85,12 +85,12 @@
widgets.table.pagination
- + {{ 'widgets.table.display-pagination' | translate }}
widgets.table.default-page-size
- +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html index 0a878676ba..576cba177e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html @@ -20,7 +20,7 @@
widgets.table.column-settings
{{ 'widgets.table.default-column-visibility' | translate }}
- + {{ 'widgets.table.column-visibility-visible' | translate }} @@ -36,7 +36,7 @@
{{ 'widgets.table.column-selection-to-display' | translate }}
- + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html index dcdc8c2904..d43039ca26 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html @@ -18,18 +18,18 @@
widgets.table.column-settings
- + {{ 'widgets.table.show-latest-data-column' | translate }}
widgets.table.latest-data-column-order
- +
{{ 'widgets.table.default-column-visibility' | translate }}
- + {{ 'widgets.table.column-visibility-visible' | translate }} @@ -45,7 +45,7 @@
{{ 'widgets.table.column-selection-to-display' | translate }}
- + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index 5cbed7da88..138554c8ed 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -18,25 +18,25 @@
widgets.table.table-header
- + {{ 'widgets.table.enable-sticky-header' | translate }} - + {{ 'widgets.table.enable-search' | translate }} - + {{ 'widgets.table.enable-select-column-display' | translate }}
widgets.table.columns
- + {{ 'widgets.table.display-timestamp' | translate }} - + {{ 'widgets.table.display-milliseconds' | translate }} - + {{ 'widgets.table.enable-sticky-action' | translate }} @@ -53,25 +53,25 @@
widgets.table.pagination
- + {{ 'widgets.table.display-pagination' | translate }}
widgets.table.default-page-size
- +
widgets.table.table-tabs
- + {{ 'widgets.table.use-entity-label-tab-name' | translate }}
widgets.table.rows
- + {{ 'widgets.table.hide-empty-lines' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html index 2bebfeef8a..118c41f366 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html @@ -15,81 +15,85 @@ limitations under the License. --> -
-
- widgets.chart.common-settings - + +
+ {{ 'widgets.chart.data-is-hidden-by-default' | translate }} - - + + {{ 'widgets.chart.disable-data-hiding' | translate }} - - + + {{ 'widgets.chart.remove-from-legend' | translate }} - - + + {{ 'widgets.chart.exclude-from-stacking' | translate }} - -
-
- widgets.chart.line-settings + +
+
- - - + + {{ 'widgets.chart.show-line' | translate }} - + widget-config.advanced-settings -
- - widgets.chart.line-width - +
+
{{ 'widgets.chart.line-width' | translate }}
+ + + px - - {{ 'widgets.chart.fill-line' | translate }} - - - widgets.chart.fill-line-opacity - +
+ + {{ 'widgets.chart.fill-line' | translate }} + +
+
{{ 'widgets.chart.fill-line-opacity' | translate }}
+ + -
+
- -
- widgets.chart.points-settings +
+
- - - + + {{ 'widgets.chart.show-points' | translate }} - + widget-config.advanced-settings -
-
- - widgets.chart.points-line-width - - - - widgets.chart.points-radius - - -
- - widgets.chart.point-shape +
+
{{ 'widgets.chart.points-line-width' | translate }}
+ + + px + +
+
+
{{ 'widgets.chart.points-radius' | translate }}
+ + + px + +
+
+
{{ 'widgets.chart.point-shape' | translate }}
+ {{ 'widgets.chart.point-shape-circle' | translate }} @@ -111,19 +115,19 @@ - - -
+
+ + - -
- widgets.chart.tooltip-settings +
+
+
widgets.chart.tooltip-settings
- -
- widgets.chart.yaxis-settings - +
+
+
widgets.chart.vertical-axis
+ {{ 'widgets.chart.show-separate-axis' | translate }} - - widgets.chart.axis-title - - -
- - widgets.chart.min-scale-value - +
+
widgets.chart.axis-title
+ + - - widgets.chart.max-scale-value - +
+
+
widgets.chart.min-scale-value
+ + -
- - widgets.chart.axis-position - - - {{ 'widgets.chart.axis-position-left' | translate }} - - - {{ 'widgets.chart.axis-position-right' | translate }} - - - -
- widgets.chart.yaxis-tick-labels-settings -
- - widgets.chart.tick-step-size - +
+
+
widgets.chart.max-scale-value
+ + + +
+
+
{{ 'widgets.chart.axis-position' | translate }}
+ + + + {{ 'widgets.chart.axis-position-left' | translate }} + + + {{ 'widgets.chart.axis-position-right' | translate }} + + + +
+
+
widgets.chart.ticks
+
+
widget-config.decimals-short
+ + - - widgets.chart.number-of-decimals - +
+
+
widgets.chart.tick-step-size
+ + - +
- - -
- widgets.chart.thresholds -
-
-
- - -
-
-
- widgets.chart.no-thresholds -
-
- +
+
+
+
+
widgets.chart.thresholds
+ +
+
+
+ +
-
+
+
+
widgets.chart.comparison-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts index b2c88e5fcb..f254eaeb2e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.ts @@ -225,6 +225,7 @@ export class FlotKeySettingsComponent extends PageComponent implements OnInit, C this.flotKeySettingsFormGroup.disable({emitEvent: false}); } else { this.flotKeySettingsFormGroup.enable({emitEvent: false}); + this.updateValidators(false); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html index 353e716ad9..43382c439d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html @@ -15,44 +15,38 @@ limitations under the License. --> - - -
- -
-
{{ thresholdText() }}
-
-
-
-
-
- - -
-
- -
- -
- -
- - widgets.chart.line-width - - - - -
+
+ + +
+
{{ thresholdText() }}
+ + + + +
+
+ + +
+ + widgets.chart.line-width + + + +
-
- - + + + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss index 53eeafb799..1b4c3865ab 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss @@ -13,28 +13,58 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -:host { - display: block; + +.tb-flot-threshold { + display: flex; + flex-direction: row; + align-items: start; + gap: 4px; .mat-expansion-panel { box-shadow: none; - &.flot-threshold { - border: 1px groove rgba(0, 0, 0, .25); - .mat-expansion-panel-header { - padding: 0 24px 0 8px; - &.mat-expanded { - height: 48px; + border-radius: 6px; + border: 1px solid rgba(0, 0, 0, 0.12); + .mat-expansion-panel-header { + height: 56px; + border-radius: 0; + display: flex; + flex-direction: row; + align-items: stretch; + .tb-threshold-header { + flex: 1; + display: flex; + flex-direction: row; + gap: 16px; + align-items: center; + padding-left: 16px; + .mat-divider-vertical { + height: 100%; } } + .tb-threshold-text { + flex: 1; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.15px; + } + .mat-expansion-indicator { + margin-right: 22px; + margin-left: 22px; + margin-top: 12px; + } } - } -} - -:host ::ng-deep { - .mat-expansion-panel { - &.flot-threshold { - .mat-expansion-panel-body { - padding: 0 8px 8px; + .mat-expansion-panel-body { + padding: 0 8px 8px; + } + &.mat-expanded { + .mat-expansion-panel-header { + border-bottom: 1px solid rgba(0, 0, 0, 0.12); } } } + .mdc-icon-button { + margin-top: 4px; + color: rgba(0, 0, 0, 0.54); + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts index 9b997ed424..eb55c12f86 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.ts @@ -15,8 +15,14 @@ /// import { ValueSourceProperty } from '@home/components/widget/lib/settings/common/value-source.component'; -import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { Component, EventEmitter, forwardRef, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { + ControlValueAccessor, + NG_VALUE_ACCESSOR, + UntypedFormBuilder, + UntypedFormGroup, + Validators +} from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -28,14 +34,15 @@ import { TbFlotKeyThreshold } from '@home/components/widget/lib/flot-widget.mode @Component({ selector: 'tb-flot-threshold', templateUrl: './flot-threshold.component.html', - styleUrls: ['./flot-threshold.component.scss', './../widget-settings.scss'], + styleUrls: ['./flot-threshold.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FlotThresholdComponent), multi: true } - ] + ], + encapsulation: ViewEncapsulation.None }) export class FlotThresholdComponent extends PageComponent implements OnInit, ControlValueAccessor { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html index 9baf89cbd4..e74126f309 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html @@ -15,35 +15,33 @@ limitations under the License. --> -
-
- widgets.chart.common-settings -
- - {{ 'widgets.chart.enable-stacking-mode' | translate }} - - - {{ 'widgets.chart.enable-selection-mode' | translate }} - -
-
- - widgets.chart.line-shadow-size - + +
+
widgets.chart.common-settings
+ + {{ 'widgets.chart.enable-stacking-mode' | translate }} + + + {{ 'widgets.chart.enable-selection-mode' | translate }} + + + {{ 'widgets.chart.display-smooth-lines' | translate }} + +
+
widgets.chart.line-shadow-size
+ + - - {{ 'widgets.chart.display-smooth-lines' | translate }} - -
-
- - widgets.chart.default-bar-width - +
+
+
widgets.chart.default-bar-width
+ + - - widgets.chart.bar-alignment +
+
+
{{ 'widgets.chart.bar-alignment' | translate }}
+ {{ 'widgets.chart.bar-alignment-left' | translate }} @@ -56,211 +54,255 @@ - -
- - widgets.chart.default-font-size - +
+
+
widgets.chart.thresholds-line-width
+ + - - - - - widgets.chart.thresholds-line-width - - - -
- widget-config.legend +
+
+
{{ 'widgets.chart.default-font' | translate }}
+
+ + + px + + + + +
+
+
+
+
widget-config.legend
- + - - {{ 'widget-config.display-legend' | translate }} + + {{ 'widget-config.legend' | translate }} - + widget-config.advanced-settings - + + - -
- widgets.chart.tooltip-settings +
+
+
widgets.chart.axis
+
+
widgets.chart.vertical-axis
+
+
widgets.chart.axis-title
+ + + +
+
+
widgets.chart.min-scale-value
+ + + +
+
+
widgets.chart.max-scale-value
+ + + +
+
+
widgets.chart.ticks
+ + + + + {{ 'widgets.chart.ticks' | translate }} + + + + widget-config.advanced-settings + + + +
+
{{ 'widget-config.color' | translate }}
+
+ + + +
+
+
+
widget-config.decimals-short
+ + + +
+
+
widgets.chart.tick-step-size
+ + + +
+ + +
+
+
+
+
+
widgets.chart.horizontal-axis
+
+
widgets.chart.axis-title
+ + + +
+
+
widgets.chart.ticks
+ + + + + {{ 'widgets.chart.ticks' | translate }} + + + + widget-config.advanced-settings + + + +
+
{{ 'widget-config.color' | translate }}
+
+ + + +
+
+
+
+
+
+
+
+
widgets.chart.chart-background
+
+ + {{ 'widgets.chart.vertical-grid-lines' | translate }} + +
+
+ + {{ 'widgets.chart.horizontal-grid-lines' | translate }} + +
+
+
{{ 'widgets.chart.grid-lines-color' | translate }}
+
+ + + +
+
+
+
{{ 'widgets.chart.border' | translate }}
+
+ + + px + + + + +
+
+
+
{{ 'widgets.chart.background-color' | translate }}
+
+ + + +
+
+
+
+
widgets.chart.tooltip
- - - + + - {{ 'widgets.chart.show-tooltip' | translate }} + {{ 'widgets.chart.tooltip' | translate }} - + widget-config.advanced-settings -
- +
+ {{ 'widgets.chart.hover-individual-points' | translate }} - +
+
+ {{ 'widgets.chart.show-cumulative-values' | translate }} - +
+
+ {{ 'widgets.chart.hide-zero-false-values' | translate }} - - -
+
+ + - -
- widgets.chart.grid-settings - - {{ 'widgets.chart.show-vertical-lines' | translate }} - - - {{ 'widgets.chart.show-horizontal-lines' | translate }} - - - widgets.chart.grid-outline-border-width - - - - - - - - -
-
- widgets.chart.xaxis-settings - - widgets.chart.axis-title - - -
- widgets.chart.xaxis-tick-labels-settings - - - - - {{ 'widgets.chart.show-tick-labels' | translate }} - - - - widget-config.advanced-settings - - - - - - - -
-
-
- widgets.chart.yaxis-settings - - widgets.chart.axis-title - - -
- - widgets.chart.min-scale-value - - - - widgets.chart.max-scale-value - - -
-
- widgets.chart.yaxis-tick-labels-settings - - - - - {{ 'widgets.chart.show-tick-labels' | translate }} - - - - widget-config.advanced-settings - - - - - -
- - widgets.chart.tick-step-size - - - - widgets.chart.number-of-decimals - - -
- - -
-
-
-
-
- widgets.chart.comparison-settings +
+
+
widgets.chart.comparison-settings
- - - + + {{ 'widgets.chart.enable-comparison' | translate }} - + widget-config.advanced-settings -
- - widgets.chart.time-for-comparison +
+
{{ 'widgets.chart.time-for-comparison' | translate }}
+ {{ 'widgets.chart.time-for-comparison-previous-interval' | translate }} @@ -282,18 +324,29 @@ - - widgets.chart.custom-interval-value - +
+
+
widgets.chart.custom-interval-value
+ + -
- widgets.chart.comparison-x-axis-settings - - widgets.chart.axis-title - +
+
+
widgets.chart.comparison-x-axis-settings
+
+
widgets.chart.axis-title
+ + - - widgets.chart.axis-position +
+
+ + {{ 'widgets.chart.show-tick-labels' | translate }} + +
+
+
{{ 'widgets.chart.axis-position' | translate }}
+ {{ 'widgets.chart.axis-position-top' | translate }} @@ -303,31 +356,28 @@ - - {{ 'widgets.chart.show-tick-labels' | translate }} - - -
+
+
- -
- widgets.chart.custom-legend-settings +
+
+
widgets.chart.custom-legend-settings
- + - + {{ 'widgets.chart.enable-custom-legend' | translate }} - + widget-config.advanced-settings -
- widgets.chart.label-keys-list +
+
widgets.chart.label-keys-list
@@ -353,8 +403,8 @@
-
+
- - +
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts index abcfdeebc3..46454937f6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts @@ -284,6 +284,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit this.flotSettingsFormGroup.disable({emitEvent: false}); } else { this.flotSettingsFormGroup.enable({emitEvent: false}); + this.updateValidators(false); } } @@ -379,9 +380,11 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit } else { this.flotSettingsFormGroup.get('comparisonCustomIntervalValue').disable({emitEvent}); } + this.flotSettingsFormGroup.get('xaxisSecond').enable({emitEvent: false}); } else { this.flotSettingsFormGroup.get('timeForComparison').disable({emitEvent: false}); this.flotSettingsFormGroup.get('comparisonCustomIntervalValue').disable({emitEvent}); + this.flotSettingsFormGroup.get('xaxisSecond').disable({emitEvent: false}); } if (customLegendEnabled) { this.flotSettingsFormGroup.get('dataKeysListForLabels').enable({emitEvent}); @@ -392,6 +395,7 @@ export class FlotWidgetSettingsComponent extends PageComponent implements OnInit this.flotSettingsFormGroup.get('legendConfig').updateValueAndValidity({emitEvent: false}); this.flotSettingsFormGroup.get('timeForComparison').updateValueAndValidity({emitEvent: false}); this.flotSettingsFormGroup.get('comparisonCustomIntervalValue').updateValueAndValidity({emitEvent: false}); + this.flotSettingsFormGroup.get('xaxisSecond').updateValueAndValidity({emitEvent: false}); this.flotSettingsFormGroup.get('dataKeysListForLabels').updateValueAndValidity({emitEvent: false}); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts index 0cd2cad7c7..0cc661cb44 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/label-data-key.component.ts @@ -47,7 +47,7 @@ export function labelDataKeyValidator(control: AbstractControl): ValidationError @Component({ selector: 'tb-label-data-key', templateUrl: './label-data-key.component.html', - styleUrls: ['./label-data-key.component.scss', './../widget-settings.scss'], + styleUrls: ['./label-data-key.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html index f7e2234afd..70663fbad6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html @@ -15,20 +15,21 @@ limitations under the License. --> -
-
- - legend.direction - + +
+
{{ 'legend.direction' | translate }}
+ + {{ legendDirectionTranslations.get(legendDirection[direction]) | translate }} - - legend.position - +
+
+
{{ 'legend.position' | translate }}
+ + @@ -37,28 +38,17 @@
-
- - {{ 'legend.show-min' | translate }} - - - {{ 'legend.show-max' | translate }} - -
-
- - {{ 'legend.show-avg' | translate }} - - - {{ 'legend.show-total' | translate }} - -
-
- - {{ 'legend.show-latest' | translate }} - - - {{ 'legend.sort-legend' | translate }} - +
+
legend.show-values
+ + {{ 'legend.min-option' | translate }} + {{ 'legend.max-option' | translate }} + {{ 'legend.average-option' | translate }} + {{ 'legend.total-option' | translate }} + {{ 'legend.latest-option' | translate }} +
- + + {{ 'legend.sort-legend' | translate }} + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts index c8de7872e8..15b2bbe316 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.ts @@ -15,7 +15,7 @@ /// import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { isDefined } from '@core/utils'; import { LegendConfig, @@ -30,7 +30,7 @@ import { Subscription } from 'rxjs'; @Component({ selector: 'tb-legend-config', templateUrl: './legend-config.component.html', - styleUrls: [], + styleUrls: ['./../widget-settings.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -62,12 +62,8 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc this.legendConfigForm = this.fb.group({ direction: [null, []], position: [null, []], - sortDataKeys: [null, []], - showMin: [null, []], - showMax: [null, []], - showAvg: [null, []], - showTotal: [null, []], - showLatest: [null, []] + showValues: [[], []], + sortDataKeys: [null, []] }); this.legendSettingsFormDirectionChanges$ = this.legendConfigForm.get('direction').valueChanges .subscribe((direction: LegendDirection) => { @@ -121,18 +117,49 @@ export class LegendConfigComponent implements OnInit, OnDestroy, ControlValueAcc this.legendConfigForm.patchValue({ direction: legendConfig.direction, position: legendConfig.position, - sortDataKeys: isDefined(legendConfig.sortDataKeys) ? legendConfig.sortDataKeys : false, - showMin: isDefined(legendConfig.showMin) ? legendConfig.showMin : false, - showMax: isDefined(legendConfig.showMax) ? legendConfig.showMax : false, - showAvg: isDefined(legendConfig.showAvg) ? legendConfig.showAvg : false, - showTotal: isDefined(legendConfig.showTotal) ? legendConfig.showTotal : false, - showLatest: isDefined(legendConfig.showLatest) ? legendConfig.showLatest : false + showValues: this.getShowValues(legendConfig), + sortDataKeys: isDefined(legendConfig.sortDataKeys) ? legendConfig.sortDataKeys : false }, {emitEvent: false}); } this.onDirectionChanged(legendConfig.direction); } private legendConfigUpdated() { - this.propagateChange(this.legendConfigForm.value); + const configValue = this.legendConfigForm.value; + const legendConfig: Partial = { + direction: configValue.direction, + position: configValue.position, + sortDataKeys: configValue.sortDataKeys + }; + this.setShowValues(configValue.showValues, legendConfig); + this.propagateChange(legendConfig); + } + + private getShowValues(legendConfig: LegendConfig): string[] { + const showValues: string[] = []; + if (isDefined(legendConfig.showMin) && legendConfig.showMin) { + showValues.push('min'); + } + if (isDefined(legendConfig.showMax) && legendConfig.showMax) { + showValues.push('max'); + } + if (isDefined(legendConfig.showAvg) && legendConfig.showAvg) { + showValues.push('average'); + } + if (isDefined(legendConfig.showTotal) && legendConfig.showTotal) { + showValues.push('total'); + } + if (isDefined(legendConfig.showLatest) && legendConfig.showLatest) { + showValues.push('latest'); + } + return showValues; + } + + private setShowValues(showValues: string[], legendConfig: Partial) { + legendConfig.showMin = showValues.includes('min'); + legendConfig.showMax = showValues.includes('max'); + legendConfig.showAvg = showValues.includes('average'); + legendConfig.showTotal = showValues.includes('total'); + legendConfig.showLatest = showValues.includes('latest'); } } 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 04c2ee467e..144d29b8b0 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 @@ -36,14 +36,16 @@ {{ 'widget-config.display-title' | translate }} -
- - widget-config.title - +
+
widget-config.title
+ + - - widget-config.title-tooltip - +
+
+
widget-config.title-tooltip
+ +
@@ -55,7 +57,7 @@ [color]="widgetSettings.get('iconColor').value" formControlName="titleIcon"> - + @@ -102,13 +104,13 @@
{{ 'widget-config.padding' | translate }}
- +
{{ 'widget-config.margin' | translate }}
- +
@@ -166,13 +168,13 @@
widget-config.order
- +
widget-config.height
- +
@@ -241,7 +243,7 @@
widget-config.limits
widget-config.data-page-size
- +
@@ -258,12 +260,12 @@
widget-config.decimals
- +
-
widget-config.no-data-display-message
+
widget-config.no-data-display-message
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 55b377dcec..395d727841 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2782,8 +2782,14 @@ "left-side": "Left side layout" }, "legend": { - "direction": "Legend direction", - "position": "Legend position", + "direction": "Direction", + "position": "Position", + "show-values": "Show values", + "min-option": "Min", + "max-option": "Max", + "average-option": "Average", + "total-option": "Total", + "latest-option": "Latest", "sort-legend": "Sort datakeys in legend", "show-max": "Show max value", "show-min": "Show min value", @@ -4250,7 +4256,10 @@ "text": "Text", "background": "Background", "advanced-widget-style": "Advanced widget style", - "card-buttons": "Card buttons" + "card-buttons": "Card buttons", + "show-card-buttons": "Show card buttons", + "card-appearance": "Card appearance", + "color": "Color" }, "widget-type": { "import": "Import widget type", @@ -4273,10 +4282,12 @@ "bar-alignment-left": "Left", "bar-alignment-right": "Right", "bar-alignment-center": "Center", + "default-font": "Default font", "default-font-size": "Default font size", "default-font-color": "Default font color", "thresholds-line-width": "Default line width for all thresholds", "tooltip-settings": "Tooltip settings", + "tooltip": "Tooltip", "show-tooltip": "Show tooltip", "hover-individual-points": "Hover individual points", "show-cumulative-values": "Show cumulative values in stacking mode", @@ -4351,7 +4362,7 @@ "axis-position-right": "Right", "thresholds": "Thresholds", "no-thresholds": "No thresholds configured", - "add-threshold": "Add new threshold", + "add-threshold": "Add threshold", "show-values-for-comparison": "Show historical values for comparison", "comparison-values-label": "Historical values label", "threshold-settings": "Threshold settings", @@ -4372,7 +4383,23 @@ "border-color": "Border color", "legend-settings": "Legend settings", "display-legend": "Display legend", - "labels-font-color": "Labels font color" + "labels-font-color": "Labels font color", + "series": "Series", + "add-series": "Add series", + "series-settings": "Series settings", + "remove-series": "Remove series", + "no-series": "No series configured", + "no-series-error": "At least one series should be specified", + "chart-appearance": "Chart appearance", + "vertical-grid-lines": "Vertical grid lines", + "horizontal-grid-lines": "Horizontal grid lines", + "chart-background": "Chart background", + "grid-lines-color": "Grid lines color", + "border": "Border", + "axis": "Axis", + "vertical-axis": "Vertical axis", + "ticks": "Ticks", + "horizontal-axis": "Horizontal axis" }, "dashboard-state": { "dashboard-state-settings": "Dashboard state settings", @@ -5239,7 +5266,6 @@ "remove-column": "Remove column", "add-column": "Add column", "no-columns": "No columns configured", - "show-card-buttons": "Show card buttons", "columns-to-display": "Columns to display", "table-header": "Table header", "header-buttons": "Header buttons", diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index f4d4192122..bcedae7a1d 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -1212,11 +1212,11 @@ mat-label { &.tb-slide-toggle { padding: 0; gap: 0; - .tb-widget-config-panel-title { + > .tb-widget-config-panel-title { padding-top: 16px; padding-left: 16px; } - .mat-expansion-panel { + > .mat-expansion-panel { padding: 16px; .mat-expansion-panel-header { height: 32px; @@ -1232,7 +1232,7 @@ mat-label { .mat-content { overflow: visible; } - .mat-expansion-panel-header { + > .mat-expansion-panel-header { font-weight: 500; font-size: 16px; line-height: 24px; @@ -1255,12 +1255,15 @@ mat-label { padding: 2px; } } - .mat-expansion-panel-header-description { + > .mat-expansion-panel-header-description { align-items: center; } > .mat-expansion-panel-content { > .mat-expansion-panel-body { - padding: 0; + display: flex; + flex-direction: column; + gap: 16px; + padding: 16px 0 0 !important; } } .tb-json-object-panel, .tb-css-content-panel { @@ -1272,9 +1275,9 @@ mat-label { } } .mat-slide { - margin: 8px 0; - &.no-margin { - margin: 0; + margin: 0; + &.margin { + margin: 8px 0; } .mdc-form-field>label { font-weight: 400; @@ -1313,7 +1316,13 @@ mat-label { height: 56px; } .mat-mdc-form-field { - width: 80px; + width: 106px; + &.medium-width { + width: 220px; + } + } + .fixed-title-width { + min-width: 200px; } } @@ -1341,9 +1350,9 @@ mat-label { } } .mat-mdc-form-field-infix { - padding-top: 7px; - padding-bottom: 7px; - min-height: 38px; + padding-top: 8px; + padding-bottom: 8px; + min-height: 40px; width: auto; .mdc-text-field__input, .mat-mdc-select { font-weight: 400; @@ -1373,6 +1382,14 @@ mat-label { } } } + .mat-mdc-form-field-flex { + .mat-mdc-form-field-icon-suffix { + font-size: 14px; + line-height: 20px; + letter-spacing: 0.2px; + color: rgba(0, 0, 0, 0.38); + } + } } } From 48e781fe2a09dcacf384ed502e04a619be769945 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Sat, 1 Jul 2023 14:02:04 +0300 Subject: [PATCH 184/421] UI: Flot line chart data key settings --- .../add-widget-dialog.component.html | 1 + .../dashboard-page/edit-widget.component.html | 1 + .../chart/flot-key-settings.component.html | 44 +++--- .../chart/flot-threshold.component.html | 18 +-- .../chart/flot-threshold.component.scss | 10 +- .../common/value-source.component.html | 50 +++---- .../settings/common/value-source.component.ts | 14 +- .../widget/widget-preview.component.html | 1 + .../widget/widget-preview.component.ts | 4 + .../components/color-input.component.html | 6 +- .../components/color-input.component.ts | 3 +- .../components/toggle-select.component.html | 24 ++++ .../components/toggle-select.component.ts | 132 ++++++++++++++++++ ui-ngx/src/app/shared/shared.module.ts | 5 + .../assets/locale/locale.constant-en_US.json | 3 +- ui-ngx/src/styles.scss | 12 ++ 16 files changed, 253 insertions(+), 75 deletions(-) create mode 100644 ui-ngx/src/app/shared/components/toggle-select.component.html create mode 100644 ui-ngx/src/app/shared/components/toggle-select.component.ts diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html index 5af51031bf..05e7daee86 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html @@ -57,6 +57,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html index c3d4caca14..db9af1ba06 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html @@ -58,6 +58,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html index 118c41f366..d2339206a5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html @@ -216,35 +216,35 @@
- -
-
- widgets.chart.comparison-settings - +
+
widgets.chart.comparison-settings
+ - - + {{ 'widgets.chart.show-values-for-comparison' | translate }} - - widget-config.advanced-settings - -
- - widgets.chart.comparison-values-label - +
+
widgets.chart.comparison-values-label
+ + - - -
+
+
+
{{ 'widgets.chart.comparison-line-color' | translate }}
+
+ + + +
+
-
-
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html index 43382c439d..0aec3e0084 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html @@ -16,7 +16,7 @@ -->
- +
{{ thresholdText() }}
@@ -29,17 +29,13 @@ -
- - widgets.chart.line-width - +
+
widgets.chart.line-width
+ + + px - - -
+
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts index 6417ae4bcb..603b12bcb5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.ts @@ -14,8 +14,8 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, HostBinding, Input, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -39,7 +39,7 @@ export interface ValueSourceProperty { @Component({ selector: 'tb-value-source', templateUrl: './value-source.component.html', - styleUrls: [], + styleUrls: ['./../widget-settings.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, @@ -50,8 +50,6 @@ export interface ValueSourceProperty { }) export class ValueSourceComponent extends PageComponent implements OnInit, ControlValueAccessor { - @HostBinding('style.display') display = 'block'; - @ViewChild('entityAliasInput') entityAliasInput: ElementRef; @ViewChild('keyInput') keyInput: ElementRef; @@ -212,15 +210,13 @@ export class ValueSourceComponent extends PageComponent implements OnInit, Contr private fetchEntityKeys(entityAliasId: string, dataKeyTypes: Array): Observable> { return this.aliasController.getAliasInfo(entityAliasId).pipe( - mergeMap((aliasInfo) => { - return this.entityService.getEntityKeysByEntityFilter( + mergeMap((aliasInfo) => this.entityService.getEntityKeysByEntityFilter( aliasInfo.entityFilter, dataKeyTypes, [], {ignoreLoading: true, ignoreErrors: true} ).pipe( catchError(() => of([])) - ); - }), + )), catchError(() => of([] as Array)) ); } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html index 870cb08513..9b6c683953 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html @@ -18,6 +18,7 @@ {{icon}} {{label}} -
+
- +
{{ 'widget-config.maximum-datasources' | translate:{count: maxDatasources} }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.html index 985db7d942..5367f03b1f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.html @@ -18,13 +18,10 @@
timewindow.timewindow
- - + + {{ 'widget-config.use-dashboard-timewindow' | translate }} + {{ 'widget-config.use-widget-timewindow' | translate }} +
- + + Ubuntu + MacOS + Windows diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/recent-dashboards-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/recent-dashboards-widget.component.html index ba7614934d..b2a085b917 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/recent-dashboards-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/recent-dashboards-widget.component.html @@ -20,16 +20,9 @@
{{ 'widgets.recent-dashboards.title' | translate }}
- + + {{ 'widgets.recent-dashboards.last' | translate }} + {{ 'widgets.recent-dashboards.starred' | translate }} {{ 'dashboard.add' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.html index a0beeacdb2..61e7c448b4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/usage-info-widget.component.html @@ -19,16 +19,9 @@
{{ 'widgets.usage-info.title' | translate }} - + + {{ 'widgets.usage-info.entities' | translate }} + {{ 'widgets.usage-info.api-calls' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts index d91baebb53..af32954e62 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/label-widget-label.component.ts @@ -33,7 +33,7 @@ export interface LabelWidgetLabel { @Component({ selector: 'tb-label-widget-label', templateUrl: './label-widget-label.component.html', - styleUrls: ['./label-widget-label.component.scss', './../widget-settings.scss'], + styleUrls: ['./label-widget-label.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html index 61f1587306..bd5d69a594 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html @@ -15,34 +15,37 @@ limitations under the License. --> -
-
- widgets.chart.threshold-settings - + +
+
widgets.chart.threshold-settings
+ - {{ 'widgets.chart.use-as-threshold' | translate }} - - widget-config.advanced-settings - -
- - widgets.chart.threshold-line-width - +
+
widgets.chart.threshold-line-width
+ + + px - - -
+
+
+
{{ 'widgets.chart.threshold-color' | translate }}
+
+ + + +
+
-
-
+
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/fixed-color-level.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/fixed-color-level.component.ts index 9baad9677c..8bd92dca8a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/fixed-color-level.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/fixed-color-level.component.ts @@ -50,7 +50,7 @@ export function fixedColorLevelValidator(control: AbstractControl): ValidationEr @Component({ selector: 'tb-fixed-color-level', templateUrl: './fixed-color-level.component.html', - styleUrls: ['./fixed-color-level.component.scss', './../widget-settings.scss'], + styleUrls: ['./fixed-color-level.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts index 33f44f0111..e5c1ec9fbc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/gauge-highlight.component.ts @@ -31,7 +31,7 @@ export interface GaugeHighlight { @Component({ selector: 'tb-gauge-highlight', templateUrl: './gauge-highlight.component.html', - styleUrls: ['./gauge-highlight.component.scss', './../widget-settings.scss'], + styleUrls: ['./gauge-highlight.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts index ef334d6ee2..51665a3afa 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gauge/tick-value.component.ts @@ -27,7 +27,7 @@ import { IAliasController } from '@core/api/widget-api.models'; @Component({ selector: 'tb-tick-value', templateUrl: './tick-value.component.html', - styleUrls: ['./tick-value.component.scss', './../widget-settings.scss'], + styleUrls: ['./tick-value.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts index d6e6d675ad..636fd9f0fe 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gpio/gpio-item.component.ts @@ -56,7 +56,7 @@ export const gpioItemValidator = (hasColor: boolean): ValidatorFn => (control: A @Component({ selector: 'tb-gpio-item', templateUrl: './gpio-item.component.html', - styleUrls: ['./gpio-item.component.scss', './../widget-settings.scss'], + styleUrls: ['./gpio-item.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts index a546537bf7..1d304aef64 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/datakey-select-option.component.ts @@ -46,7 +46,7 @@ export const dataKeySelectOptionValidator = (control: AbstractControl) => { @Component({ selector: 'tb-datakey-select-option', templateUrl: './datakey-select-option.component.html', - styleUrls: ['./datakey-select-option.component.scss', './../widget-settings.scss'], + styleUrls: ['./datakey-select-option.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, 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 144d29b8b0..5cddfd4639 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 @@ -17,9 +17,9 @@ -->
- - + +
diff --git a/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw b/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw index 9205fddf71..6f9215b4f9 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw +++ b/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw @@ -48,7 +48,7 @@ "padding": "16px", "settings": { "useMarkdownTextFunction": false, - "markdownTextPattern": "
\n
\n
{{ 'widgets.activity.title' | translate }}
\n \n \n
\n \n \n \n \n \n \n \n \n
", + "markdownTextPattern": "
\n
\n
{{ 'widgets.activity.title' | translate }}
\n \n {{ 'device.devices' | translate }}\n {{ 'widgets.transport-messages.title' | translate }}\n \n
\n \n \n \n \n \n \n \n \n
", "applyDefaultMarkdownStyle": false, "markdownCss": ".tb-card-content {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n}\n" }, @@ -1101,4 +1101,4 @@ }, "externalId": null, "name": "Tenant Administrator Home Page" -} \ No newline at end of file +} diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.ts b/ui-ngx/src/app/shared/components/toggle-header.component.ts index a7f37f53a4..15c82f6470 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.ts +++ b/ui-ngx/src/app/shared/components/toggle-header.component.ts @@ -16,29 +16,26 @@ import { AfterContentInit, - AfterViewInit, ChangeDetectorRef, Component, - ContentChildren, EventEmitter, + ContentChildren, + Directive, + ElementRef, + EventEmitter, Input, - OnInit, Output, - QueryList, - ViewChild + OnDestroy, + OnInit, + Output, + QueryList } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { AdminService } from '@core/http/admin.service'; -import { UpdateMessage } from '@shared/models/settings.models'; -import { getCurrentAuthUser } from '@core/auth/auth.selectors'; -import { Authority } from '@shared/models/authority.enum'; -import { of, Subscription } from 'rxjs'; -import { MatStepper } from '@angular/material/stepper'; -import { MatButtonToggle, MatButtonToggleGroup } from '@angular/material/button-toggle'; +import { Subject, Subscription } from 'rxjs'; import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; import { coerceBoolean } from '@shared/decorators/coercion'; -import { BreadCrumb } from '@shared/components/breadcrumb'; +import { startWith, takeUntil } from 'rxjs/operators'; export interface ToggleHeaderOption { name: string; @@ -47,12 +44,72 @@ export interface ToggleHeaderOption { export type ToggleHeaderAppearance = 'fill' | 'fill-invert' | 'stroked'; +@Directive( + { + // eslint-disable-next-line @angular-eslint/directive-selector + selector: 'tb-toggle-option', + } +) +// eslint-disable-next-line @angular-eslint/directive-class-suffix +export class ToggleOption { + + @Input() value: any; + + get viewValue(): string { + return (this._element?.nativeElement.textContent || '').trim(); + } + + constructor( + private _element: ElementRef + ) {} +} + +@Directive() +export abstract class _ToggleBase extends PageComponent implements AfterContentInit, OnDestroy { + + @ContentChildren(ToggleOption) toggleOptions: QueryList; + + @Input() + options: ToggleHeaderOption[] = []; + + private _destroyed = new Subject(); + + protected constructor(protected store: Store) { + super(store); + } + + ngAfterContentInit(): void { + this.toggleOptions.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => { + this.syncToggleHeaderOptions(); + }); + } + + ngOnDestroy() { + this._destroyed.next(); + this._destroyed.complete(); + } + + private syncToggleHeaderOptions() { + if (this.toggleOptions?.length) { + this.options.length = 0; + this.toggleOptions.forEach(option => { + this.options.push( + { name: option.viewValue, + value: option.value + } + ); + }); + } + } + +} + @Component({ selector: 'tb-toggle-header', templateUrl: './toggle-header.component.html', styleUrls: ['./toggle-header.component.scss'] }) -export class ToggleHeaderComponent extends PageComponent implements OnInit { +export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterContentInit, OnDestroy { @Input() value: any; @@ -60,9 +117,6 @@ export class ToggleHeaderComponent extends PageComponent implements OnInit { @Output() valueChange = new EventEmitter(); - @Input() - options: ToggleHeaderOption[]; - @Input() name: string; diff --git a/ui-ngx/src/app/shared/components/toggle-select.component.html b/ui-ngx/src/app/shared/components/toggle-select.component.html index 54c845b35b..20ef606288 100644 --- a/ui-ngx/src/app/shared/components/toggle-select.component.html +++ b/ui-ngx/src/app/shared/components/toggle-select.component.html @@ -18,6 +18,7 @@ diff --git a/ui-ngx/src/app/shared/components/toggle-select.component.ts b/ui-ngx/src/app/shared/components/toggle-select.component.ts index 3e9d74f3fa..7fd94485f8 100644 --- a/ui-ngx/src/app/shared/components/toggle-select.component.ts +++ b/ui-ngx/src/app/shared/components/toggle-select.component.ts @@ -14,45 +14,11 @@ /// limitations under the License. /// -import { - AfterContentInit, - ChangeDetectorRef, - Component, - ContentChildren, - Directive, - ElementRef, - forwardRef, - Input, - OnDestroy, - QueryList -} from '@angular/core'; -import { PageComponent } from '@shared/components/page.component'; +import { Component, forwardRef, Input } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { Subject } from 'rxjs'; -import { startWith, takeUntil } from 'rxjs/operators'; -import { ToggleHeaderOption } from '@shared/components/toggle-header.component'; - -@Directive( - { - // eslint-disable-next-line @angular-eslint/directive-selector - selector: 'tb-toggle-option', - } -) -// eslint-disable-next-line @angular-eslint/directive-class-suffix -export class ToggleSelectOption { - - @Input() value: any; - - get viewValue(): string { - return (this._element?.nativeElement.textContent || '').trim(); - } - - constructor( - private _element: ElementRef - ) {} -} +import { _ToggleBase, ToggleHeaderAppearance } from '@shared/components/toggle-header.component'; @Component({ selector: 'tb-toggle-select', @@ -66,37 +32,22 @@ export class ToggleSelectOption { } ] }) -export class ToggleSelectComponent extends PageComponent implements AfterContentInit, OnDestroy, ControlValueAccessor { - - @ContentChildren(ToggleSelectOption) toggleSelectOptions: QueryList; +export class ToggleSelectComponent extends _ToggleBase implements ControlValueAccessor { @Input() disabled: boolean; - options: ToggleHeaderOption[] = []; - - private _destroyed = new Subject(); + @Input() + appearance: ToggleHeaderAppearance = 'stroked'; modelValue: any; private propagateChange = null; - constructor(protected store: Store, - private cd: ChangeDetectorRef) { + constructor(protected store: Store) { super(store); } - ngAfterContentInit(): void { - this.toggleSelectOptions.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => { - this.syncToggleHeaderOptions(); - }); - } - - ngOnDestroy() { - this._destroyed.next(); - this._destroyed.complete(); - } - registerOnChange(fn: any): void { this.propagateChange = fn; } @@ -112,19 +63,6 @@ export class ToggleSelectComponent extends PageComponent implements AfterContent this.modelValue = value; } - private syncToggleHeaderOptions() { - this.options.length = 0; - if (this.toggleSelectOptions) { - this.toggleSelectOptions.forEach(selectOption => { - this.options.push( - { name: selectOption.viewValue, - value: selectOption.value - } - ); - }); - } - } - updateModel(value: any) { this.modelValue = value; this.propagateChange(this.modelValue); diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 6fc9850717..cf8b271171 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -191,9 +191,9 @@ import { import { ColorPickerComponent } from '@shared/components/color-picker/color-picker.component'; import { ResourceAutocompleteComponent } from '@shared/components/resource/resource-autocomplete.component'; import { ShortNumberPipe } from '@shared/pipe/short-number.pipe'; -import { ToggleHeaderComponent } from '@shared/components/toggle-header.component'; +import { ToggleHeaderComponent, ToggleOption } from '@shared/components/toggle-header.component'; import { RuleChainSelectComponent } from '@shared/components/rule-chain/rule-chain-select.component'; -import { ToggleSelectComponent, ToggleSelectOption } from '@shared/components/toggle-select.component'; +import { ToggleSelectComponent } from '@shared/components/toggle-select.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -365,7 +365,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ColorPickerComponent, ResourceAutocompleteComponent, ToggleHeaderComponent, - ToggleSelectOption, + ToggleOption, ToggleSelectComponent, RuleChainSelectComponent ], @@ -595,7 +595,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ColorPickerComponent, ResourceAutocompleteComponent, ToggleHeaderComponent, - ToggleSelectOption, + ToggleOption, ToggleSelectComponent, RuleChainSelectComponent ] From 552be228a35ad49ca0d8939a25a12324457cd1e7 Mon Sep 17 00:00:00 2001 From: rusikv Date: Mon, 3 Jul 2023 17:13:11 +0300 Subject: [PATCH 188/421] Refactoring --- .../script/node-script-test.service.ts | 6 ++- .../components/details-panel.component.ts | 5 -- .../entity/entities-table.component.ts | 4 ++ .../components/event/event-table-config.ts | 45 +++++++++-------- .../components/event/event-table.component.ts | 36 ++++++++------ .../entity/entity-table-component.models.ts | 1 + .../rulechain/rule-node-config.component.ts | 25 ++++++---- .../rule-node-details.component.html | 2 +- .../rulechain/rule-node-details.component.ts | 7 ++- .../rulechain/rulechain-page.component.html | 9 ++-- .../rulechain/rulechain-page.component.ts | 27 +++++++---- .../src/app/shared/models/rule-node.models.ts | 48 ++++++++----------- .../assets/locale/locale.constant-en_US.json | 10 +--- 13 files changed, 118 insertions(+), 107 deletions(-) diff --git a/ui-ngx/src/app/core/services/script/node-script-test.service.ts b/ui-ngx/src/app/core/services/script/node-script-test.service.ts index c3e0da73ad..fa30934f06 100644 --- a/ui-ngx/src/app/core/services/script/node-script-test.service.ts +++ b/ui-ngx/src/app/core/services/script/node-script-test.service.ts @@ -61,7 +61,8 @@ export class NodeScriptTestService { try { msg = JSON.parse(eventBody.data); } catch (e) {} - } else { + } + if (!msg) { msg = { temperature: 22.4, humidity: 78 @@ -71,7 +72,8 @@ export class NodeScriptTestService { try { metadata = JSON.parse(eventBody.metadata); } catch (e) {} - } else { + } + if (!metadata) { metadata = { deviceName: 'Test Device', deviceType: 'default', diff --git a/ui-ngx/src/app/modules/home/components/details-panel.component.ts b/ui-ngx/src/app/modules/home/components/details-panel.component.ts index ac8d6e3bc3..66facf08d4 100644 --- a/ui-ngx/src/app/modules/home/components/details-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/details-panel.component.ts @@ -56,9 +56,6 @@ export class DetailsPanelComponent extends PageComponent implements OnDestroy { this.theFormValue = value; if (this.theFormValue !== null) { this.formSubscription = this.theFormValue.valueChanges.subscribe(() => { - if (this.isReadOnly) { - this.switchToFirstTab.emit(); - } this.cd.detectChanges() }); } @@ -77,8 +74,6 @@ export class DetailsPanelComponent extends PageComponent implements OnDestroy { applyDetails = new EventEmitter(); @Output() closeSearch = new EventEmitter(); - @Output() - switchToFirstTab = new EventEmitter() isEditValue = false; showSearchPane = false; diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts index b868fd1e47..46a7c966c8 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.ts @@ -637,6 +637,10 @@ export class EntitiesTableComponent extends PageComponent implements IEntitiesTa } } + cellActionDescriptorsUpdated() { + this.cellActionDescriptors = [...this.entitiesTableConfig.cellActionDescriptors]; + } + headerCellStyle(column: EntityColumn>) { const index = this.entitiesTableConfig.columns.indexOf(column); let res = this.headerCellStyleCache[index]; diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 51bd99fde0..7382633e33 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -30,7 +30,7 @@ import { EntityId } from '@shared/models/id/entity-id'; import { EventService } from '@app/core/http/event.service'; import { EventTableHeaderComponent } from '@home/components/event/event-table-header.component'; import { EntityTypeResource } from '@shared/models/entity-type.models'; -import { BehaviorSubject, Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { PageData } from '@shared/models/page/page-data'; import { Direction } from '@shared/models/page/sort-order'; import { DialogService } from '@core/services/dialog.service'; @@ -41,7 +41,7 @@ import { } from '@home/components/event/event-content-dialog.component'; import { isEqual, sortObjectKeys } from '@core/utils'; import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; -import { ChangeDetectorRef, Injector, StaticProvider, ViewContainerRef } from '@angular/core'; +import { ChangeDetectorRef, EventEmitter, Injector, StaticProvider, ViewContainerRef } from '@angular/core'; import { ComponentPortal } from '@angular/cdk/portal'; import { EVENT_FILTER_PANEL_DATA, @@ -50,7 +50,6 @@ import { FilterEntityColumn } from '@home/components/event/event-filter-panel.component'; import { NodeScriptTestService } from '@core/services/script/node-script-test.service'; -import { ruleNodeClazzFunctionNameTranslations } from '@shared/models/rule-node.models'; export class EventTableConfig extends EntityTableConfig { @@ -63,6 +62,7 @@ export class EventTableConfig extends EntityTableConfig { set eventType(eventType: EventType | DebugEventType) { if (this.eventTypeValue !== eventType) { this.eventTypeValue = eventType; + this.updateCellAction(); this.updateColumns(true); this.updateFilterColumns(); } @@ -74,8 +74,6 @@ export class EventTableConfig extends EntityTableConfig { eventTypes: Array; - debugEventSelectedSubject = new BehaviorSubject(null); - constructor(private eventService: EventService, private dialogService: DialogService, private translate: TranslateService, @@ -90,9 +88,8 @@ export class EventTableConfig extends EntityTableConfig { private viewContainerRef: ViewContainerRef, private cd: ChangeDetectorRef, private nodeScriptTestService: NodeScriptTestService, - private isRuleNodeDebugModeEnabled: boolean, - private editingRuleNodeHasScript: boolean, - private rulenodeClazz: string) { + public testButtonLabel?: string, + private debugEventSelected?: EventEmitter) { super(); this.loadDataOnInit = false; this.tableTitle = ''; @@ -128,6 +125,7 @@ export class EventTableConfig extends EntityTableConfig { this.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC}; this.updateColumns(); + this.updateCellAction(); this.updateFilterColumns(); this.headerActionDescriptors.push({ @@ -325,18 +323,6 @@ export class EventTableConfig extends EntityTableConfig { onAction: ($event, entity) => this.showContent($event, entity.body.error, 'event.error') }, - '48px'), - new EntityActionTableColumn('test', '', - { - name: this.translate.instant('rulenode.test-function', - {function: this.translate.instant(ruleNodeClazzFunctionNameTranslations[this.rulenodeClazz])}), - icon: 'bug_report', - isEnabled: (entity) => this.isRuleNodeDebugModeEnabled && entity.body.type === 'IN' && - this.editingRuleNodeHasScript, - onAction: ($event, entity) => { - this.debugEventSelectedSubject.next(entity.body); - } - }, '48px') ); break; @@ -369,6 +355,25 @@ export class EventTableConfig extends EntityTableConfig { } } + updateCellAction() { + this.cellActionDescriptors = []; + switch (this.eventType) { + case DebugEventType.DEBUG_RULE_NODE: + if (this.testButtonLabel) { + this.cellActionDescriptors.push({ + name: this.translate.instant('rulenode.test-with-this-message', {test: this.testButtonLabel}), + icon: 'bug_report', + isEnabled: (entity) => entity.body.type === 'IN', + onAction: ($event, entity) => { + this.debugEventSelected.next(entity.body); + } + }); + } + break; + } + this.getTable()?.cellActionDescriptorsUpdated(); + } + showContent($event: MouseEvent, content: string, title: string, contentType: ContentType = null, sortKeys = false): void { if ($event) { $event.stopPropagation(); diff --git a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts index 4781b4811d..80394de979 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table.component.ts @@ -36,6 +36,7 @@ import { DebugEventType, DebugRuleNodeEventBody, EventType } from '@shared/model import { Overlay } from '@angular/cdk/overlay'; import { Subscription } from 'rxjs'; import { NodeScriptTestService } from '@core/services/script/node-script-test.service'; +import { isNotEmptyStr } from '@core/utils'; @Component({ selector: 'tb-event-table', @@ -60,6 +61,10 @@ export class EventTableComponent implements OnInit, AfterViewInit, OnDestroy { dirtyValue = false; entityIdValue: EntityId; + get active(): boolean { + return this.activeValue; + } + @Input() set active(active: boolean) { if (this.activeValue !== active) { @@ -84,14 +89,24 @@ export class EventTableComponent implements OnInit, AfterViewInit, OnDestroy { } } - @Input() - isRuleNodeDebugModeEnabled: boolean; + private ruleNodeTestButtonLabelValue: string; - @Input() - editingRuleNodeHasScript: boolean; + get ruleNodeTestButtonLabel(): string { + return this.ruleNodeTestButtonLabelValue; + } @Input() - rulenodeClazz: string; + set ruleNodeTestButtonLabel(value: string) { + if (isNotEmptyStr(value)) { + this.ruleNodeTestButtonLabelValue = value; + } else { + this.ruleNodeTestButtonLabelValue = ''; + } + if (this.eventTableConfig) { + this.eventTableConfig.testButtonLabel = this.ruleNodeTestButtonLabel; + this.eventTableConfig.updateCellAction(); + } + } @Output() debugEventSelected = new EventEmitter(null); @@ -130,16 +145,9 @@ export class EventTableComponent implements OnInit, AfterViewInit, OnDestroy { this.viewContainerRef, this.cd, this.nodeScriptTestService, - this.isRuleNodeDebugModeEnabled, - this.editingRuleNodeHasScript, - this.rulenodeClazz + this.ruleNodeTestButtonLabel, + this.debugEventSelected ); - - this.eventTableConfig.debugEventSelectedSubject.subscribe((debugEventBody: DebugRuleNodeEventBody) => { - if (debugEventBody) { - this.debugEventSelected.emit(debugEventBody); - } - }) } ngAfterViewInit() { diff --git a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts index 033747f6d3..a6e5ada7bf 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entity-table-component.models.ts @@ -80,6 +80,7 @@ export interface IEntitiesTableComponent { exitFilterMode(): void; resetSortAndFilter(update?: boolean, preserveTimewindow?: boolean): void; columnsUpdated(resetData?: boolean): void; + cellActionDescriptorsUpdated(): void; headerCellStyle(column: EntityColumn>): any; clearCellCache(col: number, row: number): void; cellContent(entity: BaseData, column: EntityColumn>, row: number): any; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts index 788a495607..6c19507301 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts @@ -18,14 +18,22 @@ import { AfterViewInit, Component, ComponentRef, + EventEmitter, forwardRef, Input, OnDestroy, OnInit, + Output, ViewChild, ViewContainerRef } from '@angular/core'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { + ControlValueAccessor, + NG_VALUE_ACCESSOR, + UntypedFormBuilder, + UntypedFormGroup, + Validators +} from '@angular/forms'; import { IRuleNodeConfigurationComponent, RuleNodeConfiguration, @@ -38,7 +46,6 @@ import { TranslateService } from '@ngx-translate/core'; import { JsonObjectEditComponent } from '@shared/components/json-object-edit.component'; import { deepClone } from '@core/utils'; import { RuleChainType } from '@shared/models/rule-chain.models'; -import { DebugRuleNodeEventBody } from '@shared/models/event.models'; @Component({ selector: 'tb-rule-node-config', @@ -77,6 +84,9 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On @Input() ruleChainType: RuleChainType; + @Output() + initRuleNode = new EventEmitter(); + nodeDefinitionValue: RuleNodeDefinition; @Input() @@ -86,6 +96,7 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On if (this.nodeDefinitionValue) { this.validateDefinedDirective(); } + setTimeout(() => this.initRuleNode.emit()); } } @@ -93,21 +104,15 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On return this.nodeDefinitionValue; } - @Input() - set debugEventBody(debugEventBody: DebugRuleNodeEventBody) { - if (debugEventBody) { - this.definedConfigComponent?.testScript(debugEventBody); - } - } - definedDirectiveError: string; ruleNodeConfigFormGroup: UntypedFormGroup; changeSubscription: Subscription; + definedConfigComponent: IRuleNodeConfigurationComponent; + private definedConfigComponentRef: ComponentRef; - private definedConfigComponent: IRuleNodeConfigurationComponent; private configuration: RuleNodeConfiguration; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html index c215b0d21d..2f925ded60 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html @@ -51,7 +51,7 @@ [ruleChainId]="ruleChainId" [ruleChainType]="ruleChainType" [nodeDefinition]="ruleNode.component.configurationDescriptor.nodeDefinition" - [debugEventBody]="debugEventBody"> + (initRuleNode)="initRuleNode.emit($event)">
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts index 455e70270c..7b0f426c35 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -27,7 +27,6 @@ import { RuleNodeConfigComponent } from './rule-node-config.component'; import { Router } from '@angular/router'; import { RuleChainType } from '@app/shared/models/rule-chain.models'; import { ComponentClusteringMode } from '@shared/models/component-descriptor.models'; -import { DebugRuleNodeEventBody } from '@shared/models/event.models'; @Component({ selector: 'tb-rule-node', @@ -56,8 +55,8 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O @Input() isAdd = false; - @Input() - debugEventBody: DebugRuleNodeEventBody; + @Output() + initRuleNode = new EventEmitter(); ruleNodeType = RuleNodeType; entityType = EntityType; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html index 15695d9d87..5e20a6a8e2 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html @@ -100,8 +100,7 @@ (closeDetails)="onEditRuleNodeClosed()" (toggleDetailsEditMode)="onRevertRuleNodeEdit()" (applyDetails)="saveRuleNode()" - [theForm]="tbRuleNode.ruleNodeFormGroup" - (switchToFirstTab)="onSwitchToFirstTab()"> + [theForm]="tbRuleNode.ruleNodeFormGroup">
@@ -113,7 +112,7 @@ [ruleChainType]="ruleChainType" [isEdit]="true" [isReadOnly]="false" - [debugEventBody]="debugEventBody"> + (initRuleNode)="onRuleNodeInit()"> @@ -122,9 +121,7 @@ [active]="eventsTab.isActive" [tenantId]="ruleChain.tenantId.id" [entityId]="editingRuleNode.ruleNodeId" - [isRuleNodeDebugModeEnabled]="editingRuleNode?.debugMode" - [editingRuleNodeHasScript]="editingRuleNodeHasScript" - [rulenodeClazz]="editingRuleNode.component.clazz" + [ruleNodeTestButtonLabel]="ruleNodeTestButtonLabel" (debugEventSelected)="onDebugEventSelected($event)"> diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index ff9d9060c8..d5ea093721 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -153,8 +153,7 @@ export class RuleChainPageComponent extends PageComponent editingRuleNodeAllowCustomLabels = false; editingRuleNodeLinkLabels: {[label: string]: LinkLabel}; editingRuleNodeSourceRuleChainId: string; - debugEventBody: DebugRuleNodeEventBody; - editingRuleNodeHasScript: boolean = false; + ruleNodeTestButtonLabel: string; @ViewChild('tbRuleNode') ruleNodeComponent: RuleNodeDetailsComponent; @ViewChild('tbRuleNodeLink') ruleNodeLinkComponent: RuleNodeLinkComponent; @@ -1112,7 +1111,6 @@ export class RuleChainPageComponent extends PageComponent this.isEditingRuleNode = true; this.editingRuleNodeIndex = this.ruleChainModel.nodes.indexOf(node); this.editingRuleNode = deepClone(node, ['component']); - this.editingRuleNodeHasScript = this.editingRuleNode.configuration.hasOwnProperty('scriptLang'); setTimeout(() => { this.ruleNodeComponent.ruleNodeFormGroup.markAsPristine(); }, 0); @@ -1261,7 +1259,6 @@ export class RuleChainPageComponent extends PageComponent onEditRuleNodeClosed() { this.editingRuleNode = null; this.isEditingRuleNode = false; - this.debugEventBody = null; } onEditRuleNodeLinkClosed() { @@ -1282,13 +1279,25 @@ export class RuleChainPageComponent extends PageComponent } onDebugEventSelected(debugEventBody: DebugRuleNodeEventBody) { - if (debugEventBody) { - this.debugEventBody = debugEventBody; - } + if (this.ruleNodeComponent.ruleNodeConfigComponent.useDefinedDirective() && + this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.getSupportTestFunction() && + this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.testScript$) { + this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.testScript$(debugEventBody) + .subscribe((value) => { + if (value) { + this.selectedRuleNodeTabIndex = 0; + } + }) + } } - onSwitchToFirstTab() { - this.selectedRuleNodeTabIndex = 0; + onRuleNodeInit() { + if (this.ruleNodeComponent.ruleNodeConfigComponent.useDefinedDirective() && + this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.getSupportTestFunction()) { + this.ruleNodeTestButtonLabel = this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.getTestButtonLabel(); + } else { + this.ruleNodeTestButtonLabel = ''; + } } saveRuleNode() { diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index 84ea8ddd3e..dd427aaf09 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -27,6 +27,7 @@ import { AppState } from '@core/core.state'; import { AbstractControl, UntypedFormGroup } from '@angular/forms'; import { RuleChainType } from '@shared/models/rule-chain.models'; import { DebugRuleNodeEventBody } from '@shared/models/event.models'; +import { TranslateService } from '@ngx-translate/core'; export interface RuleNodeConfiguration { [key: string]: any; @@ -76,7 +77,9 @@ export interface IRuleNodeConfigurationComponent { configuration: RuleNodeConfiguration; configurationChanged: Observable; validate(); - testScript? (debugEventBody: DebugRuleNodeEventBody); + getSupportTestFunction(): boolean; + getTestButtonLabel? (): string; + testScript$? (debugEventBody?: DebugRuleNodeEventBody): Observable; [key: string]: any; } @@ -112,7 +115,8 @@ export abstract class RuleNodeConfigurationComponent extends PageComponent imple configurationChangedEmiter = new EventEmitter(); configurationChanged = this.configurationChangedEmiter.asObservable(); - protected constructor(@Inject(Store) protected store: Store) { + protected constructor(@Inject(Store) protected store: Store, + @Inject(TranslateService) protected translate: TranslateService) { super(store); } @@ -130,6 +134,14 @@ export abstract class RuleNodeConfigurationComponent extends PageComponent imple this.onValidate(); } + getSupportTestFunction(): boolean { + return false; + } + + getTestButtonLabel(): string { + return this.translate.instant('rulenode.test-script-function'); + } + protected setupConfiguration(configuration: RuleNodeConfiguration) { this.onConfigurationSet(this.prepareInputConfig(configuration)); this.updateValidators(false); @@ -429,22 +441,13 @@ export const messageTypeNames = new Map( export const ruleChainNodeClazz = 'org.thingsboard.rule.engine.flow.TbRuleChainInputNode'; export const outputNodeClazz = 'org.thingsboard.rule.engine.flow.TbRuleChainOutputNode'; -export enum RuleNodeClazz { - TbJsFilterNode = 'org.thingsboard.rule.engine.filter.TbJsFilterNode', - TbLogNode = 'org.thingsboard.rule.engine.action.TbLogNode', - TbJsSwitchNode = 'org.thingsboard.rule.engine.filter.TbJsSwitchNode', - TbClearAlarmNode = 'org.thingsboard.rule.engine.action.TbClearAlarmNode', - TbCreateAlarmNode = 'org.thingsboard.rule.engine.action.TbCreateAlarmNode', - TbTransformMsgNode = 'org.thingsboard.rule.engine.transform.TbTransformMsgNode', - TbMsgGeneratorNode = 'org.thingsboard.rule.engine.debug.TbMsgGeneratorNode' -} const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.filter.TbCheckRelationNode': 'ruleNodeCheckRelation', 'org.thingsboard.rule.engine.filter.TbCheckMessageNode': 'ruleNodeCheckExistenceFields', 'org.thingsboard.rule.engine.geo.TbGpsGeofencingFilterNode': 'ruleNodeGpsGeofencingFilter', - [RuleNodeClazz.TbJsFilterNode]: 'ruleNodeJsFilter', - [RuleNodeClazz.TbJsSwitchNode]: 'ruleNodeJsSwitch', + 'org.thingsboard.rule.engine.filter.TbJsFilterNode': 'ruleNodeJsFilter', + 'org.thingsboard.rule.engine.filter.TbJsSwitchNode': 'ruleNodeJsSwitch', 'org.thingsboard.rule.engine.filter.TbAssetTypeSwitchNode': 'ruleNodeAssetProfileSwitch', 'org.thingsboard.rule.engine.filter.TbDeviceTypeSwitchNode': 'ruleNodeDeviceProfileSwitch', 'org.thingsboard.rule.engine.filter.TbCheckAlarmStatusNode': 'ruleNodeCheckAlarmStatus', @@ -463,18 +466,18 @@ const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.metadata.TbGetTenantDetailsNode': 'ruleNodeTenantDetails', 'org.thingsboard.rule.engine.metadata.CalculateDeltaNode': 'ruleNodeCalculateDelta', 'org.thingsboard.rule.engine.transform.TbChangeOriginatorNode': 'ruleNodeChangeOriginator', - [RuleNodeClazz.TbTransformMsgNode]: 'ruleNodeTransformMsg', + 'org.thingsboard.rule.engine.transform.TbTransformMsgNode': 'ruleNodeTransformMsg', 'org.thingsboard.rule.engine.mail.TbMsgToEmailNode': 'ruleNodeMsgToEmail', 'org.thingsboard.rule.engine.action.TbAssignToCustomerNode': 'ruleNodeAssignToCustomer', 'org.thingsboard.rule.engine.action.TbUnassignFromCustomerNode': 'ruleNodeUnassignFromCustomer', - [RuleNodeClazz.TbClearAlarmNode]: 'ruleNodeClearAlarm', - [RuleNodeClazz.TbCreateAlarmNode]: 'ruleNodeCreateAlarm', + 'org.thingsboard.rule.engine.action.TbClearAlarmNode': 'ruleNodeClearAlarm', + 'org.thingsboard.rule.engine.action.TbCreateAlarmNode': 'ruleNodeCreateAlarm', 'org.thingsboard.rule.engine.action.TbCreateRelationNode': 'ruleNodeCreateRelation', 'org.thingsboard.rule.engine.action.TbDeleteRelationNode': 'ruleNodeDeleteRelation', 'org.thingsboard.rule.engine.delay.TbMsgDelayNode': 'ruleNodeMsgDelay', - [RuleNodeClazz.TbMsgGeneratorNode]: 'ruleNodeMsgGenerator', + 'org.thingsboard.rule.engine.debug.TbMsgGeneratorNode': 'ruleNodeMsgGenerator', 'org.thingsboard.rule.engine.geo.TbGpsGeofencingActionNode': 'ruleNodeGpsGeofencingEvents', - [RuleNodeClazz.TbLogNode]: 'ruleNodeLog', + 'org.thingsboard.rule.engine.action.TbLogNode': 'ruleNodeLog', 'org.thingsboard.rule.engine.rpc.TbSendRPCReplyNode': 'ruleNodeRpcCallReply', 'org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode': 'ruleNodeRpcCallRequest', 'org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode': 'ruleNodeSaveAttributes', @@ -511,12 +514,3 @@ export function getRuleNodeHelpLink(component: RuleNodeComponentDescriptor): str return 'ruleEngine'; } -export const ruleNodeClazzFunctionNameTranslations = { - [RuleNodeClazz.TbJsFilterNode]: 'rulenode.function-name.filter', - [RuleNodeClazz.TbLogNode]: 'rulenode.function-name.to-string', - [RuleNodeClazz.TbJsSwitchNode]: 'rulenode.function-name.switch', - [RuleNodeClazz.TbClearAlarmNode]: 'rulenode.function-name.details', - [RuleNodeClazz.TbCreateAlarmNode]: 'rulenode.function-name.details', - [RuleNodeClazz.TbTransformMsgNode]: 'rulenode.function-name.transform', - [RuleNodeClazz.TbMsgGeneratorNode]: 'rulenode.function-name.generate' -} 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 d3b374f1ec..ef94480aa8 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3467,15 +3467,7 @@ "test": "Test", "help": "Help", "reset-debug-mode": "Reset debug mode in all nodes", - "test-function": "Test '{{function}}' function with this message", - "function-name": { - "filter": "Filter", - "to-string": "ToString", - "details": "Details", - "generate": "Generate", - "switch": "Switch", - "transform": "Transform" - } + "test-with-this-message": "{{test}} with this message" }, "timezone": { "timezone": "Timezone", From fbc082c00c0c3bad9e3c01b1c46f588c9b622209 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 3 Jul 2023 17:43:25 +0300 Subject: [PATCH 189/421] UI: Update charts bundle. --- .../data/json/system/widget_bundles/charts.json | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/charts.json b/application/src/main/data/json/system/widget_bundles/charts.json index 660bd9b16d..8dac2b5f5f 100644 --- a/application/src/main/data/json/system/widget_bundles/charts.json +++ b/application/src/main/data/json/system/widget_bundles/charts.json @@ -161,7 +161,9 @@ "settingsDirective": "tb-flot-line-widget-settings", "dataKeySettingsDirective": "tb-flot-line-key-settings", "latestDataKeySettingsDirective": "tb-flot-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":0,\"max\":1.2,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"timeForComparison\":\"previousInterval\",\"comparisonCustomIntervalValue\":7200000,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"right\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"dataKeysListForLabels\":[]},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}" + "hasBasicMode": true, + "basicModeDirective": "tb-flot-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":0,\"max\":1.2,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"timeForComparison\":\"previousInterval\",\"comparisonCustomIntervalValue\":7200000,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"right\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"dataKeysListForLabels\":[]},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false},\"configMode\":\"basic\",\"showTitleIcon\":false,\"titleIcon\":\"waterfall_chart\",\"iconColor\":\"#1F6BDD\"}" } }, { @@ -183,7 +185,9 @@ "settingsDirective": "tb-flot-line-widget-settings", "dataKeySettingsDirective": "tb-flot-line-key-settings", "latestDataKeySettingsDirective": "tb-flot-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Line Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" + "hasBasicMode": true, + "basicModeDirective": "tb-flot-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Line Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":false,\"titleIcon\":\"thermostat\",\"iconColor\":\"#1F6BDD\"}" } }, { @@ -204,8 +208,10 @@ "settingsDirective": "tb-flot-bar-widget-settings", "dataKeySettingsDirective": "tb-flot-bar-key-settings", "latestDataKeySettingsDirective": "tb-flot-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":true,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"defaultBarWidth\":600,\"barAlignment\":\"left\",\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Bar Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{}}" + "hasBasicMode": true, + "basicModeDirective": "tb-flot-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":true,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"defaultBarWidth\":600,\"barAlignment\":\"left\",\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Bar Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"configMode\":\"basic\",\"showTitleIcon\":false,\"titleIcon\":\"thermostat\",\"iconColor\":\"#1F6BDD\"}" } } ] -} +} \ No newline at end of file From af84989b600b876924db138f2ba4258c0ac7d0a4 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 3 Jul 2023 18:34:52 +0300 Subject: [PATCH 190/421] UI: Update modules map --- ui-ngx/src/app/modules/common/modules-map.ts | 2 ++ ui-ngx/src/app/shared/components/public-api.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 4c03b402ab..b7c382f6a0 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -179,6 +179,7 @@ import * as ProtobufContentComponent from '@shared/components/protobuf-content.c import * as SlackConversationAutocompleteComponent from '@shared/components/slack-conversation-autocomplete.component'; import * as StringItemsListComponent from '@shared/components/string-items-list.component'; import * as ToggleHeaderComponent from '@shared/components/toggle-header.component'; +import * as ToggleSelectComponent from '@shared/components/toggle-select.component'; import * as AddEntityDialogComponent from '@home/components/entity/add-entity-dialog.component'; import * as EntitiesTableComponent from '@home/components/entity/entities-table.component'; @@ -478,6 +479,7 @@ class ModulesMap implements IModulesMap { '@shared/components/slack-conversation-autocomplete.component': SlackConversationAutocompleteComponent, '@shared/components/string-items-list.component': StringItemsListComponent, '@shared/components/toggle-header.component': ToggleHeaderComponent, + '@shared/components/toggle-select.component': ToggleSelectComponent, '@home/components/entity/add-entity-dialog.component': AddEntityDialogComponent, '@home/components/entity/entities-table.component': EntitiesTableComponent, diff --git a/ui-ngx/src/app/shared/components/public-api.ts b/ui-ngx/src/app/shared/components/public-api.ts index 9ec226769a..32c709ecb0 100644 --- a/ui-ngx/src/app/shared/components/public-api.ts +++ b/ui-ngx/src/app/shared/components/public-api.ts @@ -24,3 +24,4 @@ export * from './slack-conversation-autocomplete.component'; export * from './notification/template-autocomplete.component'; export * from './resource/resource-autocomplete.component'; export * from './toggle-header.component'; +export * from './toggle-select.component'; From b781a05764a248420c2aa7502fe2a5f4f2eb8d17 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 4 Jul 2023 18:02:11 +0300 Subject: [PATCH 191/421] UI: Redesign device wizard and device credentias --- ui-ngx/src/app/core/http/device.service.ts | 7 + ...vice-credentials-mqtt-basic.component.html | 7 +- .../device/device-credentials.component.html | 13 +- .../device/device-credentials.component.scss | 23 ++ .../device/device-credentials.component.ts | 48 ++- ...device-profile-autocomplete.component.html | 5 + ...device-profile-autocomplete.component.scss | 6 + .../device-profile-autocomplete.component.ts | 17 +- .../device-wizard-dialog.component.html | 137 ++------ .../device-wizard-dialog.component.scss | 51 +-- .../wizard/device-wizard-dialog.component.ts | 319 +++--------------- .../device-credentials-dialog.component.html | 90 +++-- .../device-credentials-dialog.component.scss | 41 +++ .../device-credentials-dialog.component.ts | 2 +- .../device/devices-table-config.resolver.ts | 5 +- .../components/toggle-header.component.html | 7 +- .../components/toggle-header.component.scss | 27 ++ .../components/toggle-header.component.ts | 4 + .../components/toggle-select.component.html | 1 + .../components/toggle-select.component.ts | 2 + ui-ngx/src/app/shared/models/device.models.ts | 2 +- .../assets/locale/locale.constant-ca_ES.json | 9 +- .../assets/locale/locale.constant-cs_CZ.json | 9 +- .../assets/locale/locale.constant-da_DK.json | 9 +- .../assets/locale/locale.constant-en_US.json | 9 +- .../assets/locale/locale.constant-es_ES.json | 9 +- .../assets/locale/locale.constant-fr_FR.json | 9 +- .../assets/locale/locale.constant-ko_KR.json | 9 +- .../assets/locale/locale.constant-sl_SI.json | 9 +- .../assets/locale/locale.constant-tr_TR.json | 9 +- .../assets/locale/locale.constant-zh_CN.json | 9 +- .../assets/locale/locale.constant-zh_TW.json | 9 +- 32 files changed, 352 insertions(+), 561 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/device/device-credentials.component.scss create mode 100644 ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.scss diff --git a/ui-ngx/src/app/core/http/device.service.ts b/ui-ngx/src/app/core/http/device.service.ts index 018e202e81..dfc2d674a2 100644 --- a/ui-ngx/src/app/core/http/device.service.ts +++ b/ui-ngx/src/app/core/http/device.service.ts @@ -87,6 +87,13 @@ export class DeviceService { return this.http.post('/api/device', device, defaultHttpOptionsFromConfig(config)); } + public saveDeviceWithCredentials(device: Device, credentials: DeviceCredentials, config?: RequestConfig): Observable { + return this.http.post('/api/device-with-credentials', { + device, + credentials + }, defaultHttpOptionsFromConfig(config)); + } + public deleteDevice(deviceId: string, config?: RequestConfig) { return this.http.delete(`/api/device/${deviceId}`, defaultHttpOptionsFromConfig(config)); } diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials-mqtt-basic.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials-mqtt-basic.component.html index be71d3724e..768cea9252 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials-mqtt-basic.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials-mqtt-basic.component.html @@ -26,13 +26,14 @@ matTooltip="{{ 'device.generate-client-id' | translate }}" matTooltipPosition="above" (click)="generate('clientId')" - *ngIf="!deviceCredentialsMqttFormGroup.get('clientId').value; else copyClientId"> + *ngIf="!deviceCredentialsMqttFormGroup.get('clientId').value && !disabled; else copyClientId"> autorenew + *ngIf="!deviceCredentialsMqttFormGroup.get('userName').value && !disabled; else copyUserName"> autorenew @@ -85,7 +86,7 @@ matTooltip="{{ 'device.generate-password' | translate }}" matTooltipPosition="above" (click)="generate('password')" - *ngIf="!deviceCredentialsMqttFormGroup.get('password').value; else copyPassword"> + *ngIf="!deviceCredentialsMqttFormGroup.get('password').value && !disabled; else copyPassword"> autorenew diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html index 303c46ef70..1bd319587b 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html @@ -16,7 +16,7 @@ -->
- + device.credentials-type @@ -24,6 +24,14 @@ +
+
device.credentials-type
+ + + {{ credentialTypeNamesMap.get(credentialsType) }} + + +
@@ -36,13 +44,14 @@ matTooltip="{{ 'device.generate-access-token' | translate }}" matTooltipPosition="above" (click)="generate('credentialsId')" - *ngIf="!deviceCredentialsFormGroup.get('credentialsId').value; else copyAccessToken"> + *ngIf="!deviceCredentialsFormGroup.get('credentialsId').value && !disabled; else copyAccessToken"> autorenew DeviceCredentialsComponent), multi: true, }], - styleUrls: [] + styleUrls: ['./device-credentials.component.scss'] }) export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, Validator, OnDestroy { @@ -73,9 +74,13 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, } } + @Input() + @coerceBoolean() + initAccessToken = false; + private destroy$ = new Subject(); - deviceCredentialsFormGroup: UntypedFormGroup; + deviceCredentialsFormGroup: FormGroup; deviceCredentialsType = DeviceCredentialsType; @@ -83,9 +88,10 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, credentialTypeNamesMap = credentialTypeNames; - private propagateChange = (v: any) => {}; + private propagateChange = null; + private propagateChangePending = false; - constructor(public fb: UntypedFormBuilder) { + constructor(public fb: FormBuilder) { this.deviceCredentialsFormGroup = this.fb.group({ credentialsType: [DeviceCredentialsType.ACCESS_TOKEN], credentialsId: [null], @@ -98,8 +104,8 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, }); this.deviceCredentialsFormGroup.get('credentialsType').valueChanges.pipe( takeUntil(this.destroy$) - ).subscribe(() => { - this.credentialsTypeChanged(); + ).subscribe((value) => { + this.credentialsTypeChanged(value); }); } @@ -107,6 +113,10 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, if (this.disabled) { this.deviceCredentialsFormGroup.disable({emitEvent: false}); } + if (this.initAccessToken && !this.deviceCredentialsFormGroup.get('credentialsId').value && + this.deviceCredentialsFormGroup.get('credentialsType').value === DeviceCredentialsType.ACCESS_TOKEN) { + this.deviceCredentialsFormGroup.get('credentialsId').patchValue(generateSecret(20)); + } } ngOnDestroy() { @@ -128,11 +138,21 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, updateView() { const deviceCredentialsValue = this.deviceCredentialsFormGroup.value; - this.propagateChange(deviceCredentialsValue); + if (this.propagateChange) { + this.propagateChange(deviceCredentialsValue); + } else { + this.propagateChangePending = true; + } } registerOnChange(fn: any): void { this.propagateChange = fn; + if (this.propagateChangePending) { + this.propagateChangePending = false; + setTimeout(() => { + this.updateView(); + }, 0); + } } registerOnTouched(fn: any): void {} @@ -144,11 +164,10 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, } else { this.deviceCredentialsFormGroup.enable({emitEvent: false}); this.updateValidators(); - this.deviceCredentialsFormGroup.updateValueAndValidity(); } } - public validate(c: UntypedFormControl) { + public validate(c: FormControl) { return this.deviceCredentialsFormGroup.valid ? null : { deviceCredentials: { valid: false, @@ -156,12 +175,15 @@ export class DeviceCredentialsComponent implements ControlValueAccessor, OnInit, }; } - credentialsTypeChanged(): void { + credentialsTypeChanged(type: DeviceCredentialsType): void { this.deviceCredentialsFormGroup.patchValue({ credentialsId: null, credentialsValue: null }); this.updateValidators(); + if (type === DeviceCredentialsType.ACCESS_TOKEN && this.initAccessToken) { + this.deviceCredentialsFormGroup.get('credentialsId').patchValue(generateSecret(20)); + } } updateValidators(): void { diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html index 2a118f6300..c88d169d82 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html @@ -43,6 +43,11 @@ (click)="editDeviceProfile($event)"> edit + -
- + check @@ -54,58 +57,27 @@ {{ 'device.label-max-length' | translate }} -
- - - device.wizard.existing-device-profile - - - device.wizard.new-device-profile - - -
- - - - device-profile.new-device-profile-name - - - {{ 'device-profile.new-device-profile-name-required' | translate }} - - -
-
- - -
-
- - -
-
-
- + + + + +
+ {{ 'device.is-gateway' | translate }} - - + {{ 'device.overwrite-activity-time' | translate }} - +
device.description @@ -114,73 +86,20 @@ - -
- {{ 'device-profile.transport-configuration' | translate }} - device-profile.transport-type - - - {{deviceTransportTypeTranslations.get(type) | translate}} - - - - {{deviceTransportTypeHints.get(transportConfigFormGroup.get('transportType').value) | translate}} - - - {{ 'device-profile.transport-type-required' | translate }} - - - - -
-
- -
- {{'device-profile.alarm-rules-with-count' | translate: - {count: alarmRulesFormGroup.get('alarms').value ? - alarmRulesFormGroup.get('alarms').value.length : 0} }} - - -
-
- -
- {{ 'device-profile.device-provisioning' | translate }} - - -
-
- + {{ 'device.credentials' | translate }}
- {{ 'device.wizard.add-credentials' | translate }}
- - {{ 'customer.customer' | translate }} -
- - -
-
-
-
+
+
@@ -192,7 +111,7 @@ (click)="nextStep()">{{ 'action.next-with-label' | translate:{label: (getFormLabel(this.selectedIndex+1) | translate)} }}
-
+
diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss index 0fe18467fd..2f35b3e60d 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.scss @@ -18,49 +18,62 @@ :host { height: 100%; display: grid; + grid-template-rows: min-content 4px auto min-content; - .dialog-actions-row { - padding: 8px; + .toggle-group { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 16px; + margin-bottom: 16px; + } + + @media #{$mat-sm} { + min-width: 470px; + } + + @media #{$mat-gt-sm} { + min-width: 650px; } } -:host-context(.tb-fullscreen-dialog .mat-mdc-dialog-container) { - @media #{$mat-lt-sm} { - .mat-mdc-dialog-content { - max-height: 75vh; +:host-context(.mat-mdc-dialog-container) { + .tb-dialog-actions { + padding: 0; + grid-row: 4; + + .dialog-actions-row { + padding: 8px; + display: flex; + gap: 8px; + justify-content: flex-end; + flex: 1; } } - .invisible{ - visibility: hidden; + .mat-mdc-dialog-content { + grid-row: 3; + padding: 0; } + } :host ::ng-deep { .mat-mdc-dialog-content { - display: flex; - flex-direction: column; - height: 100%; - padding: 0 !important; - .mat-stepper-horizontal { display: flex; height: 100%; overflow: hidden; .mat-horizontal-stepper-wrapper { - flex: 1 1 100%; + width: 100%; } .mat-horizontal-content-container { - height: 680px; + height: 500px; max-height: 100%; - width: 100%;; overflow-y: auto; scrollbar-gutter: stable; - @media #{$mat-gt-sm} { - min-width: 500px; - } } } } diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 77916d379c..77ae90fab3 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -14,201 +14,83 @@ /// limitations under the License. /// -import { Component, Inject, OnDestroy, SkipSelf, ViewChild } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Component, ViewChild } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { DialogComponent } from '@shared/components/dialog.component'; import { Router } from '@angular/router'; -import { - createDeviceProfileConfiguration, - createDeviceProfileTransportConfiguration, - DeviceProfile, - DeviceProfileInfo, - DeviceProfileType, - DeviceProvisionConfiguration, - DeviceProvisionType, - DeviceTransportType, - deviceTransportTypeHintMap, - deviceTransportTypeTranslationMap -} from '@shared/models/device.models'; -import { MatStepper } from '@angular/material/stepper'; -import { AddEntityDialogData } from '@home/models/entity/entity-component.models'; +import { Device, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; +import { MatStepper, StepperOrientation } from '@angular/material/stepper'; import { BaseData, HasId } from '@shared/models/base-data'; import { EntityType } from '@shared/models/entity-type.models'; -import { DeviceProfileService } from '@core/http/device-profile.service'; -import { EntityId } from '@shared/models/id/entity-id'; -import { Observable, of, Subscription, throwError } from 'rxjs'; -import { catchError, map, mergeMap, tap } from 'rxjs/operators'; +import { Observable, throwError } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; import { DeviceService } from '@core/http/device.service'; -import { ErrorStateMatcher } from '@angular/material/core'; import { StepperSelectionEvent } from '@angular/cdk/stepper'; -import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; +import { BreakpointObserver } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; -import { RuleChainId } from '@shared/models/id/rule-chain-id'; -import { ServiceType } from '@shared/models/queue.models'; import { deepTrim } from '@core/utils'; +import { CustomerId } from '@shared/models/id/customer-id'; +import { HttpErrorResponse } from '@angular/common/http'; @Component({ selector: 'tb-device-wizard', templateUrl: './device-wizard-dialog.component.html', - providers: [], styleUrls: ['./device-wizard-dialog.component.scss'] }) -export class DeviceWizardDialogComponent extends - DialogComponent implements OnDestroy, ErrorStateMatcher { +export class DeviceWizardDialogComponent extends DialogComponent { @ViewChild('addDeviceWizardStepper', {static: true}) addDeviceWizardStepper: MatStepper; - selectedIndex = 0; - - showNext = true; - - createProfile = false; - - entityType = EntityType; - - deviceTransportTypes = Object.values(DeviceTransportType); - - deviceTransportTypeTranslations = deviceTransportTypeTranslationMap; + stepperOrientation: Observable; - deviceTransportTypeHints = deviceTransportTypeHintMap; + stepperLabelPosition: Observable<'bottom' | 'end'>; - deviceWizardFormGroup: UntypedFormGroup; - - transportConfigFormGroup: UntypedFormGroup; - - alarmRulesFormGroup: UntypedFormGroup; + selectedIndex = 0; - provisionConfigFormGroup: UntypedFormGroup; + credentialsOptionalStep = true; - credentialsFormGroup: UntypedFormGroup; + showNext = true; - customerFormGroup: UntypedFormGroup; + entityType = EntityType; - labelPosition: MatStepper['labelPosition'] = 'end'; + deviceWizardFormGroup: FormGroup; - serviceType = ServiceType.TB_RULE_ENGINE; + credentialsFormGroup: FormGroup; - private subscriptions: Subscription[] = []; private currentDeviceProfileTransportType = DeviceTransportType.DEFAULT; constructor(protected store: Store, protected router: Router, - @Inject(MAT_DIALOG_DATA) public data: AddEntityDialogData>, - @SkipSelf() private errorStateMatcher: ErrorStateMatcher, public dialogRef: MatDialogRef, - private deviceProfileService: DeviceProfileService, private deviceService: DeviceService, private breakpointObserver: BreakpointObserver, - private fb: UntypedFormBuilder) { + private fb: FormBuilder) { super(store, router, dialogRef); + + this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-sm']) + .pipe(map(({matches}) => matches ? 'horizontal' : 'vertical')); + + this.stepperLabelPosition = this.breakpointObserver.observe(MediaBreakpoints['gt-sm']) + .pipe(map(({matches}) => matches ? 'end' : 'bottom')); + this.deviceWizardFormGroup = this.fb.group({ name: ['', [Validators.required, Validators.maxLength(255)]], label: ['', Validators.maxLength(255)], gateway: [false], overwriteActivityTime: [false], - addProfileType: [0], + customerId: [null], deviceProfileId: [null, Validators.required], - newDeviceProfileTitle: [{value: null, disabled: true}], - defaultRuleChainId: [{value: null, disabled: true}], - defaultQueueName: [{value: null, disabled: true}], description: [''] } ); - this.subscriptions.push(this.deviceWizardFormGroup.get('addProfileType').valueChanges.subscribe( - (addProfileType: number) => { - if (addProfileType === 0) { - this.deviceWizardFormGroup.get('deviceProfileId').setValidators([Validators.required]); - this.deviceWizardFormGroup.get('deviceProfileId').enable(); - this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators(null); - this.deviceWizardFormGroup.get('newDeviceProfileTitle').disable(); - this.deviceWizardFormGroup.get('defaultRuleChainId').disable(); - this.deviceWizardFormGroup.get('defaultQueueName').disable(); - this.deviceWizardFormGroup.updateValueAndValidity(); - this.createProfile = false; - } else { - this.deviceWizardFormGroup.get('deviceProfileId').setValidators(null); - this.deviceWizardFormGroup.get('deviceProfileId').disable(); - this.deviceWizardFormGroup.get('newDeviceProfileTitle').setValidators([Validators.required]); - this.deviceWizardFormGroup.get('newDeviceProfileTitle').enable(); - this.deviceWizardFormGroup.get('defaultRuleChainId').enable(); - this.deviceWizardFormGroup.get('defaultQueueName').enable(); - - this.deviceWizardFormGroup.updateValueAndValidity(); - this.createProfile = true; - } - } - )); - - this.transportConfigFormGroup = this.fb.group( - { - transportType: [DeviceTransportType.DEFAULT, Validators.required], - transportConfiguration: [createDeviceProfileTransportConfiguration(DeviceTransportType.DEFAULT), Validators.required] - } - ); - - this.subscriptions.push(this.transportConfigFormGroup.get('transportType').valueChanges.subscribe((transportType) => { - this.deviceProfileTransportTypeChanged(transportType); - })); - - this.alarmRulesFormGroup = this.fb.group({ - alarms: [null] - } - ); - - this.provisionConfigFormGroup = this.fb.group( - { - provisionConfiguration: [{ - type: DeviceProvisionType.DISABLED - } as DeviceProvisionConfiguration, [Validators.required]] - } - ); - this.credentialsFormGroup = this.fb.group({ - setCredential: [false], - credential: [{value: null, disabled: true}] - } - ); - - this.subscriptions.push(this.credentialsFormGroup.get('setCredential').valueChanges.subscribe((value) => { - if (value) { - this.credentialsFormGroup.get('credential').enable(); - } else { - this.credentialsFormGroup.get('credential').disable(); - } - })); - - this.customerFormGroup = this.fb.group({ - customerId: [null] + credential: [] } ); - - this.labelPosition = this.breakpointObserver.isMatched(MediaBreakpoints['gt-sm']) ? 'end' : 'bottom'; - - this.subscriptions.push(this.breakpointObserver - .observe(MediaBreakpoints['gt-sm']) - .subscribe((state: BreakpointState) => { - if (state.matches) { - this.labelPosition = 'end'; - } else { - this.labelPosition = 'bottom'; - } - } - )); - } - - ngOnDestroy() { - super.ngOnDestroy(); - this.subscriptions.forEach(s => s.unsubscribe()); - } - - isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean { - const originalErrorState = this.errorStateMatcher.isErrorState(control, form); - const customErrorState = !!(control && control.invalid); - return originalErrorState || customErrorState; } cancel(): void { @@ -224,24 +106,11 @@ export class DeviceWizardDialogComponent extends } getFormLabel(index: number): string { - if (index > 0) { - if (!this.createProfile) { - index += 3; - } - } switch (index) { case 0: return 'device.wizard.device-details'; case 1: - return 'device-profile.transport-configuration'; - case 2: - return 'device-profile.alarm-rules'; - case 3: - return 'device-profile.device-provisioning'; - case 4: return 'device.credentials'; - case 5: - return 'customer.customer'; } } @@ -249,88 +118,30 @@ export class DeviceWizardDialogComponent extends return this.addDeviceWizardStepper?._steps?.length - 1; } - private deviceProfileTransportTypeChanged(deviceTransportType: DeviceTransportType): void { - this.transportConfigFormGroup.patchValue( - {transportConfiguration: createDeviceProfileTransportConfiguration(deviceTransportType)}); - const setCredentialBox = this.credentialsFormGroup.get('setCredential'); - if (deviceTransportType === DeviceTransportType.LWM2M) { - setCredentialBox.patchValue(true); - setCredentialBox.disable(); - } else { - setCredentialBox.patchValue(false); - setCredentialBox.enable(); - } - } - add(): void { if (this.allValid()) { - this.createDeviceProfile().pipe( - mergeMap(profileId => this.createDevice(profileId)), - mergeMap(device => this.saveCredentials(device)) - ).subscribe( - (created) => { - this.dialogRef.close(created); - } + this.createDevice().subscribe( + () => this.dialogRef.close(true) ); } } get deviceTransportType(): DeviceTransportType { - if (this.deviceWizardFormGroup.get('addProfileType').value) { - return this.transportConfigFormGroup.get('transportType').value; - } else { - return this.currentDeviceProfileTransportType; - } + return this.currentDeviceProfileTransportType; } deviceProfileChanged(deviceProfile: DeviceProfileInfo) { if (deviceProfile) { this.currentDeviceProfileTransportType = deviceProfile.transportType; + this.credentialsOptionalStep = this.currentDeviceProfileTransportType !== DeviceTransportType.LWM2M; } } - private createDeviceProfile(): Observable { - if (this.deviceWizardFormGroup.get('addProfileType').value) { - const deviceProvisionConfiguration: DeviceProvisionConfiguration = this.provisionConfigFormGroup.get('provisionConfiguration').value; - const provisionDeviceKey = deviceProvisionConfiguration.provisionDeviceKey; - delete deviceProvisionConfiguration.provisionDeviceKey; - const deviceProfile: DeviceProfile = { - name: this.deviceWizardFormGroup.get('newDeviceProfileTitle').value, - type: DeviceProfileType.DEFAULT, - defaultQueueName: this.deviceWizardFormGroup.get('defaultQueueName').value, - transportType: this.transportConfigFormGroup.get('transportType').value, - provisionType: deviceProvisionConfiguration.type, - provisionDeviceKey, - profileData: { - configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT), - transportConfiguration: this.transportConfigFormGroup.get('transportConfiguration').value, - alarms: this.alarmRulesFormGroup.get('alarms').value, - provisionConfiguration: deviceProvisionConfiguration - } - }; - if (this.deviceWizardFormGroup.get('defaultRuleChainId').value) { - deviceProfile.defaultRuleChainId = new RuleChainId(this.deviceWizardFormGroup.get('defaultRuleChainId').value); - } - return this.deviceProfileService.saveDeviceProfile(deepTrim(deviceProfile)).pipe( - tap((profile) => { - this.currentDeviceProfileTransportType = profile.transportType; - this.deviceWizardFormGroup.patchValue({ - deviceProfileId: profile.id, - addProfileType: 0 - }); - }), - map(profile => profile.id) - ); - } else { - return of(this.deviceWizardFormGroup.get('deviceProfileId').value); - } - } - - private createDevice(profileId): Observable> { - const device = { + private createDevice(): Observable> { + const device: Device = { name: this.deviceWizardFormGroup.get('name').value, label: this.deviceWizardFormGroup.get('label').value, - deviceProfileId: profileId, + deviceProfileId: this.deviceWizardFormGroup.get('deviceProfileId').value, additionalInfo: { gateway: this.deviceWizardFormGroup.get('gateway').value, overwriteActivityTime: this.deviceWizardFormGroup.get('overwriteActivityTime').value, @@ -338,13 +149,22 @@ export class DeviceWizardDialogComponent extends }, customerId: null }; - if (this.customerFormGroup.get('customerId').value) { - device.customerId = { - entityType: EntityType.CUSTOMER, - id: this.customerFormGroup.get('customerId').value - }; + if (this.deviceWizardFormGroup.get('customerId').value) { + device.customerId = new CustomerId(this.deviceWizardFormGroup.get('customerId').value); + } + if (this.addDeviceWizardStepper.steps.last.completed || this.addDeviceWizardStepper.selectedIndex > 0) { + return this.deviceService.saveDeviceWithCredentials(deepTrim(device), deepTrim(this.credentialsFormGroup.value.credential)).pipe( + catchError((e: HttpErrorResponse) => { + if (e.error.message.include('Device credentials')) { + this.addDeviceWizardStepper.selectedIndex = 1; + } else { + this.addDeviceWizardStepper.selectedIndex = 0; + } + return throwError(() => e); + }) + ); } - return this.data.entitiesTableConfig.saveEntity(deepTrim(device)).pipe( + return this.deviceService.saveDevice(deepTrim(device)).pipe( catchError(e => { this.addDeviceWizardStepper.selectedIndex = 0; return throwError(e); @@ -352,31 +172,8 @@ export class DeviceWizardDialogComponent extends ); } - private saveCredentials(device: BaseData): Observable { - if (this.credentialsFormGroup.get('setCredential').value) { - return this.deviceService.getDeviceCredentials(device.id.id).pipe( - mergeMap( - (deviceCredentials) => { - const deviceCredentialsValue = {...deviceCredentials, ...this.credentialsFormGroup.value.credential}; - return this.deviceService.saveDeviceCredentials(deviceCredentialsValue).pipe( - catchError(e => { - this.addDeviceWizardStepper.selectedIndex = 1; - return this.deviceService.deleteDevice(device.id.id).pipe( - mergeMap(() => { - return throwError(e); - } - )); - }) - ); - } - ), - map(() => true)); - } - return of(true); - } - allValid(): boolean { - if (this.addDeviceWizardStepper.steps.find((item, index) => { + return !this.addDeviceWizardStepper.steps.find((item, index) => { if (item.stepControl.invalid) { item.interacted = true; this.addDeviceWizardStepper.selectedIndex = index; @@ -384,19 +181,11 @@ export class DeviceWizardDialogComponent extends } else { return false; } - } )) { - return false; - } else { - return true; - } + }); } changeStep($event: StepperSelectionEvent): void { this.selectedIndex = $event.selectedIndex; - if (this.selectedIndex === this.maxStepperIndex) { - this.showNext = false; - } else { - this.showNext = true; - } + this.showNext = this.selectedIndex !== this.maxStepperIndex; } } diff --git a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html index ff32bf68df..d7f964542e 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.html @@ -15,49 +15,47 @@ limitations under the License. --> -
- -

{{ 'device.device-credentials' | translate }}

- - -
- - -
-
-
-
- - -
-
- -
- - - {{ 'device.loading-device-credentials' | translate }} - -
-
-
-
- - -
-
+ +

{{ 'device.device-credentials' | translate }}

+ + +
+ + +
+
+
+ + +
+
+ +
+ + + {{ 'device.loading-device-credentials' | translate }} + +
+
+
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.scss new file mode 100644 index 0000000000..f2c168e150 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.scss @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2023 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 { + height: 100%; + display: grid; + grid-template-rows: min-content 4px auto min-content; + + @media #{$mat-gt-xs} { + min-width: 420px; + } +} + +:host-context(.mat-mdc-dialog-container) { + .tb-dialog-actions { + grid-row: 4; + display: flex; + gap: 8px; + justify-content: flex-end; + flex: 1; + } + + .mat-mdc-dialog-content { + grid-row: 3; + padding: 24px 24px 4px; + } +} diff --git a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts index 41986b2b03..cb4a795c9e 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device-credentials-dialog.component.ts @@ -37,7 +37,7 @@ export interface DeviceCredentialsDialogData { selector: 'tb-device-credentials-dialog', templateUrl: './device-credentials-dialog.component.html', providers: [{provide: ErrorStateMatcher, useExisting: DeviceCredentialsDialogComponent}], - styleUrls: [] + styleUrls: ['./device-credentials-dialog.component.scss'] }) export class DeviceCredentialsDialogComponent extends DialogComponent implements OnInit, ErrorStateMatcher { diff --git a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts index 83064c27ff..b246bd8d7c 100644 --- a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts @@ -458,10 +458,7 @@ export class DevicesTableConfigResolver implements Resolve>, boolean>(DeviceWizardDialogComponent, { disableClose: true, - panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], - data: { - entitiesTableConfig: this.config - } + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'] }).afterClosed().subscribe( (res) => { if (res) { diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.html b/ui-ngx/src/app/shared/components/toggle-header.component.html index e36cdbd592..d7ed76de90 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.html +++ b/ui-ngx/src/app/shared/components/toggle-header.component.html @@ -18,13 +18,14 @@ - {{ option.name }} + {{ option.name }} - + {{ option.name }} diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.scss b/ui-ngx/src/app/shared/components/toggle-header.component.scss index a9542012d4..6a6785c11b 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.scss +++ b/ui-ngx/src/app/shared/components/toggle-header.component.scss @@ -80,6 +80,33 @@ } } } + &.tb-disabled { + pointer-events: none; + background: rgba(0, 0, 0, 0.03); + + .mat-button-toggle.mat-button-toggle-appearance-standard { + color: rgba(0, 0, 0, 0.28); + + &.mat-button-toggle-checked { + .mat-button-toggle-button { + background: transparent; + color: rgba(0, 0, 0, 0.38); + border-color: rgba(0, 0, 0, 0.38); + } + } + } + &.tb-fill { + .mat-button-toggle.mat-button-toggle-appearance-standard { + &.mat-button-toggle-checked { + .mat-button-toggle-button { + background: rgba(0, 0, 0, 0.12); + color: rgba(0, 0, 0, 0.38); + border: transparent; + } + } + } + } + } } @media #{$mat-md-lg} { .mat-button-toggle-group.mat-button-toggle-group-appearance-standard.tb-toggle-header:not(.tb-ignore-md-lg) { diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.ts b/ui-ngx/src/app/shared/components/toggle-header.component.ts index 15c82f6470..35daad0e3f 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.ts +++ b/ui-ngx/src/app/shared/components/toggle-header.component.ts @@ -131,6 +131,10 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterC @Input() appearance: ToggleHeaderAppearance = 'stroked'; + @Input() + @coerceBoolean() + disabled = false; + isMdLg: boolean; private observeBreakpointSubscription: Subscription; diff --git a/ui-ngx/src/app/shared/components/toggle-select.component.html b/ui-ngx/src/app/shared/components/toggle-select.component.html index 20ef606288..a5ce7778b5 100644 --- a/ui-ngx/src/app/shared/components/toggle-select.component.html +++ b/ui-ngx/src/app/shared/components/toggle-select.component.html @@ -18,6 +18,7 @@ , ExportableEntity { tenantId?: TenantId; customerId?: CustomerId; name: string; - type: string; + type?: string; label: string; firmwareId?: OtaPackageId; softwareId?: OtaPackageId; 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 8c07387adc..349d13da2c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -1376,13 +1376,8 @@ "device-configuration": "Configuració del dispositiu", "transport-configuration": "Configuració del transport", "wizard": { - "device-wizard": "Assistent de dispositiu", "device-details": "Detalls del dispositiu", - "new-device-profile": "Crear un nou perfil de dispositiu", - "existing-device-profile": "Seleccionar un perfil existent", - "specific-configuration": "Configuració específica", - "customer-to-assign-device": "Client al que assignar el dispositiu", - "add-credentials": "Afegir credencial" + "customer-to-assign-device": "Client al que assignar el dispositiu" }, "unassign-devices-from-edge-title": "Està segur de que desitja desassignar {count, plural, =1 {1 dispositivo} other {# dispositivos} }?", "unassign-devices-from-edge-text": "Després de la confirmació, tots els dispositius seleccionats quedaran sense assignar i la vora no podrà accedir a ells." @@ -1404,8 +1399,6 @@ "delete": "Esborrar perfil de dispositiu", "copyId": "Copiar ID de perfil", "name-max-length": "El nom ha de ser inferior a 256", - "new-device-profile-name": "Nom del perfil", - "new-device-profile-name-required": "Cal nom de perfil.", "name": "Nom", "name-required": "Cal nom.", "type": "Tipus de perfil", 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 229a4d7eee..52873b4d70 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -1018,13 +1018,8 @@ "device-configuration": "Konfigurace zařízení", "transport-configuration": "Konfigurace přenosu", "wizard": { - "device-wizard": "Průvodce zařízením", "device-details": "Detail zařízení", - "new-device-profile": "Vytvořit nový profil zařízení", - "existing-device-profile": "Vybrat existující profil zařízení", - "specific-configuration": "Specifická konfigurace", - "customer-to-assign-device": "Přiřadit zařízení zákazníkovi", - "add-credentials": "Přidat přístupový údaj" + "customer-to-assign-device": "Přiřadit zařízení zákazníkovi" }, "unassign-devices-from-edge-title": "Jste se jisti, že chcete odebrat { count, plural, =1 {1 zařízení} other {# zařízení} }?", "unassign-devices-from-edge-text": "Po potvrzení budou všechna vybraná zařízení odebrána a nebudou pro edge dostupná." @@ -1045,8 +1040,6 @@ "set-default": "Učinit profil zařízení defaultním", "delete": "Smazat profil zařízení", "copyId": "Kopírovat Id profilu zařízení", - "new-device-profile-name": "Název profilu zařízení", - "new-device-profile-name-required": "Název profilu zařízení je povinný.", "name": "Název", "name-required": "Název je povinný.", "type": "Typ profilu", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 0f1dd146b1..2c1df70902 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -1095,13 +1095,8 @@ "device-configuration": "Enhedskonfiguration", "transport-configuration": "Transportkonfiguration", "wizard": { - "device-wizard": "Enhedsguide", "device-details": "Enhedsoplysninger", - "new-device-profile": "Opret ny enhedsprofil", - "existing-device-profile": "Vælg eksisterende enhedsprofil", - "specific-configuration": "Specifik konfiguration", - "customer-to-assign-device": "Kunden skal tildele enheden", - "add-credential": "Tilføj brugeroplysninger" + "customer-to-assign-device": "Kunden skal tildele enheden" } }, "device-profile": { @@ -1120,8 +1115,6 @@ "set-default": "Gør enhedsprofil standard", "delete": "Slet enhedsprofil", "copyId": "Kopiér enhedsprofil-id", - "new-device-profile-name": "Enhedsprofilnavn", - "new-device-profile-name-required": "Enhedsprofilnavn er påkrævet.", "name": "Navn", "name-required": "Navn er påkrævet.", "type": "Profiltype", 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 c032198efa..37013e2cc7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1373,13 +1373,8 @@ "device-configuration": "Device configuration", "transport-configuration": "Transport configuration", "wizard": { - "device-wizard": "Device Wizard", "device-details": "Device details", - "new-device-profile": "Create new device profile", - "existing-device-profile": "Select existing device profile", - "specific-configuration": "Specific configuration", - "customer-to-assign-device": "Customer to assign the device", - "add-credentials": "Add credentials" + "customer-to-assign-device": "Customer to assign the device" }, "unassign-devices-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 device} other {# devices} }?", "unassign-devices-from-edge-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the edge." @@ -1446,8 +1441,6 @@ "delete": "Delete device profile", "copyId": "Copy device profile Id", "name-max-length": "Name should be less than 256", - "new-device-profile-name": "Device profile name", - "new-device-profile-name-required": "Device profile name is required.", "name": "Name", "name-required": "Name is required.", "type": "Profile type", 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 4689c66bed..6518e03f58 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -1325,13 +1325,8 @@ "device-configuration": "Configuración del dispositivo", "transport-configuration": "Configuración del transporte", "wizard": { - "device-wizard": "Asistente de dispositivo", "device-details": "Detalles del dispositivo", - "new-device-profile": "Crear un nuevo perfil de dispositivo", - "existing-device-profile": "Seleccionar un perfil existente", - "specific-configuration": "Configuración específica", - "customer-to-assign-device": "Cliente al que asignar el dispositivo", - "add-credentials": "Añadir credencial" + "customer-to-assign-device": "Cliente al que asignar el dispositivo" }, "unassign-devices-from-edge-title": "¿Está seguro de que desea desasignar {count, plural, =1 {1 dispositivo} other {# dispositivos} }?", "unassign-devices-from-edge-text": "Después de la confirmación, todos los dispositivos seleccionados quedarán sin asignar y el Edge no podrá acceder a ellos." @@ -1398,8 +1393,6 @@ "delete": "Borrar perfil de dispositivo", "copyId": "Copiar ID de perfil", "name-max-length": "El nombre debe ser menor de 256", - "new-device-profile-name": "Nombre de perfil", - "new-device-profile-name-required": "Se requiere nombre de perfil.", "name": "Nombre", "name-required": "Se requiere nombre.", "type": "Tipo de perfil", 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 8704210933..19f92e5a7c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -1053,13 +1053,8 @@ "device-configuration": "Configuration du dipositif", "transport-configuration": "Configuration du transport", "wizard": { - "device-wizard": "Wizard du dispositif", "device-details": "Détails du dispositif", - "new-device-profile": "Créer un nouveau profil de dispositif", - "existing-device-profile": "Choisissez un profile de dispositif existant", - "specific-configuration": "Configuration spécifique", - "customer-to-assign-device": "Client auquel assigner le dispositif", - "add-credentials": "Ajouter identifiants" + "customer-to-assign-device": "Client auquel assigner le dispositif" } }, "device-profile": { @@ -1079,8 +1074,6 @@ "delete": "Supprimer le profil de dispositif", "copyId": "Copier l'Identifiant du profil de dispositif", "name-max-length": "La longueur du nom devrait être moins de 256", - "new-device-profile-name": "Nom du profil de dispositif", - "new-device-profile-name-required": "Nom du profil de dispositif est requis.", "name": "Nom", "name-required": "Nom est requis.", "type": "Type de profile", diff --git a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json index 1462a4f3d1..758482f578 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -913,13 +913,8 @@ "device-configuration": "장치 설정", "transport-configuration": "전송 설정", "wizard": { - "device-wizard": "장치 마법사", "device-details": "장치 상세 정보", - "new-device-profile": "새로운 장치 프로파일 생성", - "existing-device-profile": "기존 장치 프로파일 선택", - "specific-configuration": "특수 설정", - "customer-to-assign-device": "장치에 할당할 커스터머", - "add-credentials": "크리덴셜 추가" + "customer-to-assign-device": "장치에 할당할 커스터머" } }, "device-profile": { @@ -938,8 +933,6 @@ "set-default": "Make device profile default", "delete": "Delete device profile", "copyId": "Copy device profile Id", - "new-device-profile-name": "장치 프로파일 이름", - "new-device-profile-name-required": "Device profile name is required.", "name": "이름", "name-required": "이름을 입력하세요.", "type": "프로파일 유형", diff --git a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json index 1200732365..8aced0ddc6 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -913,13 +913,8 @@ "device-configuration": "Device configuration", "transport-configuration": "Transport configuration", "wizard": { - "device-wizard": "Device Wizard", "device-details": "Device details", - "new-device-profile": "Create new device profile", - "existing-device-profile": "Select existing device profile", - "specific-configuration": "Specific configuration", - "customer-to-assign-device": "Customer to assign the device", - "add-credentials": "Add credentials" + "customer-to-assign-device": "Customer to assign the device" } }, "device-profile": { @@ -938,8 +933,6 @@ "set-default": "Make device profile default", "delete": "Delete device profile", "copyId": "Copy device profile Id", - "new-device-profile-name": "Device profile name", - "new-device-profile-name-required": "Device profile name is required.", "name": "Name", "name-required": "Name is required.", "type": "Profile type", 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 1aa6900be7..b175a2d51a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -1021,13 +1021,8 @@ "device-configuration": "Cihaz yapılandırması", "transport-configuration": "Aktarım yapılandırması", "wizard": { - "device-wizard": "Cihaz Sihirbazı", "device-details": "Cihaz ayrıntıları", - "new-device-profile": "Yeni cihaz profili oluştur", - "existing-device-profile": "Mevcut cihaz profilini seçin", - "specific-configuration": "Özel yapılandırma", - "customer-to-assign-device": "Cihazı atamak için kullanıcı grubu", - "add-credentials": "Kimlik bilgileri ekle" + "customer-to-assign-device": "Cihazı atamak için kullanıcı grubu" }, "unassign-devices-from-edge-title": "{ count, plural, =1 {1 cihazın} other {# cihazın} } atamasını kaldırmak istediğinizden emin misiniz?", "unassign-devices-from-edge-text": "Onaydan sonra, seçilen tüm cihazların ataması kaldırılacak ve uç tarafından erişilemeyecek." @@ -1048,8 +1043,6 @@ "set-default": "Cihaz profilini varsayılan yap", "delete": "Cihaz profilini sil", "copyId": "Cihaz profili kimliğini kopyala", - "new-device-profile-name": "Cihaz profili adı", - "new-device-profile-name-required": "Cihaz profili adı gerekli.", "name": "İsim", "name-required": "İsim gerekli.", "type": "Profil türü", 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 58a214372a..b39e10e46c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -1221,13 +1221,8 @@ "device-configuration": "设备配置", "transport-configuration": "传输配置", "wizard": { - "device-wizard": "设备向导", "device-details": "设备详细信息", - "new-device-profile": "新建设备配置", - "existing-device-profile": "选择已有设备配置", - "specific-configuration": "指定配置", - "customer-to-assign-device": "客户分配设备", - "add-credentials": "添加凭据" + "customer-to-assign-device": "客户分配设备" }, "unassign-devices-from-edge-title": "确定要取消分配 { count, plural, =1 {1 个设备} other {# 个设备} } 吗?", "unassign-devices-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。" @@ -1292,8 +1287,6 @@ "delete": "删除设备配置", "copyId": "复制设备配置 ID", "name-max-length": "名称长度必须少于256个字符", - "new-device-profile-name": "设备配置名称", - "new-device-profile-name-required": "设备配置名称必填。", "name": "名称", "name-required": "名称是必需的。", "type": "配置类型", 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 2d493961aa..f2cce81824 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -1134,13 +1134,8 @@ "device-configuration": "設備配置", "transport-configuration": "傳輸配置", "wizard": { - "device-wizard": "設備嚮導", "device-details": "設備詳情", - "new-device-profile": "建立設備協議", - "existing-device-profile": "選擇現有的設備協議", - "specific-configuration": "具體配置", - "customer-to-assign-device": "客戶指定設備", - "add-credentials": "新增驗證資訊" + "customer-to-assign-device": "客戶指定設備" }, "unassign-devices-from-edge-title": "您確定要解除邊緣設備 { count, plural, =1 {1 device} other {# devices} }的指定嗎?", "unassign-devices-from-edge-text": "確認後邊緣指定設備將解除指定及其所有相關資料將無法恢復。" @@ -1205,8 +1200,6 @@ "delete": "刪除設備協議", "copyId": "複製設備協議Id", "name-max-length": "名稱應小於256", - "new-device-profile-name": "設備協議名稱", - "new-device-profile-name-required": "需要設備協議名稱。", "name": "名稱", "name-required": "需要名稱", "type": "協議類型", From fee8aa359a126cedddf0814f7fbf1cfbaecb483e Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 4 Jul 2023 18:18:23 +0300 Subject: [PATCH 192/421] refactoring --- .../server/controller/DeviceController.java | 3 +- .../src/main/resources/thingsboard.yml | 16 ++ .../server/dao/device/DeviceService.java | 3 +- .../DeviceConnectivityConfiguration.java | 9 + .../server/dao/device/DeviceServiceImpl.java | 176 ++++++++++++------ 5 files changed, 151 insertions(+), 56 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index e473163642..100fa8234c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -80,6 +80,7 @@ import javax.servlet.http.HttpServletRequest; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @@ -168,7 +169,7 @@ public class DeviceController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device/{deviceId}/commands", method = RequestMethod.GET) @ResponseBody - public List getDevicePublishTelemetryCommands(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) + public Map getDevicePublishTelemetryCommands(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) @PathVariable(DEVICE_ID) String strDeviceId, HttpServletRequest request) throws ThingsboardException, URISyntaxException { checkParameter(DEVICE_ID, strDeviceId); DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index e7fbbd2a3d..1c044daa74 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -775,6 +775,10 @@ transport: worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}" max_payload_size: "${NETTY_MAX_PAYLOAD_SIZE:65536}" so_keep_alive: "${NETTY_SO_KEEPALIVE:false}" + # Mqtt device connectivity host to publish telemetry + device_connectivity_host: "${MQTT_DEVICE_CONNECTIVITY_HOST:localhost}" + # Mqtt device connectivity port to publish telemetry + device_connectivity_port: "${MQTT_DEVICE_CONNECTIVITY_PORT:1883}" # MQTT SSL configuration ssl: # Enable/disable SSL support @@ -785,6 +789,10 @@ transport: bind_port: "${MQTT_SSL_BIND_PORT:8883}" # SSL protocol: See https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}" + # Mqtt ssl device connectivity host to publish telemetry + device_connectivity_host: "${MQTT_DEVICE_CONNECTIVITY_HOST:localhost}" + # Mqtt ssl device connectivity port to publish telemetry + device_connectivity_port: "${MQTT_DEVICE_CONNECTIVITY_PORT:8883}" # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) @@ -821,6 +829,10 @@ transport: piggyback_timeout: "${COAP_PIGGYBACK_TIMEOUT:500}" psm_activity_timer: "${COAP_PSM_ACTIVITY_TIMER:10000}" paging_transmission_window: "${COAP_PAGING_TRANSMISSION_WINDOW:10000}" + # Coap device connectivity host to publish telemetry + device_connectivity_host: "${COAP_DEVICE_CONNECTIVITY_HOST:localhost}" + # Coap device connectivity port to publish telemetry + device_connectivity_port: "${COAP_DEVICE_CONNECTIVITY_PORT:5683}" dtls: # Enable/disable DTLS 1.2 support enabled: "${COAP_DTLS_ENABLED:false}" @@ -830,6 +842,10 @@ transport: bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" # CoAP DTLS bind port bind_port: "${COAP_DTLS_BIND_PORT:5684}" + # Coap DTLS device connectivity host to publish telemetry + device_connectivity_host: "${COAP_DEVICE_CONNECTIVITY_HOST:localhost}" + # Coap DTLS device connectivity port to publish telemetry + device_connectivity_port: "${COAP_DEVICE_CONNECTIVITY_PORT:5684}" # Server DTLS credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index 79f4781936..72c6a8852c 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -38,13 +38,14 @@ import org.thingsboard.server.dao.entity.EntityDaoService; import java.net.URISyntaxException; import java.util.List; +import java.util.Map; import java.util.UUID; public interface DeviceService extends EntityDaoService { DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId); - List findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException; + Map findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException; Device findDeviceById(TenantId tenantId, DeviceId deviceId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java new file mode 100644 index 0000000000..f156729cbc --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java @@ -0,0 +1,9 @@ +package org.thingsboard.server.dao.device; + +import lombok.Data; + +@Data +public class DeviceConnectivityConfiguration { + private String deviceConnectivityHost; + private Integer deviceConnectivityPort; +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 82d380056b..cca89742e1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -20,6 +20,9 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.event.TransactionalEventListener; @@ -51,6 +54,7 @@ import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfigu import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration; +import org.thingsboard.server.common.data.device.profile.EfentoCoapDeviceTypeConfiguration; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; @@ -79,11 +83,11 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; -import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -124,6 +128,46 @@ public class DeviceServiceImpl extends AbstractCachedEntityService findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException { + public Map findDevicePublishTelemetryCommands(String baseUrl, Device device) { DeviceId deviceId = device.getId(); log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId); validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); - String hostname = new URI(baseUrl).getHost(); - DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); - DeviceCredentialsType credentialsType = deviceCredentials.getCredentialsType(); + DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); + DeviceCredentialsType credentialsType = creds.getCredentialsType(); DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); + DeviceTransportType transportType = deviceProfile.getTransportType(); + + Map commands = new HashMap<>(); - ArrayList commands = new ArrayList<>(); - switch (deviceProfile.getTransportType()) { + switch (transportType) { case DEFAULT: - switch (credentialsType) { + switch (credentialsType) { case ACCESS_TOKEN: - commands.add(getMqttAccessTokenCommand(hostname, deviceCredentials) + " -m " + PAYLOAD); - commands.add(getHttpAccessTokenCommand(baseUrl, deviceCredentials)); - commands.add("echo -n " + PAYLOAD + " | " + getCoapAccessTokenCommand(hostname, deviceCredentials) + " -f-"); - break; + commands.put("http", getHttpPublishCommand(baseUrl, creds)); + commands.put("mqtt", getMqttPublishCommand(mqttProperties.getDeviceConnectivityHost(), mqttProperties.getDeviceConnectivityPort(), creds)); + commands.put("mqtts", getMqttPublishCommand(mqttsProperties.getDeviceConnectivityHost(), mqttsProperties.getDeviceConnectivityPort(), creds)); + commands.put("coap", getCoapPublishCommand(coapProperties.getDeviceConnectivityHost(), coapProperties.getDeviceConnectivityPort(), creds)); + commands.put("coaps", getCoapPublishCommand(coapsProperties.getDeviceConnectivityHost(), coapsProperties.getDeviceConnectivityPort(), creds)); break; case MQTT_BASIC: - commands.add(getMqttBasicPublishCommand(hostname, deviceCredentials) + " -m " + PAYLOAD); + commands.put("mqtt", getMqttPublishCommand(mqttProperties.getDeviceConnectivityHost(), mqttProperties.getDeviceConnectivityPort(), creds)); + commands.put("mqtts", getMqttPublishCommand(mqttsProperties.getDeviceConnectivityHost(), mqttsProperties.getDeviceConnectivityPort(), creds)); break; case X509_CERTIFICATE: - commands.add(getMqttX509Command(hostname) + " -m " + PAYLOAD); + commands.put("mqtt", getMqttPublishCommand(mqttProperties.getDeviceConnectivityHost(), mqttProperties.getDeviceConnectivityPort(), creds)); + commands.put("mqtts", getMqttPublishCommand(mqttsProperties.getDeviceConnectivityHost(), mqttsProperties.getDeviceConnectivityPort(), creds)); + commands.put("coap", getCoapPublishCommand(coapProperties.getDeviceConnectivityHost(), coapProperties.getDeviceConnectivityPort(), creds)); + commands.put("coaps", getCoapPublishCommand(coapsProperties.getDeviceConnectivityHost(), coapsProperties.getDeviceConnectivityPort(), creds)); break; } break; case MQTT: MqttDeviceProfileTransportConfiguration transportConfiguration = (MqttDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); + String topicName = transportConfiguration.getDeviceTelemetryTopic(); TransportPayloadType payloadType = transportConfiguration.getTransportPayloadTypeConfiguration().getTransportPayloadType(); String payload = (payloadType == TransportPayloadType.PROTOBUF) ? " -f protobufFileName" : " -m " + PAYLOAD; - switch (credentialsType) { - case ACCESS_TOKEN: - commands.add(getMqttAccessTokenCommand(hostname, deviceCredentials) + payload); - break; - case MQTT_BASIC: - commands.add(getMqttBasicPublishCommand(hostname, deviceCredentials) + payload); - break; - case X509_CERTIFICATE: - commands.add(getMqttX509Command(hostname) + payload); - break; - } + + commands.put("mqtt", getMqttPublishCommand(mqttProperties.getDeviceConnectivityHost(), mqttProperties.getDeviceConnectivityPort(), + topicName, creds, payload)); + commands.put("mqtts", getMqttPublishCommand(mqttProperties.getDeviceConnectivityHost(), mqttProperties.getDeviceConnectivityPort(), + topicName, creds, payload)); break; case COAP: CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); CoapDeviceTypeConfiguration coapConfiguration = coapTransportConfiguration.getCoapDeviceTypeConfiguration(); if (coapConfiguration instanceof DefaultCoapDeviceTypeConfiguration) { - DefaultCoapDeviceTypeConfiguration configuration = - (DefaultCoapDeviceTypeConfiguration) coapTransportConfiguration.getCoapDeviceTypeConfiguration(); - TransportPayloadType transportPayloadType = configuration.getTransportPayloadTypeConfiguration().getTransportPayloadType(); - String payloadExample = (transportPayloadType == TransportPayloadType.PROTOBUF) ? " -t binary -f protobufFileName" : " -t json -f jsonFileName"; - commands.add(getCoapAccessTokenCommand(hostname, deviceCredentials) + payloadExample); + commands.put("coap", getCoapPublishCommand(coapProperties.getDeviceConnectivityHost(), coapProperties.getDeviceConnectivityPort(), creds)); + commands.put("coaps", getCoapPublishCommand(coapsProperties.getDeviceConnectivityHost(), coapsProperties.getDeviceConnectivityPort(), creds)); + } else if (coapConfiguration instanceof EfentoCoapDeviceTypeConfiguration) { + commands.put("coap", "Not supported"); + commands.put("coaps", "Not supported"); } break; + default: + commands.put(transportType.name(), "Not supported"); } return commands; } @@ -752,36 +799,57 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Tue, 4 Jul 2023 19:04:54 +0300 Subject: [PATCH 193/421] added tests for Geofencing filter node --- .../thingsboard/server/common/msg/TbMsg.java | 2 + .../engine/geo/AbstractGeofencingNode.java | 10 +- .../thingsboard/rule/engine/geo/GeoUtil.java | 4 +- .../filter/TbAssetTypeSwitchNodeTest.java | 5 +- .../filter/TbCheckAlarmStatusNodeTest.java | 3 +- .../engine/filter/TbCheckMessageNodeTest.java | 6 +- .../filter/TbCheckRelationNodeTest.java | 5 +- .../filter/TbDeviceTypeSwitchNodeTest.java | 2 +- .../engine/filter/TbJsFilterNodeTest.java | 6 +- .../filter/TbMsgTypeFilterNodeTest.java | 2 +- .../filter/TbMsgTypeSwitchNodeTest.java | 4 +- .../TbOriginatorTypeFilterNodeTest.java | 2 +- .../TbOriginatorTypeSwitchNodeTest.java | 4 +- .../{TbGeoUtilTest.java => GeoUtilTest.java} | 2 +- .../geo/TbGpsGeofencingFilterNodeTest.java | 460 ++++++++++++++++++ 15 files changed, 482 insertions(+), 35 deletions(-) rename rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/{TbGeoUtilTest.java => GeoUtilTest.java} (99%) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index 17bc7c0a8f..9848046b11 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -42,6 +42,8 @@ import java.util.UUID; @Slf4j public final class TbMsg implements Serializable { + public static final String EMPTY = "{}"; + private final String queueName; private final UUID id; private final long ts; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/AbstractGeofencingNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/AbstractGeofencingNode.java index 1f1f1fd132..b263518c41 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/AbstractGeofencingNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/AbstractGeofencingNode.java @@ -48,14 +48,14 @@ public abstract class AbstractGeofencingNode getConfigClazz(); protected boolean checkMatches(TbMsg msg) throws TbNodeException { - JsonElement msgDataElement = new JsonParser().parse(msg.getData()); + JsonElement msgDataElement = JsonParser.parseString(msg.getData()); if (!msgDataElement.isJsonObject()) { - throw new TbNodeException("Incoming Message is not a valid JSON object"); + throw new TbNodeException("Incoming Message is not a valid JSON object!"); } JsonObject msgDataObj = msgDataElement.getAsJsonObject(); double latitude = getValueFromMessageByName(msg, msgDataObj, config.getLatitudeKeyName()); double longitude = getValueFromMessageByName(msg, msgDataObj, config.getLongitudeKeyName()); - List perimeters = getPerimeters(msg, msgDataObj); + List perimeters = getPerimeters(msg); boolean matches = false; for (Perimeter perimeter : perimeters) { if (checkMatches(perimeter, latitude, longitude)) { @@ -74,11 +74,11 @@ public abstract class AbstractGeofencingNode getPerimeters(TbMsg msg, JsonObject msgDataObj) throws TbNodeException { + protected List getPerimeters(TbMsg msg) throws TbNodeException { if (config.isFetchPerimeterInfoFromMessageMetadata()) { if (StringUtils.isEmpty(config.getPerimeterKeyName())) { // Old configuration before "perimeterKeyName" was introduced diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java index 519a4274c1..4467dfe30b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/GeoUtil.java @@ -45,8 +45,6 @@ public class GeoUtil { private static final SpatialContext distCtx = SpatialContext.GEO; private static final JtsSpatialContext jtsCtx; - private static final JsonParser JSON_PARSER = new JsonParser(); - static { JtsSpatialContextFactory factory = new JtsSpatialContextFactory(); factory.normWrapLongitude = true; @@ -64,7 +62,7 @@ public class GeoUtil { throw new RuntimeException("Polygon string can't be empty or null!"); } - JsonArray polygonsJson = normalizePolygonsJson(JSON_PARSER.parse(polygonInString).getAsJsonArray()); + JsonArray polygonsJson = normalizePolygonsJson(JsonParser.parseString(polygonInString).getAsJsonArray()); List polygons = buildPolygonsFromJson(polygonsJson); Set holes = extractHolesFrom(polygons); polygons.removeIf(holes::contains); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java index a6b2433df4..772d278ee8 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java @@ -50,9 +50,6 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R class TbAssetTypeSwitchNodeTest { - private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); - private static final String EMPTY_DATA = "{}"; - private AssetId assetId; private AssetId assetIdDeleted; private TbContext ctx; @@ -121,7 +118,7 @@ class TbAssetTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, EMPTY_METADATA, EMPTY_DATA, callback); + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java index a794b96620..7bb8365895 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java @@ -52,7 +52,6 @@ class TbCheckAlarmStatusNodeTest { private static final DeviceId DEVICE_ID = new DeviceId(UUID.randomUUID()); private static final AlarmId ALARM_ID = new AlarmId(UUID.randomUUID()); private static final TestDbCallbackExecutor DB_EXECUTOR = new TestDbCallbackExecutor(); - private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); private TbCheckAlarmStatusNode node; @@ -160,7 +159,7 @@ class TbCheckAlarmStatusNodeTest { } private TbMsg getTbMsg(String msgData) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, EMPTY_METADATA, msgData); + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, TbMsgMetaData.EMPTY, msgData); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java index 23d6711088..8926f36054 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java @@ -46,9 +46,7 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R class TbCheckMessageNodeTest { private static final DeviceId DEVICE_ID = new DeviceId(UUID.randomUUID()); - private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); - private static final String EMPTY_DATA = "{}"; - private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, EMPTY_METADATA, EMPTY_DATA); + private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY); private TbCheckMessageNode node; @@ -195,7 +193,7 @@ class TbCheckMessageNodeTest { } private TbMsg getTbMsg(boolean emptyData) { - String data = emptyData ? EMPTY_DATA : "{\"temperature-0\": 25}"; + String data = emptyData ? TbMsg.EMPTY : "{\"temperature-0\": 25}"; var metadata = new TbMsgMetaData(); metadata.putValue(DEVICE_NAME, "Test Device"); metadata.putValue(DEVICE_TYPE, DEFAULT_DEVICE_TYPE); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java index 59b2b823bc..926d3b654b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java @@ -26,7 +26,6 @@ import org.thingsboard.rule.engine.TestDbCallbackExecutor; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; @@ -62,9 +61,7 @@ class TbCheckRelationNodeTest { private static final TenantId TENANT_ID = new TenantId(UUID.randomUUID()); private static final DeviceId ORIGINATOR_ID = new DeviceId(UUID.randomUUID()); private static final TestDbCallbackExecutor DB_EXECUTOR = new TestDbCallbackExecutor(); - private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); - private static final String EMPTY_DATA = "{}"; - private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), ORIGINATOR_ID, EMPTY_METADATA, EMPTY_DATA); + private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), ORIGINATOR_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY); private TbCheckRelationNode node; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java index ef76787f94..3fe2e44f5d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java @@ -118,6 +118,6 @@ class TbDeviceTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(), "{}", callback); + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java index b49dd4aac8..2f75bbfe1b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java @@ -59,7 +59,7 @@ public class TbJsFilterNodeTest { @Test public void falseEvaluationDoNotSendMsg() throws TbNodeException { initWithScript(); - TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, new TbMsgMetaData(), TbMsgDataType.JSON, TbMsg.EMPTY, ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(false)); node.onMsg(ctx, msg); @@ -71,7 +71,7 @@ public class TbJsFilterNodeTest { public void exceptionInJsThrowsException() throws TbNodeException { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, metaData, TbMsgDataType.JSON, TbMsg.EMPTY, ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFailedFuture(new ScriptException("error"))); @@ -83,7 +83,7 @@ public class TbJsFilterNodeTest { public void metadataConditionCanBeTrue() throws TbNodeException { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, metaData, TbMsgDataType.JSON, TbMsg.EMPTY, ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java index 7814c82662..e79e2b77eb 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java @@ -97,7 +97,7 @@ class TbMsgTypeFilterNodeTest { } private TbMsg getTbMsg(EntityId entityId, TbMsgType msgType) { - return TbMsg.newMsg(msgType.name(), entityId, new TbMsgMetaData(), "{}"); + return TbMsg.newMsg(msgType.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java index d43d309cda..cd4e21182f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java @@ -40,8 +40,6 @@ import static org.mockito.Mockito.verify; class TbMsgTypeSwitchNodeTest { private static final DeviceId DEVICE_ID = new DeviceId(UUID.randomUUID()); - private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); - private static final String EMPTY_DATA = "{}"; private TbMsgTypeSwitchNode node; @@ -90,7 +88,7 @@ class TbMsgTypeSwitchNodeTest { } private TbMsg getTbMsg(TbMsgType msgType) { - return TbMsg.newMsg(msgType.name(), DEVICE_ID, EMPTY_METADATA, EMPTY_DATA); + return TbMsg.newMsg(msgType.name(), DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java index 86ba9d1fd0..852552537f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java @@ -96,7 +96,7 @@ class TbOriginatorTypeFilterNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(), "{}"); + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java index 28d8b55264..64eb40fc41 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java @@ -42,8 +42,6 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_R class TbOriginatorTypeSwitchNodeTest { private static final UUID RANDOM_UUID = UUID.randomUUID(); - private static final TbMsgMetaData EMPTY_METADATA = new TbMsgMetaData(); - private static final String EMPTY_DATA = "{}"; private TbOriginatorTypeSwitchNode node; @@ -92,7 +90,7 @@ class TbOriginatorTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, EMPTY_METADATA, EMPTY_DATA); + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGeoUtilTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/GeoUtilTest.java similarity index 99% rename from rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGeoUtilTest.java rename to rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/GeoUtilTest.java index 6a03a8f362..f53a876954 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGeoUtilTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/GeoUtilTest.java @@ -21,7 +21,7 @@ import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) -public class TbGeoUtilTest { +public class GeoUtilTest { public static final String SIMPLE_RECT = "[[51.903762928405555,23.642220786948297],[44.669801219635644,41.83345155830211]]"; public static final String SIMPLE_RECT_WITH_HOLE_IN_CENTER = "[[[44.66980121963565,23.642220786948297],[44.66980121963565,41.83345155830211],[51.903762928405555,41.83345155830211],[51.903762928405555,23.642220786948297]],[[46.10464044504632,26.234282119122227],[50.8755868028522,26.25625220459488],[51.04164771375101,38.5595000692786],[45.99790855491869,38.75723083853248]]]"; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java new file mode 100644 index 0000000000..1a01dda8c2 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java @@ -0,0 +1,460 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.geo; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.thingsboard.rule.engine.geo.GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER; +import static org.thingsboard.rule.engine.geo.GeoUtilTest.POINT_OUTSIDE_SIMPLE_RECT; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; + +class TbGpsGeofencingFilterNodeTest { + + private static final double CIRCLE_RANGE = 1.0; + private static final Coordinates CIRCLE_CENTER = new Coordinates(49.0384, 31.4513); + private static final Coordinates POINT_INSIDE_CIRCLE = new Coordinates(49.0354, 31.4513); // distance from center: 0.334 km + private static final Coordinates POINT_OUTSIDE_CIRCLE = new Coordinates(49.0284, 31.4513); // distance from center: 1.112 km + + private TbContext ctx; + private TbGpsGeofencingFilterNode node; + + @BeforeEach + void setUp() { + ctx = mock(TbContext.class); + node = new TbGpsGeofencingFilterNode(); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + // Exception tests + + @Test + void givenDefaultConfig_whenOnMsg_thenExceptionInvalidMsg() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsg msg = getEmptyArrayTbMsg(deviceId); + + // WHEN + var exception = assertThrows(TbNodeException.class, () -> node.onMsg(ctx, msg)); + + // THEN + assertThat(exception.getMessage()).isEqualTo("Incoming Message is not a valid JSON object!"); + } + + @Test + void givenDefaultConfig_whenOnMsg_thenExceptionMissingPerimeterDefinitionNewVersion() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, + POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + + // WHEN + var exception = assertThrows(TbNodeException.class, () -> node.onMsg(ctx, msg)); + + // THEN + assertThat(exception.getMessage()).isEqualTo("Missing perimeter definition!"); + } + + @Test + void givenTypePolygonAndConfigWithoutPerimeterKeyName_whenOnMsg_thenExceptionMissingPerimeterDefinitionOldVersion() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setPerimeterKeyName(null); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, + POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + + // WHEN + var exception = assertThrows(TbNodeException.class, () -> node.onMsg(ctx, msg)); + + // THEN + assertThat(exception.getMessage()).isEqualTo("Missing perimeter definition!"); + } + + // Polygon tests + + @Test + void givenTypePolygonAndConfigWithoutPerimeterKeyName_whenOnMsg_thenTrue() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setPerimeterKeyName(null); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsgMetaData metadata = getMetadataForOldVersionPolygonPerimeter(); + TbMsg msg = getTbMsg(deviceId, metadata, + POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenTypePolygonAndConfigWithoutPerimeterKeyName_whenOnMsg_thenFalse() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setPerimeterKeyName(null); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsgMetaData metadata = getMetadataForOldVersionPolygonPerimeter(); + TbMsg msg = getTbMsg(deviceId, metadata, + POINT_OUTSIDE_SIMPLE_RECT.getLatitude(), POINT_OUTSIDE_SIMPLE_RECT.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenDefaultConfig_whenOnMsg_thenTrue() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsgMetaData metadata = getMetadataForNewVersionPolygonPerimeter(); + TbMsg msg = getTbMsg(deviceId, metadata, + POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenDefaultConfig_whenOnMsg_thenFalse() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsgMetaData metadata = getMetadataForNewVersionPolygonPerimeter(); + TbMsg msg = getTbMsg(deviceId, metadata, + POINT_OUTSIDE_SIMPLE_RECT.getLatitude(), POINT_OUTSIDE_SIMPLE_RECT.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenTypePolygonAndConfigWithPolygonDefined_whenOnMsg_thenTrue() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setFetchPerimeterInfoFromMessageMetadata(false); + config.setPolygonsDefinition(GeoUtilTest.SIMPLE_RECT); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, + POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenTypePolygonAndConfigWithPolygonDefined_whenOnMsg_thenFalse() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setFetchPerimeterInfoFromMessageMetadata(false); + config.setPolygonsDefinition(GeoUtilTest.SIMPLE_RECT); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, + POINT_OUTSIDE_SIMPLE_RECT.getLatitude(), POINT_OUTSIDE_SIMPLE_RECT.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + private TbMsgMetaData getMetadataForOldVersionPolygonPerimeter() { + var metadata = new TbMsgMetaData(); + metadata.putValue("perimeter", GeoUtilTest.SIMPLE_RECT); + return metadata; + } + + private TbMsgMetaData getMetadataForNewVersionPolygonPerimeter() { + var metadata = new TbMsgMetaData(); + metadata.putValue("ss_perimeter", GeoUtilTest.SIMPLE_RECT); + return metadata; + } + + // Circle tests + + @Test + void givenTypeCircleAndConfigWithoutPerimeterKeyName_whenOnMsg_thenTrue() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setPerimeterKeyName(null); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsgMetaData metadata = getMetadataForOldVersionCirclePerimeter(); + TbMsg msg = getTbMsg(deviceId, metadata, + POINT_INSIDE_CIRCLE.getLatitude(), POINT_INSIDE_CIRCLE.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenTypeCircleAndConfigWithoutPerimeterKeyName_whenOnMsg_thenFalse() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setPerimeterKeyName(null); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsgMetaData metadata = getMetadataForOldVersionCirclePerimeter(); + TbMsg msg = getTbMsg(deviceId, metadata, + POINT_OUTSIDE_CIRCLE.getLatitude(), POINT_OUTSIDE_CIRCLE.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenTypeCircle_whenOnMsg_thenTrue() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setPerimeterType(PerimeterType.CIRCLE); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsgMetaData metadata = getMetadataForNewVersionCirclePerimeter(); + TbMsg msg = getTbMsg(deviceId, metadata, + POINT_INSIDE_CIRCLE.getLatitude(), POINT_INSIDE_CIRCLE.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenTypeCircle_whenOnMsg_thenFalse() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setPerimeterType(PerimeterType.CIRCLE); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsgMetaData metadata = getMetadataForNewVersionCirclePerimeter(); + TbMsg msg = getTbMsg(deviceId, metadata, + POINT_OUTSIDE_CIRCLE.getLatitude(), POINT_OUTSIDE_CIRCLE.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenTypeCircleAndConfigWithCircleDefined_whenOnMsg_thenTrue() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setFetchPerimeterInfoFromMessageMetadata(false); + config.setPerimeterType(PerimeterType.CIRCLE); + config.setCenterLatitude(CIRCLE_CENTER.getLatitude()); + config.setCenterLongitude(CIRCLE_CENTER.getLongitude()); + config.setRange(CIRCLE_RANGE); + config.setRangeUnit(RangeUnit.KILOMETER); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, + POINT_INSIDE_CIRCLE.getLatitude(), POINT_INSIDE_CIRCLE.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.TRUE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + @Test + void givenTypeCircleAndConfigWithCircleDefined_whenOnMsg_thenFalse() throws TbNodeException { + // GIVEN + var config = new TbGpsGeofencingFilterNodeConfiguration().defaultConfiguration(); + config.setFetchPerimeterInfoFromMessageMetadata(false); + config.setPerimeterType(PerimeterType.CIRCLE); + config.setCenterLatitude(CIRCLE_CENTER.getLatitude()); + config.setCenterLongitude(CIRCLE_CENTER.getLongitude()); + config.setRange(CIRCLE_RANGE); + config.setRangeUnit(RangeUnit.KILOMETER); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + DeviceId deviceId = new DeviceId(UUID.randomUUID()); + TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, + POINT_OUTSIDE_CIRCLE.getLatitude(), POINT_OUTSIDE_CIRCLE.getLongitude()); + + // WHEN + node.onMsg(ctx, msg); + + // THEN + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq(TbNodeConnectionType.FALSE)); + verify(ctx, never()).tellFailure(any(), any()); + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + private TbMsgMetaData getMetadataForOldVersionCirclePerimeter() { + var metadata = new TbMsgMetaData(); + metadata.putValue("centerLatitude", String.valueOf(CIRCLE_CENTER.getLatitude())); + metadata.putValue("centerLongitude", String.valueOf(CIRCLE_CENTER.getLongitude())); + metadata.putValue("range", String.valueOf(CIRCLE_RANGE)); + metadata.putValue("rangeUnit", String.valueOf(RangeUnit.KILOMETER)); + return metadata; + } + + private TbMsgMetaData getMetadataForNewVersionCirclePerimeter() { + ObjectNode perimeter = JacksonUtil.newObjectNode(); + perimeter.put("latitude", CIRCLE_CENTER.getLatitude()); + perimeter.put("longitude", CIRCLE_CENTER.getLongitude()); + perimeter.put("radius", CIRCLE_RANGE); + perimeter.put("radiusUnit", String.valueOf(RangeUnit.KILOMETER)); + var metadata = new TbMsgMetaData(); + metadata.putValue("ss_perimeter", JacksonUtil.toString(perimeter)); + return metadata; + } + + private TbMsg getTbMsg(EntityId entityId, TbMsgMetaData metadata, double latitude, double longitude) { + String data = "{\"latitude\": " + latitude + ", \"longitude\": " + longitude + "}"; + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, metadata, data); + } + + private TbMsg getEmptyArrayTbMsg(EntityId entityId) { + return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, "[]"); + } + +} From c7823a26afcbf0a45b34a801668f5fc208a6c1f8 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 4 Jul 2023 19:58:55 +0300 Subject: [PATCH 194/421] UI: Alarms table widget basic config. --- .../system/widget_bundles/alarm_widgets.json | 8 +- .../alarm/alarm-assignee-panel.component.html | 6 +- .../alarm/alarm-assignee-panel.component.ts | 19 ++- .../alarm-assignee-select-panel.component.ts | 23 ++- .../alarm-assignee-select.component.html | 12 +- .../alarm/alarm-assignee-select.component.ts | 55 +++++- .../alarm/alarm-assignee.component.scss | 23 ++- .../alarm/alarm-filter-config.component.html | 61 +++---- .../alarm/alarm-filter-config.component.ts | 32 ++-- .../alarms-table-basic-config.component.html | 100 +++++++++++ .../alarms-table-basic-config.component.ts | 160 ++++++++++++++++++ .../basic/basic-widget-config.module.ts | 8 +- ...entities-table-basic-config.component.html | 2 +- .../simple-card-basic-config.component.html | 6 + .../simple-card-basic-config.component.ts | 19 ++- ...meseries-table-basic-config.component.html | 2 +- .../chart/flot-basic-config.component.html | 9 + .../chart/flot-basic-config.component.ts | 1 + .../basic/common/data-key-row.component.html | 4 +- .../basic/common/data-key-row.component.ts | 8 + .../common/data-keys-panel.component.html | 4 +- .../basic/common/data-keys-panel.component.ts | 8 + .../widget/config/datasources.component.html | 2 +- .../widget/config/datasources.component.ts | 9 +- .../lib/alarms-table-widget.component.ts | 8 +- ui-ngx/src/app/shared/models/alarm.models.ts | 5 + ui-ngx/src/styles.scss | 54 ++++-- 27 files changed, 547 insertions(+), 101 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts diff --git a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json index 16a155cebb..7f1def31ac 100644 --- a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json @@ -3,7 +3,9 @@ "alias": "alarm_widgets", "title": "Alarm widgets", "image": "data:image/png;base64,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", - "description": "Visualization of alarms for devices, assets and other entities." + "description": "Visualization of alarms for devices, assets and other entities.", + "externalId": null, + "name": "Alarm widgets" }, "widgetTypes": [ { @@ -23,7 +25,9 @@ "dataKeySettingsSchema": "", "settingsDirective": "tb-alarms-table-widget-settings", "dataKeySettingsDirective": "tb-alarms-table-key-settings", - "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayActivity\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false}" + "hasBasicMode": true, + "basicModeDirective": "tb-alarms-table-basic-config", + "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayActivity\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true,\"entitiesTitle\":null},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"warning\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false,\"configMode\":\"basic\",\"alarmFilterConfig\":null}" } } ] diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-panel.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-panel.component.html index 8f43f27964..8d178aaa2c 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-panel.component.html @@ -26,10 +26,14 @@ #userAutocomplete="matAutocomplete" [displayWith]="displayUserFn" (optionSelected)="selected($event)"> - + account_circle {{ assigneeNotSetText | translate }} + + account_circle + {{ assignedToCurrentUserText | translate }} + ('AlarmAssigneePanelData'); @@ -59,15 +60,19 @@ export interface AlarmAssigneePanelData { }) export class AlarmAssigneePanelComponent implements OnInit, AfterViewInit, OnDestroy { + assigneeOptions = AlarmAssigneeOption; + private dirty = false; alarmId: string; assigneeId?: string; + assigneeOption?: AlarmAssigneeOption = null; assigneeNotSetText = 'alarm.unassigned'; + assignedToCurrentUserText = ''; - reassigned: boolean = false; + reassigned = false; selectUserFormGroup: FormGroup; @@ -77,6 +82,14 @@ export class AlarmAssigneePanelComponent implements OnInit, AfterViewInit, OnDe searchText = ''; + get displayAssigneeNotSet(): boolean { + return !!this.assigneeId; + } + + get displayAssignedToCurrentUser(): boolean { + return false; + } + private destroy$ = new Subject(); constructor(@Inject(ALARM_ASSIGNEE_PANEL_DATA) public data: AlarmAssigneePanelData, @@ -124,8 +137,8 @@ export class AlarmAssigneePanelComponent implements OnInit, AfterViewInit, OnDe selected(event: MatAutocompleteSelectedEvent): void { this.clear(); - const user: User = event.option.value; - if (user) { + if (event.option.value?.id) { + const user: User = event.option.value; this.assign(user); } else { this.unassign(); diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select-panel.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select-panel.component.ts index 1526616833..cd8ce2ec33 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select-panel.component.ts @@ -36,11 +36,14 @@ import { emptyPageData } from '@shared/models/page/page-data'; import { OverlayRef } from '@angular/cdk/overlay'; import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { UtilsService } from '@core/services/utils.service'; +import { AlarmAssigneeOption } from '@shared/models/alarm.models'; export const ALARM_ASSIGNEE_SELECT_PANEL_DATA = new InjectionToken('AlarmAssigneeSelectPanelData'); export interface AlarmAssigneeSelectPanelData { assigneeId?: string; + assigneeOption?: AlarmAssigneeOption; + userMode?: boolean; } @Component({ @@ -50,11 +53,15 @@ export interface AlarmAssigneeSelectPanelData { }) export class AlarmAssigneeSelectPanelComponent implements OnInit, AfterViewInit, OnDestroy { + assigneeOptions = AlarmAssigneeOption; + private dirty = false; assigneeId?: string; + assigneeOption?: AlarmAssigneeOption; assigneeNotSetText = 'alarm.assignee-not-set'; + assignedToCurrentUserText = this.data.userMode ? 'alarm.assigned-to-me' : 'alarm.assigned-to-current-user'; selectUserFormGroup: FormGroup; @@ -67,6 +74,15 @@ export class AlarmAssigneeSelectPanelComponent implements OnInit, AfterViewInit userSelected = false; result?: UserEmailInfo; + optionResult?: AlarmAssigneeOption; + + get displayAssigneeNotSet(): boolean { + return this.assigneeOption !== AlarmAssigneeOption.noAssignee; + } + + get displayAssignedToCurrentUser(): boolean { + return this.assigneeOption !== AlarmAssigneeOption.currentUser; + } private destroy$ = new Subject(); @@ -77,6 +93,7 @@ export class AlarmAssigneeSelectPanelComponent implements OnInit, AfterViewInit private fb: FormBuilder, private utilsService: UtilsService) { this.assigneeId = data.assigneeId; + this.assigneeOption = data.assigneeOption; this.selectUserFormGroup = this.fb.group({ user: [null] }); @@ -112,7 +129,11 @@ export class AlarmAssigneeSelectPanelComponent implements OnInit, AfterViewInit selected(event: MatAutocompleteSelectedEvent): void { this.clear(); this.userSelected = true; - this.result = event.option.value; + if (event.option.value?.id) { + this.result = event.option.value; + } else { + this.optionResult = event.option.value; + } this.overlayRef.dispose(); } diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.html index 2ad7229365..c07a4cb3c6 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.html @@ -16,16 +16,16 @@ --> - - alarm.assignee + subscriptSizing="dynamic" [appearance]="inline ? 'outline' : 'fill'"> + alarm.assignee - {{ getUserInitials() }} - account_circle - arrow_drop_down + account_circle + arrow_drop_down diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.ts index 4d1f6021be..50918bfd0d 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.ts @@ -30,6 +30,8 @@ import { AlarmAssigneeSelectPanelComponent, AlarmAssigneeSelectPanelData } from '@home/components/alarm/alarm-assignee-select-panel.component'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { AlarmAssigneeOption } from '@shared/models/alarm.models'; @Component({ selector: 'tb-alarm-assignee-select', @@ -47,8 +49,17 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso @Input() disabled: boolean; + @coerceBoolean() + @Input() + inline = false; + + @coerceBoolean() + @Input() + userMode = false; + assigneeFormGroup: UntypedFormGroup; assignee?: User | UserEmailInfo; + assigneeOption?: AlarmAssigneeOption; private propagateChange = (_: any) => {}; @@ -82,7 +93,15 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso } } - writeValue(userId?: UserId): void { + writeValue(value?: UserId | AlarmAssigneeOption): void { + let userId: UserId; + if (value && (value as UserId).id) { + userId = value as UserId; + this.assigneeOption = null; + } else { + userId = null; + this.assigneeOption = value ? value as AlarmAssigneeOption : AlarmAssigneeOption.noAssignee; + } const userObservable = userId ? this.userService.getUser(userId.id, {ignoreErrors: true}).pipe( catchError(() => of(null)) ) : of(null); @@ -92,15 +111,31 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso }), map((user) => this.getAssignee(user)) ).subscribe((assignee) => { - this.assigneeFormGroup.get('assignee').patchValue(assignee, {emitEvent: false}); + if (assignee) { + this.assigneeFormGroup.get('assignee').patchValue(assignee, {emitEvent: false}); + } else { + if (!this.assigneeOption) { + this.assigneeOption = AlarmAssigneeOption.noAssignee; + } + assignee = this.getAssigneeOption(this.assigneeOption); + this.assigneeFormGroup.get('assignee').patchValue(assignee, {emitEvent: false}); + } }); } - private getAssignee(user?: User| UserEmailInfo): string { + private getAssignee(user?: User| UserEmailInfo): string | null { if (user) { return this.getUserDisplayName(user); } else { + return null; + } + } + + private getAssigneeOption(assigneeOption: AlarmAssigneeOption): string { + if (assigneeOption === AlarmAssigneeOption.noAssignee) { return this.translateService.instant('alarm.assignee-not-set'); + } else { + return this.translateService.instant(this.userMode ? 'alarm.assigned-to-me' : 'alarm.assigned-to-current-user'); } } @@ -169,7 +204,9 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso { provide: ALARM_ASSIGNEE_SELECT_PANEL_DATA, useValue: { - assigneeId: this.assignee?.id?.id + assigneeId: this.assignee?.id?.id, + assigneeOption: this.assigneeOption, + userMode: this.userMode } as AlarmAssigneeSelectPanelData }, { @@ -183,8 +220,14 @@ export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccesso component.onDestroy(() => { if (component.instance.userSelected) { this.assignee = component.instance.result; - this.assigneeFormGroup.get('assignee').patchValue(this.getAssignee(this.assignee), {emitEvent: false}); - this.propagateChange(this.assignee?.id); + this.assigneeOption = component.instance.optionResult; + if (this.assignee) { + this.assigneeFormGroup.get('assignee').patchValue(this.getAssignee(this.assignee), {emitEvent: false}); + this.propagateChange(this.assignee?.id); + } else if (this.assigneeOption) { + this.assigneeFormGroup.get('assignee').patchValue(this.getAssigneeOption(this.assigneeOption), {emitEvent: false}); + this.propagateChange(this.assigneeOption); + } } }); } 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 82f10650cf..947eeb01d0 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 @@ -19,20 +19,14 @@ justify-content: center; align-items: center; border-radius: 50%; - width: 28px; - height: 28px; min-width: 28px; min-height: 28px; color: white; font-size: 13px; font-weight: 700; - margin-left: 12px; - margin-right: 20px; } .unassigned-icon { - width: 28px; - height: 28px; font-size: 28px; color: rgba(0, 0, 0, 0.38); overflow: visible; @@ -40,3 +34,20 @@ margin-right: 20px; padding: 0; } + +.user-avatar, .unassigned-icon { + width: 28px; + height: 28px; + margin-left: 12px; + margin-right: 20px; + &.inline { + margin-left: 0; + margin-right: 8px; + } +} + +.drop-down-icon { + &.inline { + margin-right: -12px; + } +} diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html index a2a0c158a5..cbf1da82f6 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html @@ -48,32 +48,26 @@ -
-
- - alarm.alarm-status-list - - - {{ alarmSearchStatusTranslationMap.get(searchStatus) | translate }} - - - - - alarm.alarm-severity-list - - - {{ alarmSeverityTranslationMap.get(alarmSeverityEnum[alarmSeverity]) | translate }} - - - +
+
+
alarm.alarm-status-list
+ + + {{ alarmSearchStatusTranslationMap.get(searchStatus) | translate }} + + +
+
+
alarm.alarm-severity-list
+ + + {{ alarmSeverityTranslationMap.get(alarmSeverityEnum[alarmSeverity]) | translate }} + +
-
- - alarm.alarm-type-list +
+
alarm.alarm-type-list
+ @@ -88,16 +82,15 @@
-
- - {{ 'alarm.search-propagated-alarms' | translate }} - - - {{ (userMode ? 'alarm.assigned-to-me' : 'alarm.assigned-to-current-user') | translate }} - - +
+
alarm.assignee
+
+ + {{ 'alarm.search-propagated-alarms' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts index b46fbf506c..96f7717e3d 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.ts @@ -34,6 +34,7 @@ import { coerceBoolean } from '@shared/decorators/coercion'; import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { TemplatePortal } from '@angular/cdk/portal'; import { + AlarmAssigneeOption, AlarmSearchStatus, alarmSearchStatusTranslations, AlarmSeverity, @@ -133,12 +134,10 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal severityList: [null, []], typeList: [null, []], searchPropagatedAlarms: [false, []], - assignedToCurrentUser: [false, []], - assigneeId: [null, []] + assigneeId: [AlarmAssigneeOption.noAssignee, []] }); this.alarmFilterConfigForm.valueChanges.subscribe( () => { - this.updateValidators(); if (!this.buttonMode) { this.alarmConfigUpdated(this.alarmFilterConfigForm.value); } @@ -165,7 +164,6 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal this.alarmFilterConfigForm.disable({emitEvent: false}); } else { this.alarmFilterConfigForm.enable({emitEvent: false}); - this.updateValidators(); } } @@ -175,16 +173,6 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal this.updateAlarmConfigForm(alarmFilterConfig); } - private updateValidators() { - const assignedToCurrentUser = this.alarmFilterConfigForm.get('assignedToCurrentUser').value; - if (assignedToCurrentUser) { - this.alarmFilterConfigForm.get('assigneeId').disable({emitEvent: false}); - } else { - this.alarmFilterConfigForm.get('assigneeId').enable({emitEvent: false}); - } - this.alarmFilterConfigForm.get('assigneeId').updateValueAndValidity({emitEvent: false}); - } - toggleAlarmFilterPanel($event: Event) { if ($event) { $event.stopPropagation(); @@ -276,14 +264,20 @@ export class AlarmFilterConfigComponent implements OnInit, OnDestroy, ControlVal severityList: alarmFilterConfig?.severityList, typeList: alarmFilterConfig?.typeList, searchPropagatedAlarms: alarmFilterConfig?.searchPropagatedAlarms, - assignedToCurrentUser: alarmFilterConfig?.assignedToCurrentUser, - assigneeId: alarmFilterConfig?.assigneeId + assigneeId: alarmFilterConfig?.assignedToCurrentUser ? AlarmAssigneeOption.currentUser : + (alarmFilterConfig?.assigneeId ? alarmFilterConfig?.assigneeId : AlarmAssigneeOption.noAssignee) }, {emitEvent: false}); - this.updateValidators(); } - private alarmConfigUpdated(alarmFilterConfig: AlarmFilterConfig) { - this.alarmFilterConfig = alarmFilterConfig; + private alarmConfigUpdated(formValue: any) { + this.alarmFilterConfig = { + statusList: formValue.statusList, + severityList: formValue.severityList, + typeList: formValue.typeList, + searchPropagatedAlarms: formValue.searchPropagatedAlarms, + assignedToCurrentUser: formValue.assigneeId === AlarmAssigneeOption.currentUser, + assigneeId: formValue.assigneeId?.id ? formValue.assigneeId : null + }; this.updateButtonDisplayValue(); this.propagateChange(this.alarmFilterConfig); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html new file mode 100644 index 0000000000..a5cef1a649 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html @@ -0,0 +1,100 @@ + + + + +
+
alarm.filter
+ +
+ + + + +
+
widget-config.card-appearance
+
+ + {{ 'widget-config.card-title' | translate }} + + + + +
+
+ + {{ 'widget-config.card-icon' | translate }} + +
+ + + + + +
+
+
+
widget-config.show-card-buttons
+ + {{ 'action.search' | translate }} + {{ 'alarm.alarm-filter' | translate }} + {{ 'widgets.table.columns-to-display' | translate }} + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.text-color' | translate }}
+
+ + + +
+
+
+
{{ 'widget-config.background-color' | translate }}
+
+ + + +
+
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts new file mode 100644 index 0000000000..e8dbca5f18 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts @@ -0,0 +1,160 @@ +/// +/// Copyright © 2016-2023 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 } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { isUndefined } from '@core/utils'; +import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; + +@Component({ + selector: 'tb-alarms-table-basic-config', + templateUrl: './alarms-table-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent { + + public get alarmSource(): Datasource { + const datasources: Datasource[] = this.alarmsTableWidgetConfigForm.get('datasources').value; + if (datasources && datasources.length) { + return datasources[0]; + } else { + return null; + } + } + + alarmsTableWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.alarmsTableWidgetConfigForm; + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + this.alarmsTableWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + alarmFilterConfig: [configData.config.alarmFilterConfig, []], + datasources: [[configData.config.alarmSource], []], + columns: [this.getColumns(configData.config.alarmSource), []], + showTitle: [configData.config.showTitle, []], + title: [configData.config.settings?.entitiesTitle, []], + showTitleIcon: [configData.config.showTitleIcon, []], + titleIcon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + color: [configData.config.color, []], + backgroundColor: [configData.config.backgroundColor, []], + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; + this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; + this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + this.widgetConfig.config.alarmFilterConfig = config.alarmFilterConfig; + this.widgetConfig.config.alarmSource = config.datasources[0]; + this.setColumns(config.columns, this.widgetConfig.config.alarmSource); + this.widgetConfig.config.actions = config.actions; + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.widgetConfig.config.settings.entitiesTitle = config.title; + this.widgetConfig.config.showTitleIcon = config.showTitleIcon; + this.widgetConfig.config.titleIcon = config.titleIcon; + this.widgetConfig.config.iconColor = config.iconColor; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.color = config.color; + this.widgetConfig.config.backgroundColor = config.backgroundColor; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showTitleIcon']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.alarmsTableWidgetConfigForm.get('showTitle').value; + const showTitleIcon: boolean = this.alarmsTableWidgetConfigForm.get('showTitleIcon').value; + if (showTitle) { + this.alarmsTableWidgetConfigForm.get('title').enable(); + this.alarmsTableWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); + if (showTitleIcon) { + this.alarmsTableWidgetConfigForm.get('titleIcon').enable(); + this.alarmsTableWidgetConfigForm.get('iconColor').enable(); + } else { + this.alarmsTableWidgetConfigForm.get('titleIcon').disable(); + this.alarmsTableWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.alarmsTableWidgetConfigForm.get('title').disable(); + this.alarmsTableWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); + this.alarmsTableWidgetConfigForm.get('titleIcon').disable(); + this.alarmsTableWidgetConfigForm.get('iconColor').disable(); + } + this.alarmsTableWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.alarmsTableWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); + this.alarmsTableWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); + this.alarmsTableWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); + } + + private getColumns(alarmSource?: Datasource): DataKey[] { + if (alarmSource) { + return alarmSource.dataKeys || []; + } + return []; + } + + private setColumns(columns: DataKey[], alarmSource?: Datasource) { + if (alarmSource) { + alarmSource.dataKeys = columns; + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.settings?.enableSearch) || config.settings?.enableSearch) { + buttons.push('search'); + } + if (isUndefined(config.settings?.enableFilter) || config.settings?.enableFilter) { + buttons.push('filter'); + } + if (isUndefined(config.settings?.enableSelectColumnDisplay) || config.settings?.enableSelectColumnDisplay) { + buttons.push('columnsToDisplay'); + } + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.settings.enableSearch = buttons.includes('search'); + config.settings.enableFilter = buttons.includes('filter'); + config.settings.enableSelectColumnDisplay = buttons.includes('columnsToDisplay'); + config.enableFullscreen = buttons.includes('fullscreen'); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 8b90de1ef0..1ef7550c95 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -35,6 +35,9 @@ import { } from '@home/components/widget/config/basic/cards/timeseries-table-basic-config.component'; import { FlotBasicConfigComponent } from '@home/components/widget/config/basic/chart/flot-basic-config.component'; import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widget-settings.module'; +import { + AlarmsTableBasicConfigComponent +} from '@home/components/widget/config/basic/alarm/alarms-table-basic-config.component'; @NgModule({ declarations: [ @@ -43,6 +46,7 @@ import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widge EntitiesTableBasicConfigComponent, TimeseriesTableBasicConfigComponent, FlotBasicConfigComponent, + AlarmsTableBasicConfigComponent, DataKeyRowComponent, DataKeysPanelComponent ], @@ -58,6 +62,7 @@ import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widge EntitiesTableBasicConfigComponent, TimeseriesTableBasicConfigComponent, FlotBasicConfigComponent, + AlarmsTableBasicConfigComponent, DataKeyRowComponent, DataKeysPanelComponent ] @@ -69,5 +74,6 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type
-
widget-config.appearance
+
widget-config.card-appearance
{{ 'widget-config.card-title' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html index 5c16b9f195..09e8e0d779 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html @@ -61,6 +61,12 @@
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
{{ 'widget-config.text-color' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts index b0e03d66d0..26d7b5ba61 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts @@ -23,11 +23,12 @@ import { WidgetConfigComponentData } from '@home/models/widget-component.models' import { Datasource, datasourcesHasAggregation, - datasourcesHasOnlyComparisonAggregation, + datasourcesHasOnlyComparisonAggregation, WidgetConfig, } from '@shared/models/widget.models'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; +import { isUndefined } from '@core/utils'; @Component({ selector: 'tb-simple-card-basic-config', @@ -70,6 +71,7 @@ export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent { labelPosition: [configData.config.settings?.labelPosition, []], units: [configData.config.units, []], decimals: [configData.config.decimals, []], + cardButtons: [this.getCardButtons(configData.config), []], color: [configData.config.color, []], backgroundColor: [configData.config.backgroundColor, []], actions: [configData.config.actions || {}, []] @@ -85,9 +87,10 @@ export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent { this.widgetConfig.config.actions = config.actions; this.widgetConfig.config.units = config.units; this.widgetConfig.config.decimals = config.decimals; + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); this.widgetConfig.config.color = config.color; this.widgetConfig.config.backgroundColor = config.backgroundColor; - this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; this.widgetConfig.config.settings.labelPosition = config.labelPosition; return this.widgetConfig; } @@ -111,4 +114,16 @@ export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent { } } + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html index a0c3d64e25..2e2439db03 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html @@ -38,7 +38,7 @@ formControlName="columns">
-
widget-config.appearance
+
widget-config.card-appearance
{{ 'widget-config.card-title' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html index 0fff9342fd..59512a4b76 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html @@ -68,6 +68,15 @@ {{ 'fullscreen.fullscreen' | translate }}
+
+
{{ 'widget-config.text-color' | translate }}
+
+ + + +
+
{{ 'widget-config.background-color' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts index 7f529c490f..9d3dc4f1dd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts @@ -94,6 +94,7 @@ export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { this.widgetConfig.config.iconColor = config.iconColor; this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.color = config.color; this.widgetConfig.config.backgroundColor = config.backgroundColor; this.widgetConfig.config.settings.grid = this.widgetConfig.config.settings.grid || {}; this.widgetConfig.config.settings.grid.verticalLines = config.verticalLines; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html index e8bc229488..b639d08512 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html @@ -147,12 +147,12 @@ formControlName="color">
-
+
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts index b0e52ee758..7cdf277631 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.ts @@ -145,6 +145,14 @@ export class DataKeyRowComponent implements ControlValueAccessor, OnInit, OnChan return this.dataKeysPanelComponent.hideDataKeyColor; } + get hideUnits(): boolean { + return this.dataKeysPanelComponent.hideUnits; + } + + get hideDecimals(): boolean { + return this.dataKeysPanelComponent.hideDecimals; + } + get widgetType(): widgetType { return this.widgetConfigComponent.widgetType; } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html index 23aab3c720..fcf50139e1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html @@ -23,8 +23,8 @@
datakey.key
datakey.label
datakey.color
-
widget-config.units-short
-
widget-config.decimals-short
+
widget-config.units-short
+
widget-config.decimals-short
-
{{ (singleDatasource ? 'widget-config.datasource' : 'widget-config.datasources') | translate }}
+
{{ (singleDatasource ? (isAlarmSource ? 'widget-config.alarm-source' : 'widget-config.datasource') : 'widget-config.datasources') | translate }}
{{ 'widget-config.timeseries-key-error' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts index 9900fe90f4..62305195a1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts @@ -64,12 +64,17 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid datasourceType = DatasourceType; + + public get isAlarmSource(): boolean { + return this.widgetConfigComponent.widgetType === widgetType.alarm; + } + public get basicMode(): boolean { return !this.widgetConfigComponent.widgetEditMode && this.configMode === WidgetConfigMode.basic; } public get maxDatasources(): number { - return this.forceSingleDatasource ? 1 : this.widgetConfigComponent.modelValue?.typeParameters?.maxDatasources; + return (this.forceSingleDatasource || this.isAlarmSource) ? 1 : this.widgetConfigComponent.modelValue?.typeParameters?.maxDatasources; } public get singleDatasource(): boolean { @@ -266,7 +271,7 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid private configModeChanged() { if (this.basicMode) { - let datasourcesMode = this.detectDatasourcesMode(this.datasourcesFormGroup.get('datasources').value); + const datasourcesMode = this.detectDatasourcesMode(this.datasourcesFormGroup.get('datasources').value); this.datasourcesModeChange(datasourcesMode); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 6b0537d968..0927114e1c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -138,6 +138,8 @@ import { AlarmFilterConfigComponent, AlarmFilterConfigData } from '@home/components/alarm/alarm-filter-config.component'; +import { getCurrentAuthUser } from '@core/auth/auth.selectors'; +import { UserId } from '@shared/models/id/user-id'; interface AlarmsTableWidgetSettings extends TableWidgetSettings { alarmsTitle: string; @@ -606,6 +608,9 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, overlayRef.backdropClick().subscribe(() => { overlayRef.dispose(); }); + const authUser = getCurrentAuthUser(this.store); + const assignedToCurrentUser = isDefinedAndNotNull(this.pageLink.assigneeId) && this.pageLink.assigneeId.id === authUser.userId; + const assigneeId = assignedToCurrentUser ? null : this.pageLink.assigneeId; const providers: StaticProvider[] = [ { provide: ALARM_FILTER_CONFIG_DATA, @@ -617,7 +622,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, severityList: deepClone(this.pageLink.severityList), typeList: deepClone(this.pageLink.typeList), searchPropagatedAlarms: this.pageLink.searchPropagatedAlarms, - assignedToCurrentUser: isDefinedAndNotNull(this.pageLink.assigneeId) + assignedToCurrentUser, + assigneeId } } as AlarmFilterConfigData }, diff --git a/ui-ngx/src/app/shared/models/alarm.models.ts b/ui-ngx/src/app/shared/models/alarm.models.ts index 202b25d539..49f780beeb 100644 --- a/ui-ngx/src/app/shared/models/alarm.models.ts +++ b/ui-ngx/src/app/shared/models/alarm.models.ts @@ -145,6 +145,11 @@ export interface AlarmAssignee { email: string; } +export enum AlarmAssigneeOption { + noAssignee = 'noAssignee', + currentUser = 'currentUser' +} + export interface AlarmDataInfo extends AlarmInfo { actionCellButtons?: TableCellButtonActionDescriptor[]; hasActions?: boolean; diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index 22e9a2f751..0f1a64aa97 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -1209,6 +1209,10 @@ mat-label { border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 6px; } + &.no-border { + box-shadow: none; + border-radius: 0; + } &.tb-slide-toggle { padding: 0; gap: 0; @@ -1297,7 +1301,9 @@ mat-label { color: #808080; } .tb-widget-config-row { - height: 56px; + height: 100%; + padding-top: 7px; + padding-bottom: 7px; display: flex; flex-direction: row; align-items: center; @@ -1314,6 +1320,8 @@ mat-label { } .mat-divider-vertical { height: 56px; + margin-top: -7px; + margin-bottom: -7px; } .mat-mdc-form-field { width: 106px; @@ -1324,6 +1332,29 @@ mat-label { .fixed-title-width { min-width: 200px; } + .mat-slide:only-child { + margin: 8px 0; + } + &.tb-chips { + .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + .mat-mdc-form-field-infix { + padding-top: 4px; + padding-bottom: 4px; + + .mdc-evolution-chip-set { + min-height: 32px; + + .mdc-evolution-chip { + height: 24px; + } + } + } + } + } + } + } } .tb-widget-config-row .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { @@ -1361,7 +1392,12 @@ mat-label { } } .mat-mdc-form-field-icon-suffix { - button.mat-mdc-icon-button { + height: 40px; + font-size: 14px; + line-height: 40px; + letter-spacing: 0.2px; + color: rgba(0, 0, 0, 0.38); + > button.mat-mdc-icon-button { width: 40px; height: 40px; padding: 8px; @@ -1371,6 +1407,12 @@ mat-label { font-size: 20px; } } + > .mat-icon { + width: 20px; + height: 20px; + padding: 10px; + font-size: 20px; + } } } } @@ -1394,14 +1436,6 @@ mat-label { } } } - .mat-mdc-form-field-flex { - .mat-mdc-form-field-icon-suffix { - font-size: 14px; - line-height: 20px; - letter-spacing: 0.2px; - color: rgba(0, 0, 0, 0.38); - } - } } } From ea2d5485f4daa98f91defda9fa4a4b7f947c1e77 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Wed, 5 Jul 2023 12:46:35 +0300 Subject: [PATCH 195/421] Remove Slack from user-level settings --- .../data/notification/NotificationDeliveryMethod.java | 6 ------ .../notification/settings/UserNotificationSettings.java | 8 +++++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java index ac878adac6..4a2c4657d5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/NotificationDeliveryMethod.java @@ -18,10 +18,6 @@ package org.thingsboard.server.common.data.notification; import lombok.Getter; import lombok.RequiredArgsConstructor; -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; - @RequiredArgsConstructor public enum NotificationDeliveryMethod { @@ -33,6 +29,4 @@ public enum NotificationDeliveryMethod { @Getter private final String name; - public static final Set values = Arrays.stream(values()).collect(Collectors.toSet()); - } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java b/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java index f24520bc32..b7af57238b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/notification/settings/UserNotificationSettings.java @@ -39,6 +39,8 @@ public class UserNotificationSettings { public static final UserNotificationSettings DEFAULT = new UserNotificationSettings(Collections.emptyMap()); + private static final Set deliveryMethods = NotificationTargetType.PLATFORM_USERS.getSupportedDeliveryMethods(); + @JsonCreator public UserNotificationSettings(@JsonProperty("prefs") Map prefs) { this.prefs = prefs; @@ -49,7 +51,7 @@ public class UserNotificationSettings { if (pref != null) { return pref.isEnabled() ? pref.getEnabledDeliveryMethods() : Collections.emptySet(); } else { - return NotificationDeliveryMethod.values; + return deliveryMethods; } } @@ -62,14 +64,14 @@ public class UserNotificationSettings { public static NotificationPref createDefault() { NotificationPref pref = new NotificationPref(); pref.setEnabled(true); - pref.setEnabledDeliveryMethods(NotificationDeliveryMethod.values); + pref.setEnabledDeliveryMethods(deliveryMethods); return pref; } @JsonIgnore @AssertTrue(message = "Only email, Web and SMS delivery methods are allowed") public boolean isValid() { - return NotificationTargetType.PLATFORM_USERS.getSupportedDeliveryMethods().containsAll(enabledDeliveryMethods); + return deliveryMethods.containsAll(enabledDeliveryMethods); } } From 95f10e016bbc248ab700e50faa51ef2b6b5baf52 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 5 Jul 2023 13:06:54 +0300 Subject: [PATCH 196/421] UI: Change style add device dialog; Change device credentials style in mobile mode --- .../device/device-credentials.component.html | 10 +--------- .../wizard/device-wizard-dialog.component.html | 4 ++-- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html index 1bd319587b..fd666e1398 100644 --- a/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html +++ b/ui-ngx/src/app/modules/home/components/device/device-credentials.component.html @@ -16,15 +16,7 @@ -->
- - device.credentials-type - - - {{ credentialTypeNamesMap.get(credentialsType) }} - - - -
+
device.credentials-type
diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index be6caba2ab..cc1aa3235c 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -79,9 +79,9 @@ {{ 'device.overwrite-activity-time' | translate }}
- + device.description - + From 88b1bfc95bbd762a01bcfa6ecf60ade9a7da1203 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 5 Jul 2023 13:19:29 +0300 Subject: [PATCH 197/421] UI: User notification settings by notification type and remove slack --- .../notification-setting-form.component.html | 2 +- .../notification-setting-form.component.ts | 12 ++++++--- .../notification-settings.component.ts | 27 ++++++++++++++----- .../app/shared/models/notification.models.ts | 4 +-- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html index 9aa733bee5..a4e7e062b5 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html @@ -26,7 +26,7 @@ - {{notificationSettingsFormGroup.get('ruleName').value}} + {{notificationTemplateTypeTranslateMap.get(notificationSettingsFormGroup.get('name').value)?.name | translate}}
diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts index 1c73ed8a8c..9e8df2e107 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts @@ -19,7 +19,11 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFor import { UtilsService } from '@core/services/utils.service'; import { isDefinedAndNotNull } from '@core/utils'; import { Subscription } from 'rxjs'; -import { NotificationDeliveryMethod, NotificationUserSetting } from '@shared/models/notification.models'; +import { + NotificationDeliveryMethod, + NotificationTemplateTypeTranslateMap, + NotificationUserSetting +} from '@shared/models/notification.models'; @Component({ selector: 'tb-notification-setting-form', @@ -44,7 +48,8 @@ export class NotificationSettingFormComponent implements ControlValueAccessor, O notificationSettingsFormGroup: UntypedFormGroup; notificationDeliveryMethod = NotificationDeliveryMethod; - notificationDeliveryMethodMap = Object.keys(NotificationDeliveryMethod) as NotificationDeliveryMethod[]; + notificationDeliveryMethodMap = [NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.SMS, NotificationDeliveryMethod.EMAIL]; + notificationTemplateTypeTranslateMap = NotificationTemplateTypeTranslateMap; private propagateChange = null; @@ -64,8 +69,7 @@ export class NotificationSettingFormComponent implements ControlValueAccessor, O ngOnInit() { this.notificationSettingsFormGroup = this.fb.group( { - ruleId: [], - ruleName: [''], + name: [''], enabled: [true], enabledDeliveryMethods: [] }); diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts index 183ebb9a99..afcc833754 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts @@ -40,7 +40,7 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn notificationSettings: UntypedFormGroup; - notificationDeliveryMethods = Object.keys(NotificationDeliveryMethod) as NotificationDeliveryMethod[]; + notificationDeliveryMethods = [NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.SMS, NotificationDeliveryMethod.EMAIL]; notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap; allowNotificationDeliveryMethods: Array; @@ -72,14 +72,23 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn private patchNotificationSettings(settings: NotificationUserSettings) { const notificationSettingsControls: Array = []; + let preparedSettings; if (settings.prefs) { - settings.prefs.forEach((setting) => { + preparedSettings = this.prepareNotificationSettings(settings.prefs); + preparedSettings.forEach((setting) => { notificationSettingsControls.push(this.fb.control(setting, [Validators.required])); }); } this.notificationSettings.setControl('prefs', this.fb.array(notificationSettingsControls), {emitEvent: false}); } + private prepareNotificationSettings(prefs: any) { + return Object.entries(prefs).map((value: any) => { + value[1].name = value[0]; + return value[1]; + }); + } + resetSettings() { this.dialogService.confirm( this.translate.instant('notification.settings.reset-all-title'), @@ -90,11 +99,11 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn ).subscribe( result => { if (result) { - const settings = this.route.snapshot.data.userSettings; + const settings = this.prepareNotificationSettings(this.route.snapshot.data.userSettings.prefs); const notificationSettingsControls: Array = []; this.notificationSettings.reset({}); - if (settings.prefs) { - settings.prefs.forEach((setting) => { + if (settings) { + settings.forEach((setting) => { setting.enabled = true; setting.enabledDeliveryMethods = this.notificationDeliveryMethods; notificationSettingsControls.push(this.fb.control(setting, [Validators.required])); @@ -153,7 +162,13 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn } save(): void { - this.notificationService.saveNotificationUserSettings(this.notificationSettings.getRawValue()).subscribe( + const settings = {prefs: {}}; + this.notificationSettings.getRawValue().prefs.forEach(value => { + const key = value.name; + delete value.name; + settings.prefs[key] = value; + }); + this.notificationService.saveNotificationUserSettings(settings).subscribe( (userSettings) => { this.notificationSettings.get('prefs').reset({}); this.patchNotificationSettings(userSettings); diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 071e3230fa..9ba1bca7c5 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -591,12 +591,10 @@ export const TriggerTypeTranslationMap = new Map([ ]); export interface NotificationUserSettings { - prefs: Array; + prefs: {[key: string]: NotificationUserSetting}; } export interface NotificationUserSetting { - ruleId: string; - ruleName: string; enabled: boolean; enabledDeliveryMethods: Array; } From e7fd826a85f4c1931933d209e8aa28de18065375 Mon Sep 17 00:00:00 2001 From: kalytka Date: Wed, 5 Jul 2023 13:59:07 +0300 Subject: [PATCH 198/421] Update courceBoolean Decorator --- ui-ngx/src/app/shared/decorators/coercion.ts | 38 ++++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/ui-ngx/src/app/shared/decorators/coercion.ts b/ui-ngx/src/app/shared/decorators/coercion.ts index c60cda730d..a43cc920cf 100644 --- a/ui-ngx/src/app/shared/decorators/coercion.ts +++ b/ui-ngx/src/app/shared/decorators/coercion.ts @@ -22,21 +22,29 @@ import { coerceStringArray as coerceStringArrayAngular } from '@angular/cdk/coercion'; -export const coerceBoolean = () => (target: any, key: string): void => { - const getter = function() { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceBooleanProperty(next); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceBoolean = () => (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceBooleanProperty(next)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceBooleanProperty(next); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; export const coerceNumber = () => (target: any, key: string): void => { From 3baa12ce7739bfec4e66bb0c3392f64fccd0e720 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 5 Jul 2023 15:06:42 +0300 Subject: [PATCH 199/421] refactored config properties --- .../src/main/resources/thingsboard.yml | 35 ++-- .../DeviceConnectivityConfiguration.java | 24 ++- .../dao/device/DeviceConnectivityInfo.java | 26 +++ .../server/dao/device/DeviceServiceImpl.java | 168 +++++++++--------- 4 files changed, 152 insertions(+), 101 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 1c044daa74..f8ea15b2b8 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -775,10 +775,6 @@ transport: worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}" max_payload_size: "${NETTY_MAX_PAYLOAD_SIZE:65536}" so_keep_alive: "${NETTY_SO_KEEPALIVE:false}" - # Mqtt device connectivity host to publish telemetry - device_connectivity_host: "${MQTT_DEVICE_CONNECTIVITY_HOST:localhost}" - # Mqtt device connectivity port to publish telemetry - device_connectivity_port: "${MQTT_DEVICE_CONNECTIVITY_PORT:1883}" # MQTT SSL configuration ssl: # Enable/disable SSL support @@ -789,10 +785,6 @@ transport: bind_port: "${MQTT_SSL_BIND_PORT:8883}" # SSL protocol: See https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}" - # Mqtt ssl device connectivity host to publish telemetry - device_connectivity_host: "${MQTT_DEVICE_CONNECTIVITY_HOST:localhost}" - # Mqtt ssl device connectivity port to publish telemetry - device_connectivity_port: "${MQTT_DEVICE_CONNECTIVITY_PORT:8883}" # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) @@ -829,10 +821,6 @@ transport: piggyback_timeout: "${COAP_PIGGYBACK_TIMEOUT:500}" psm_activity_timer: "${COAP_PSM_ACTIVITY_TIMER:10000}" paging_transmission_window: "${COAP_PAGING_TRANSMISSION_WINDOW:10000}" - # Coap device connectivity host to publish telemetry - device_connectivity_host: "${COAP_DEVICE_CONNECTIVITY_HOST:localhost}" - # Coap device connectivity port to publish telemetry - device_connectivity_port: "${COAP_DEVICE_CONNECTIVITY_PORT:5683}" dtls: # Enable/disable DTLS 1.2 support enabled: "${COAP_DTLS_ENABLED:false}" @@ -842,10 +830,6 @@ transport: bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" # CoAP DTLS bind port bind_port: "${COAP_DTLS_BIND_PORT:5684}" - # Coap DTLS device connectivity host to publish telemetry - device_connectivity_host: "${COAP_DEVICE_CONNECTIVITY_HOST:localhost}" - # Coap DTLS device connectivity port to publish telemetry - device_connectivity_port: "${COAP_DEVICE_CONNECTIVITY_PORT:5684}" # Server DTLS credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) @@ -994,6 +978,25 @@ transport: enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" +# Device connectivity properties to publish telemetry +device: + connectivity: + http: + host: "${DEVICE_CONNECTIVITY_HTTP_HOST:localhost}" + port: "${DEVICE_CONNECTIVITY_HTTP_PORT:8080}" + mqtt: + host: "${DEVICE_CONNECTIVITY_MQTT_HOST:localhost}" + port: "${DEVICE_CONNECTIVITY_MQTT_PORT:1883}" + mqtts: + host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:localhost}" + port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" + coap: + host: "${DEVICE_CONNECTIVITY_COAP_HOST:localhost}" + port: "${DEVICE_CONNECTIVITY_COAP_PORT:5683}" + coaps: + host: "${DEVICE_CONNECTIVITY_COAPS_HOST:localhost}" + port: "${DEVICE_CONNECTIVITY_COAPS_PORT:5684}" + # Edges parameters edges: enabled: "${EDGES_ENABLED:true}" diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java index f156729cbc..454c795f12 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java @@ -1,9 +1,29 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.thingsboard.server.dao.device; import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import java.util.Map; + +@Configuration +@ConfigurationProperties(prefix = "device") @Data public class DeviceConnectivityConfiguration { - private String deviceConnectivityHost; - private Integer deviceConnectivityPort; + private Map connectivity; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java new file mode 100644 index 0000000000..7b477bfc42 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.device; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + + +@Data +public class DeviceConnectivityInfo { + private String host; + private Integer port; +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index cca89742e1..fe5ac33e73 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -20,9 +20,6 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.event.TransactionalEventListener; @@ -108,7 +105,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService commands.put("http", v)); + Optional.ofNullable(getMqttPublishCommand(creds)).ifPresent(v -> commands.put("mqtt", v)); + Optional.ofNullable(getMqttsPublishCommand(creds)).ifPresent(v -> commands.put("mqtts", v)); + Optional.ofNullable(getCoapPublishCommand(creds)).ifPresent(v -> commands.put("coap", v)); + Optional.ofNullable(getCoapsPublishCommand(creds)).ifPresent(v -> commands.put("coaps", v)); break; case MQTT: MqttDeviceProfileTransportConfiguration transportConfiguration = @@ -217,25 +164,22 @@ public class DeviceServiceImpl extends AbstractCachedEntityService commands.put("mqtt", v)); + Optional.ofNullable(getMqttsPublishCommand(topicName, creds, payload)).ifPresent(v -> commands.put("mqtts", v)); break; case COAP: CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); CoapDeviceTypeConfiguration coapConfiguration = coapTransportConfiguration.getCoapDeviceTypeConfiguration(); if (coapConfiguration instanceof DefaultCoapDeviceTypeConfiguration) { - commands.put("coap", getCoapPublishCommand(coapProperties.getDeviceConnectivityHost(), coapProperties.getDeviceConnectivityPort(), creds)); - commands.put("coaps", getCoapPublishCommand(coapsProperties.getDeviceConnectivityHost(), coapsProperties.getDeviceConnectivityPort(), creds)); + Optional.ofNullable(getCoapPublishCommand(creds)).ifPresent(v -> commands.put("coap", v)); + Optional.ofNullable(getCoapsPublishCommand(creds)).ifPresent(v -> commands.put("coaps", v)); } else if (coapConfiguration instanceof EfentoCoapDeviceTypeConfiguration) { - commands.put("coap", "Not supported"); - commands.put("coaps", "Not supported"); + commands.put("coap for efento", "Not supported"); } break; default: - commands.put(transportType.name(), "Not supported"); + commands.put(transportType.name(), NOT_SUPPORTED); } return commands; } @@ -800,18 +744,61 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Wed, 5 Jul 2023 15:27:52 +0300 Subject: [PATCH 200/421] minor refactoring --- application/src/main/resources/thingsboard.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index f8ea15b2b8..2f58590bf6 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -981,9 +981,6 @@ transport: # Device connectivity properties to publish telemetry device: connectivity: - http: - host: "${DEVICE_CONNECTIVITY_HTTP_HOST:localhost}" - port: "${DEVICE_CONNECTIVITY_HTTP_PORT:8080}" mqtt: host: "${DEVICE_CONNECTIVITY_MQTT_HOST:localhost}" port: "${DEVICE_CONNECTIVITY_MQTT_PORT:1883}" From 3be53a3605771acbb4bb6c24a93f3ed0d41753e0 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 5 Jul 2023 14:40:44 +0200 Subject: [PATCH 201/421] fixed saveDeviceWithCredentials api --- .../server/controller/DeviceController.java | 7 +-- .../controller/DeviceControllerTest.java | 47 +++++++++++++++++++ .../SaveDeviceWithCredentialsRequest.java | 4 ++ .../server/dao/device/DeviceServiceImpl.java | 4 -- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 8be76856a4..d73915b617 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -75,6 +75,7 @@ import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; import javax.annotation.Nullable; +import javax.validation.Valid; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -210,9 +211,9 @@ public class DeviceController extends BaseController { @RequestMapping(value = "/device-with-credentials", method = RequestMethod.POST) @ResponseBody public Device saveDeviceWithCredentials(@ApiParam(value = "The JSON object with device and credentials. See method description above for example.") - @RequestBody SaveDeviceWithCredentialsRequest deviceAndCredentials) throws ThingsboardException { - Device device = checkNotNull(deviceAndCredentials.getDevice()); - DeviceCredentials credentials = checkNotNull(deviceAndCredentials.getCredentials()); + @Valid @RequestBody SaveDeviceWithCredentialsRequest deviceAndCredentials) throws ThingsboardException { + Device device = deviceAndCredentials.getDevice(); + DeviceCredentials credentials = deviceAndCredentials.getCredentials(); device.setTenantId(getCurrentUser().getTenantId()); checkEntity(device.getId(), device, Resource.DEVICE); return tbDeviceService.saveDeviceWithCredentials(device, credentials, getCurrentUser()); diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java index 11d11eccdd..1c952bd549 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java @@ -244,6 +244,53 @@ public class DeviceControllerTest extends AbstractControllerTest { testNotificationUpdateGatewayOneTime(savedDevice, oldDevice); } + @Test + public void testSaveDeviceWithCredentials_CredentialsIsNull() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setType("default"); + + SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(device, null); + doPost("/api/device-with-credentials", saveRequest).andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Validation error: credentials must not be null"))); + } + + @Test + public void testSaveDeviceWithCredentials_DeviceIsNull() throws Exception { + String testToken = "TEST_TOKEN"; + + DeviceCredentials deviceCredentials = new DeviceCredentials(); + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); + deviceCredentials.setCredentialsId(testToken); + + SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(null, deviceCredentials); + doPost("/api/device-with-credentials", saveRequest).andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Validation error: device must not be null"))); + } + + @Test + public void testSaveDeviceWithCredentials_WithExistingName() throws Exception { + String testToken = "TEST_TOKEN"; + + Device device = new Device(); + device.setName("My device"); + device.setType("default"); + + DeviceCredentials deviceCredentials = new DeviceCredentials(); + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); + deviceCredentials.setCredentialsId(testToken); + + SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(device, deviceCredentials); + + Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService); + + Device savedDevice = readResponse(doPost("/api/device-with-credentials", saveRequest).andExpect(status().isOk()), Device.class); + Assert.assertNotNull(savedDevice); + + doPost("/api/device-with-credentials", saveRequest).andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Device with such name already exists!"))); + } + @Test public void saveDeviceWithViolationOfValidation() throws Exception { Device device = new Device(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java b/common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java index f8c74a5155..836a5bff93 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/SaveDeviceWithCredentialsRequest.java @@ -20,13 +20,17 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.thingsboard.server.common.data.security.DeviceCredentials; +import javax.validation.constraints.NotNull; + @ApiModel @Data public class SaveDeviceWithCredentialsRequest { @ApiModelProperty(position = 1, value = "The JSON with device entity.", required = true) + @NotNull private final Device device; @ApiModelProperty(position = 2, value = "The JSON with credentials entity.", required = true) + @NotNull private final DeviceCredentials credentials; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 46830f8f76..3f9ee12dda 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -174,10 +174,6 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Wed, 5 Jul 2023 15:58:52 +0300 Subject: [PATCH 202/421] UI: Change position is gateway and style is gatway in device component --- .../wizard/device-wizard-dialog.component.html | 12 ++++++------ .../wizard/device-wizard-dialog.component.ts | 2 +- .../modules/home/pages/device/device.component.html | 12 ++++++------ .../modules/home/pages/device/device.component.scss | 8 +++++++- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index cc1aa3235c..8d55b4bc6a 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -65,20 +65,20 @@ formControlName="deviceProfileId" (deviceProfileChanged)="deviceProfileChanged($event)"> - -
{{ 'device.is-gateway' | translate }} + formControlName="overwriteActivityTime"> {{ 'device.overwrite-activity-time' | translate }}
+ + device.description diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 77ae90fab3..65e7df1e90 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -155,7 +155,7 @@ export class DeviceWizardDialogComponent extends DialogComponent 0) { return this.deviceService.saveDeviceWithCredentials(deepTrim(device), deepTrim(this.credentialsFormGroup.value.credential)).pipe( catchError((e: HttpErrorResponse) => { - if (e.error.message.include('Device credentials')) { + if (e.error.message.includes('Device credentials')) { this.addDeviceWizardStepper.selectedIndex = 1; } else { this.addDeviceWizardStepper.selectedIndex = 0; diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.html b/ui-ngx/src/app/modules/home/pages/device/device.component.html index e619fa9561..244b1c000b 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.html @@ -133,14 +133,14 @@ required>
-
- +
+ {{ 'device.is-gateway' | translate }} - - + + {{ 'device.overwrite-activity-time' | translate }} - +
device.description diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.scss b/ui-ngx/src/app/modules/home/pages/device/device.component.scss index 66df772d2d..526b1daa58 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.scss +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.scss @@ -14,5 +14,11 @@ * limitations under the License. */ :host { - + .toggle-group { + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 16px; + margin-bottom: 16px; + } } From 76e201bd3b66a4438a5095097b3cfe44e9f5ff02 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 5 Jul 2023 16:19:12 +0300 Subject: [PATCH 203/421] UI: Alarms table widget advanced appearance config. --- .../system/widget_bundles/alarm_widgets.json | 2 +- .../alarms-table-basic-config.component.ts | 4 +- .../alarms-table-key-settings.component.html | 96 ++++++----- ...larms-table-widget-settings.component.html | 150 ++++++++++-------- .../assets/locale/locale.constant-en_US.json | 1 + 5 files changed, 138 insertions(+), 115 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json index 7f1def31ac..04f4042fae 100644 --- a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json @@ -27,7 +27,7 @@ "dataKeySettingsDirective": "tb-alarms-table-key-settings", "hasBasicMode": true, "basicModeDirective": "tb-alarms-table-basic-config", - "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayActivity\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true,\"entitiesTitle\":null},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"warning\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false,\"configMode\":\"basic\",\"alarmFilterConfig\":null}" + "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayActivity\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true,\"entitiesTitle\":null,\"alarmsTitle\":\"Alarms\"},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"warning\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false,\"configMode\":\"basic\",\"alarmFilterConfig\":null}" } } ] diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts index e8dbca5f18..33abc0670c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts @@ -60,7 +60,7 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent datasources: [[configData.config.alarmSource], []], columns: [this.getColumns(configData.config.alarmSource), []], showTitle: [configData.config.showTitle, []], - title: [configData.config.settings?.entitiesTitle, []], + title: [configData.config.settings?.alarmsTitle, []], showTitleIcon: [configData.config.showTitleIcon, []], titleIcon: [configData.config.titleIcon, []], iconColor: [configData.config.iconColor, []], @@ -81,7 +81,7 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent this.widgetConfig.config.actions = config.actions; this.widgetConfig.config.showTitle = config.showTitle; this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; - this.widgetConfig.config.settings.entitiesTitle = config.title; + this.widgetConfig.config.settings.alarmsTitle = config.title; this.widgetConfig.config.showTitleIcon = config.showTitleIcon; this.widgetConfig.config.titleIcon = config.titleIcon; this.widgetConfig.config.iconColor = config.iconColor; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.html index a2ccedb34c..a20ba0f100 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.html @@ -15,21 +15,56 @@ limitations under the License. --> -
- - widgets.table.custom-title - - - - widgets.table.column-width - - -
- widgets.table.cell-style + +
+
widgets.table.column-settings
+
+
{{ 'widgets.table.custom-title' | translate }}
+ + + +
+
+
{{ 'widgets.table.column-width' | translate }}
+ + + +
+
+
{{ 'widgets.table.default-column-visibility' | translate }}
+ + + + {{ 'widgets.table.column-visibility-visible' | translate }} + + + {{ 'widgets.table.column-visibility-hidden' | translate }} + + + {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} + + + +
+
+
{{ 'widgets.table.column-selection-to-display' | translate }}
+ + + + {{ 'widgets.table.column-selection-to-display-enabled' | translate }} + + + {{ 'widgets.table.column-selection-to-display-disabled' | translate }} + + + +
+
+
- + - {{ 'widgets.table.use-cell-style-function' | translate }} @@ -48,13 +83,12 @@ -
-
- widgets.table.cell-content +
+
- + - {{ 'widgets.table.use-cell-content-function' | translate }} @@ -73,27 +107,5 @@ - - - widgets.table.default-column-visibility - - - {{ 'widgets.table.column-visibility-visible' | translate }} - - - {{ 'widgets.table.column-visibility-hidden' | translate }} - - - - - widgets.table.column-selection-to-display - - - {{ 'widgets.table.column-selection-to-display-enabled' | translate }} - - - {{ 'widgets.table.column-selection-to-display-disabled' | translate }} - - - -
+
+ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html index 534f12493d..1c85bfb739 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html @@ -15,38 +15,62 @@ limitations under the License. --> -
-
- widgets.table.common-table-settings - - widgets.table.alarms-table-title - - -
-
- - {{ 'widgets.table.enable-alarms-selection' | translate }} - - - {{ 'widgets.table.enable-alarms-search' | translate }} - - - {{ 'widgets.table.enable-select-column-display' | translate }} - - - {{ 'widgets.table.enable-alarm-filter' | translate }} - -
-
- - {{ 'widgets.table.enable-sticky-header' | translate }} - - - {{ 'widgets.table.enable-sticky-action' | translate }} - -
-
- + +
+
widgets.table.table-header
+
+
{{ 'widgets.table.alarms-table-title' | translate }}
+ + + +
+
+ + {{ 'widgets.table.enable-sticky-header' | translate }} + +
+
+
widgets.table.header-buttons
+ + {{ 'widgets.table.enable-alarms-search' | translate }} + + + {{ 'widgets.table.enable-select-column-display' | translate }} + + + {{ 'widgets.table.enable-alarm-filter' | translate }} + +
+
+
+
widgets.table.columns
+ + {{ 'widgets.table.enable-alarms-selection' | translate }} + +
+ + {{ 'widgets.table.enable-sticky-action' | translate }} + +
+
+
widgets.table.table-buttons
+ + {{ 'widgets.table.display-alarm-activity' | translate }} + + + {{ 'widgets.table.display-alarm-details' | translate }} + + + {{ 'widgets.table.allow-alarms-assign' | translate }} + + + {{ 'widgets.table.allow-alarms-ack' | translate }} + + + {{ 'widgets.table.allow-alarms-clear' | translate }} + +
+ widgets.table.hidden-cell-button-display-mode @@ -57,48 +81,34 @@ -
- - {{ 'widgets.table.display-alarm-activity' | translate }} - - - {{ 'widgets.table.display-alarm-details' | translate }} - - - {{ 'widgets.table.allow-alarms-ack' | translate }} - - - {{ 'widgets.table.allow-alarms-clear' | translate }} - - - {{ 'widgets.table.allow-alarms-assign' | translate }} - -
- - {{ 'widgets.table.display-pagination' | translate }} - - - widgets.table.default-page-size - - -
- - widgets.table.default-sort-order - + + widgets.table.default-sort-order + + +
+
+
widgets.table.pagination
+ + {{ 'widgets.table.display-pagination' | translate }} + +
+
widgets.table.default-page-size
+ + -
- -
- widgets.table.row-style +
+
+
+
widgets.table.rows
- - - + + {{ 'widgets.table.use-row-style-function' | translate }} - + widget-config.advanced-settings @@ -112,5 +122,5 @@ - - +
+
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 c032198efa..501a15a4cb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5270,6 +5270,7 @@ "columns-to-display": "Columns to display", "table-header": "Table header", "header-buttons": "Header buttons", + "table-buttons": "Table buttons", "pagination": "Pagination", "rows": "Rows", "timeseries-column-error": "At least one timeseries column should be specified", From 7f555fa7477919b4a6f7fc43e7aab10c2a1fd0a4 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 5 Jul 2023 16:34:36 +0300 Subject: [PATCH 204/421] UI: Fixed device transport configuration enabled/disabled state --- .../data/device-transport-configuration.component.ts | 7 ++++--- .../data/snmp-device-transport-configuration.component.ts | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts index 01e5584a57..58465dd207 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; import { ControlValueAccessor, UntypedFormBuilder, @@ -30,6 +30,7 @@ import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { DeviceTransportConfiguration, DeviceTransportType } from '@shared/models/device.models'; import { deepClone } from '@core/utils'; +import { Subscription } from 'rxjs'; @Component({ selector: 'tb-device-transport-configuration', @@ -104,9 +105,9 @@ export class DeviceTransportConfigurationComponent implements ControlValueAccess if (configuration) { delete configuration.type; } - setTimeout(() => { + // setTimeout(() => { this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); - }, 0); + // }, 0); } validate(): ValidationErrors | null { diff --git a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts index 29ac39ee6a..26b70396d9 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/snmp-device-transport-configuration.component.ts @@ -127,6 +127,9 @@ export class SnmpDeviceTransportConfigurationComponent implements ControlValueAc this.snmpDeviceTransportConfigurationFormGroup.disable({emitEvent: false}); } else { this.snmpDeviceTransportConfigurationFormGroup.enable({emitEvent: false}); + this.updateDisabledFormValue( + this.snmpDeviceTransportConfigurationFormGroup.get('protocolVersion').value || SnmpDeviceProtocolVersion.V2C + ); } } From 4eca0bd9af42ef934d3ccbd31eecd7e28df72150 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 5 Jul 2023 16:36:36 +0300 Subject: [PATCH 205/421] UI: refactoring --- .../data/device-transport-configuration.component.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts index 58465dd207..5aa9b0b317 100644 --- a/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/data/device-transport-configuration.component.ts @@ -14,13 +14,13 @@ /// limitations under the License. /// -import { Component, forwardRef, Input, OnDestroy, OnInit } from '@angular/core'; +import { Component, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, - UntypedFormBuilder, - UntypedFormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, + UntypedFormBuilder, + UntypedFormGroup, ValidationErrors, Validator, Validators @@ -30,7 +30,6 @@ import { AppState } from '@app/core/core.state'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { DeviceTransportConfiguration, DeviceTransportType } from '@shared/models/device.models'; import { deepClone } from '@core/utils'; -import { Subscription } from 'rxjs'; @Component({ selector: 'tb-device-transport-configuration', @@ -105,9 +104,7 @@ export class DeviceTransportConfigurationComponent implements ControlValueAccess if (configuration) { delete configuration.type; } - // setTimeout(() => { - this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); - // }, 0); + this.deviceTransportConfigurationFormGroup.patchValue({configuration}, {emitEvent: false}); } validate(): ValidationErrors | null { From afb41663227a3939110ef9490cb6feeba1ea8de2 Mon Sep 17 00:00:00 2001 From: kalytka Date: Wed, 5 Jul 2023 17:12:07 +0300 Subject: [PATCH 206/421] Update decorators --- ui-ngx/src/app/shared/decorators/coercion.ts | 153 +++++++++++-------- 1 file changed, 93 insertions(+), 60 deletions(-) diff --git a/ui-ngx/src/app/shared/decorators/coercion.ts b/ui-ngx/src/app/shared/decorators/coercion.ts index a43cc920cf..d1d00828f1 100644 --- a/ui-ngx/src/app/shared/decorators/coercion.ts +++ b/ui-ngx/src/app/shared/decorators/coercion.ts @@ -47,70 +47,103 @@ export const coerceBoolean = () => (target: any, key: string, propertyDescriptor } }; -export const coerceNumber = () => (target: any, key: string): void => { - const getter = function(): number { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceNumberProperty(next); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceNumber = () => (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceNumberProperty(next)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceNumberProperty(next); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; -export const coerceCssPixelValue = () => (target: any, key: string): void => { - const getter = function(): string { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceCssPixelValueAngular(next); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceCssPixelValue = () => (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceCssPixelValueAngular(next)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceCssPixelValueAngular(next); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; -export const coerceArray = () => (target: any, key: string): void => { - const getter = function(): any[] { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceArrayAngular(next); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceArray = () => (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceArrayAngular(next)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceArrayAngular(next); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; -export const coerceStringArray = (separator?: string | RegExp) => (target: any, key: string): void => { - const getter = function(): string[] { - return this['__' + key]; - }; - - const setter = function(next: any) { - this['__' + key] = coerceStringArrayAngular(next, separator); - }; - - Object.defineProperty(target, key, { - get: getter, - set: setter, - enumerable: true, - configurable: true, - }); +export const coerceStringArray = (separator?: string | RegExp) => + (target: any, key: string, propertyDescriptor?: PropertyDescriptor): void => { + if (!!propertyDescriptor && !!propertyDescriptor.set) { + const original = propertyDescriptor.set; + + propertyDescriptor.set = function(next) { + original.apply(this, [coerceStringArrayAngular(next, separator)]); + }; + } else { + const getter = function() { + return this['__' + key]; + }; + + const setter = function(next: any) { + this['__' + key] = coerceStringArrayAngular(next, separator); + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + } }; From 4374b83b7f092c86f69ed842aed20f9bc99023e1 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 5 Jul 2023 18:19:22 +0300 Subject: [PATCH 207/421] UI: Add reset option to alarm filter panel. --- ui-ngx/src/app/core/utils.ts | 37 ++++++++++------ .../alarm/alarm-filter-config.component.html | 7 +++ .../alarm/alarm-filter-config.component.ts | 44 +++++++++++++++++-- .../alarms-table-basic-config.component.html | 11 ++++- .../widget/config/datasource.component.html | 1 + .../widget/config/datasource.component.ts | 2 + .../lib/alarms-table-widget.component.ts | 7 +-- .../widget/widget-config.component.html | 12 ++++- .../app/shared/models/query/query.models.ts | 40 ++++++++++++++++- .../assets/locale/locale.constant-en_US.json | 3 +- 10 files changed, 138 insertions(+), 26 deletions(-) diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 4018fd491f..c310693b03 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -20,7 +20,7 @@ import { finalize, share } from 'rxjs/operators'; import { Datasource, DatasourceData, FormattedData, ReplaceInfo } from '@app/shared/models/widget.models'; import { EntityId } from '@shared/models/id/entity-id'; import { NULL_UUID } from '@shared/models/id/has-uuid'; -import { EntityType, baseDetailsPageByEntityType } from '@shared/models/entity-type.models'; +import { baseDetailsPageByEntityType, EntityType } from '@shared/models/entity-type.models'; import { HttpErrorResponse } from '@angular/common/http'; import { TranslateService } from '@ngx-translate/core'; import { serverErrorCodesTranslations } from '@shared/models/constants'; @@ -126,15 +126,6 @@ export function isString(value: any): boolean { return typeof value === 'string'; } -export function isEmpty(obj: any): boolean { - for (const key of Object.keys(obj)) { - if (Object.prototype.hasOwnProperty.call(obj, key)) { - return false; - } - } - return true; -} - export function isLiteralObject(value: any) { return (!!value) && (value.constructor === Object); } @@ -320,9 +311,29 @@ export function extractType(target: any, keysOfProps: (keyof T return _.pick(target, keysOfProps); } -export function isEqual(a: any, b: any): boolean { - return _.isEqual(a, b); -} +export const isEqual = (a: any, b: any): boolean => _.isEqual(a, b); + +export const isEmpty = (a: any): boolean => _.isEmpty(a); + +export const isEqualIgnoreUndefined = (a: any, b: any): boolean => { + if (a === b) { + return true; + } + if (isDefinedAndNotNull(a) && isDefinedAndNotNull(b)) { + return isEqual(a, b); + } else { + return (isUndefinedOrNull(a) || !a) && (isUndefinedOrNull(b) || !b); + } +}; + +export const isArraysEqualIgnoreUndefined = (a: any[], b: any[]): boolean => { + const res = isEqualIgnoreUndefined(a, b); + if (!res) { + return (isUndefinedOrNull(a) || !a?.length) && (isUndefinedOrNull(b) || !b?.length); + } else { + return res; + } +}; export function mergeDeep(target: T, ...sources: T[]): T { return _.merge(target, ...sources); diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html index cbf1da82f6..7502ea7791 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html @@ -33,6 +33,13 @@
+ + +
+
= []; datasourceTypesTranslations = datasourceTypeTranslationMap; + alarmSearchStatus = AlarmSearchStatus; + datasourceFormGroup: UntypedFormGroup; private propagateChange = (_val: any) => {}; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index 0927114e1c..a0062645ac 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -384,7 +384,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, this.pageSizeOptions = [this.defaultPageSize, this.defaultPageSize * 2, this.defaultPageSize * 3]; this.pageLink.pageSize = this.displayPagination ? this.defaultPageSize : 1024; - const alarmFilter = this.entityService.resolveAlarmFilter(this.widgetConfig.alarmFilterConfig); + const alarmFilter = this.entityService.resolveAlarmFilter(this.widgetConfig.alarmFilterConfig, false); this.pageLink = {...this.pageLink, ...alarmFilter}; this.noDataDisplayMessageText = @@ -624,7 +624,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, searchPropagatedAlarms: this.pageLink.searchPropagatedAlarms, assignedToCurrentUser, assigneeId - } + }, + initialAlarmFilterConfig: deepClone(this.widgetConfig.alarmFilterConfig) } as AlarmFilterConfigData }, { @@ -638,7 +639,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, componentRef.onDestroy(() => { if (componentRef.instance.panelResult) { const result = componentRef.instance.panelResult; - const alarmFilter = this.entityService.resolveAlarmFilter(result); + const alarmFilter = this.entityService.resolveAlarmFilter(result, false); this.pageLink = {...this.pageLink, ...alarmFilter}; this.resetPageIndex(); this.updateData(); 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 5cddfd4639..e71e6ae745 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 @@ -207,8 +207,16 @@ formControlName="timewindowConfig"> -
- +
+
+
alarm.filter
+ +
+
Date: Thu, 6 Jul 2023 11:02:15 +0300 Subject: [PATCH 208/421] UI: Introduce borderRadius widget card setting. Improve widget style json field. --- .../widget/widget-config.component.html | 7 ++++++- .../components/widget/widget-config.component.ts | 2 ++ .../home/models/dashboard-component.models.ts | 5 ++++- .../components/json-object-edit.component.ts | 15 +++++++++++++-- ui-ngx/src/app/shared/models/widget.models.ts | 1 + .../src/assets/locale/locale.constant-en_US.json | 1 + 6 files changed, 27 insertions(+), 4 deletions(-) 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 e71e6ae745..53d5342b49 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 @@ -114,6 +114,12 @@
+
+
{{ 'widget-config.border-radius' | translate }}
+ + + +
{{ 'widget-config.drop-shadow' | translate }} @@ -126,7 +132,6 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index 999e7e55ff..1f418224dd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -224,6 +224,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe color: [null, []], padding: [null, []], margin: [null, []], + borderRadius: [null, []], widgetStyle: [null, []], widgetCss: [null, []], titleStyle: [null, []], @@ -484,6 +485,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe color: config.color, padding: config.padding, margin: config.margin, + borderRadius: config.borderRadius, widgetStyle: isDefined(config.widgetStyle) ? config.widgetStyle : {}, widgetCss: isDefined(config.widgetCss) ? config.widgetCss : '', titleStyle: isDefined(config.titleStyle) ? config.titleStyle : { diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 2c79ef7b68..e9787260bb 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -328,6 +328,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { backgroundColor: string; padding: string; margin: string; + borderRadius: string; title: string; customTranslatedTitle: string; @@ -427,6 +428,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { this.backgroundColor = this.widget.config.backgroundColor || '#fff'; this.padding = this.widget.config.padding || '8px'; this.margin = this.widget.config.margin || '0px'; + this.borderRadius = this.widget.config.borderRadius; this.title = isDefined(this.widgetContext.widgetTitle) && this.widgetContext.widgetTitle.length ? this.widgetContext.widgetTitle : this.widget.config.title; @@ -478,7 +480,8 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { color: this.color, backgroundColor: this.backgroundColor, padding: this.padding, - margin: this.margin}; + margin: this.margin, + borderRadius: this.borderRadius}; if (this.widget.config.widgetStyle) { this.style = {...this.style, ...this.widget.config.widgetStyle}; } diff --git a/ui-ngx/src/app/shared/components/json-object-edit.component.ts b/ui-ngx/src/app/shared/components/json-object-edit.component.ts index ad2e3abd2f..f7e3116b0f 100644 --- a/ui-ngx/src/app/shared/components/json-object-edit.component.ts +++ b/ui-ngx/src/app/shared/components/json-object-edit.component.ts @@ -14,7 +14,16 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + ElementRef, + forwardRef, + Input, + OnDestroy, + OnInit, + ViewChild +} from '@angular/core'; import { ControlValueAccessor, UntypedFormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; import { Ace } from 'ace-builds'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; @@ -104,7 +113,8 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va constructor(public elementRef: ElementRef, protected store: Store, - private raf: RafService) { + private raf: RafService, + private cd: ChangeDetectorRef) { } ngOnInit(): void { @@ -283,6 +293,7 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va } this.modelValue = data; this.propagateChange(data); + this.cd.markForCheck(); } } diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 55a1070c41..de4c5332f7 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -637,6 +637,7 @@ export interface WidgetConfig { backgroundColor?: string; padding?: string; margin?: string; + borderRadius?: string; widgetStyle?: {[klass: string]: any}; widgetCss?: string; titleStyle?: {[klass: string]: any}; 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 ac78048f16..85497e004b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4190,6 +4190,7 @@ "enable-fullscreen": "Enable fullscreen", "background-color": "Background color", "text-color": "Text color", + "border-radius": "Border radius", "padding": "Padding", "margin": "Margin", "widget-style": "Widget style", From 47929ef78442808c32b88fa627426b5f98367a7e Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 6 Jul 2023 12:20:23 +0300 Subject: [PATCH 209/421] replaced newMsg and trasformMsg with new methods that uses TbMsgType && mark old methods as deprecated && refactoring --- .../actors/ruleChain/DefaultTbContext.java | 58 +++++-- .../server/controller/RpcV2Controller.java | 4 +- .../service/action/EntityActionService.java | 2 +- .../device/DeviceProvisionServiceImpl.java | 29 ++-- .../service/edge/rpc/EdgeGrpcService.java | 15 +- .../processor/device/DeviceEdgeProcessor.java | 9 +- .../telemetry/BaseTelemetryProcessor.java | 11 +- .../DefaultTbNotificationEntityService.java | 5 +- .../rpc/DefaultTbCoreDeviceRpcService.java | 5 +- .../server/service/rpc/TbRpcService.java | 3 +- .../state/DefaultDeviceStateService.java | 21 +-- .../transport/DefaultTransportApiService.java | 4 +- .../AbstractRuleEngineControllerTest.java | 6 +- ...AbstractRuleEngineFlowIntegrationTest.java | 13 +- ...actRuleEngineLifecycleIntegrationTest.java | 7 +- .../SequentialTimeseriesPersistenceTest.java | 4 +- .../server/common/data/msg/TbMsgType.java | 32 +++- .../server/common/data/msg/TbMsgTypeTest.java | 18 +- .../thingsboard/server/common/msg/TbMsg.java | 164 +++++++++++++++++- .../service/DefaultTransportService.java | 2 +- .../rule/engine/api/TbContext.java | 32 +++- .../rule/engine/api/util/TbNodeUtilsTest.java | 11 +- .../engine/action/TbAbstractAlarmNode.java | 21 +-- .../rule/engine/action/TbClearAlarmNode.java | 2 +- .../rule/engine/action/TbCreateAlarmNode.java | 4 +- .../engine/action/TbCreateRelationNode.java | 2 +- .../rule/engine/action/TbMsgCountNode.java | 15 +- .../rule/engine/aws/sns/TbSnsNode.java | 4 +- .../rule/engine/aws/sqs/TbSqsNode.java | 17 +- .../rule/engine/debug/TbMsgGeneratorNode.java | 13 +- .../deduplication/TbMsgDeduplicationNode.java | 8 +- .../rule/engine/delay/TbMsgDelayNode.java | 12 +- .../rule/engine/gcp/pubsub/TbPubSubNode.java | 13 +- .../rule/engine/kafka/TbKafkaNode.java | 12 +- .../rule/engine/mail/TbMsgToEmailNode.java | 11 +- .../rule/engine/mail/TbSendEmailNode.java | 8 +- .../engine/metadata/CalculateDeltaNode.java | 2 +- .../engine/metadata/TbGetTelemetryNode.java | 18 +- .../rule/engine/mqtt/TbMqttNode.java | 10 +- .../rule/engine/profile/AlarmState.java | 3 +- .../rule/engine/profile/DeviceState.java | 6 +- .../engine/profile/TbDeviceProfileNode.java | 61 ++++--- .../rule/engine/rabbitmq/TbRabbitMqNode.java | 7 +- .../rule/engine/rest/TbHttpClient.java | 16 +- .../rule/engine/rest/TbRestApiCallNode.java | 1 - .../rule/engine/rpc/TbSendRPCRequestNode.java | 5 +- .../transform/TbChangeOriginatorNode.java | 10 +- .../rule/engine/transform/TbCopyKeysNode.java | 2 +- .../engine/transform/TbDeleteKeysNode.java | 4 +- .../rule/engine/transform/TbJsonPathNode.java | 2 +- .../engine/transform/TbRenameKeysNode.java | 4 +- .../engine/transform/TbSplitArrayMsgNode.java | 4 +- .../rule/engine/action/TbAlarmNodeTest.java | 110 ++++++------ .../action/TbCreateRelationNodeTest.java | 36 ++-- .../rule/engine/action/TbLogNodeTest.java | 7 +- .../engine/edge/TbMsgPushToEdgeNodeTest.java | 25 ++- .../filter/TbAssetTypeSwitchNodeTest.java | 4 +- .../filter/TbCheckAlarmStatusNodeTest.java | 4 +- .../engine/filter/TbCheckMessageNodeTest.java | 16 +- .../filter/TbCheckRelationNodeTest.java | 4 +- .../filter/TbDeviceTypeSwitchNodeTest.java | 4 +- .../engine/filter/TbJsFilterNodeTest.java | 10 +- .../engine/filter/TbJsSwitchNodeTest.java | 3 +- .../filter/TbMsgTypeFilterNodeTest.java | 2 +- .../filter/TbMsgTypeSwitchNodeTest.java | 2 +- .../TbOriginatorTypeFilterNodeTest.java | 4 +- .../TbOriginatorTypeSwitchNodeTest.java | 4 +- .../geo/TbGpsGeofencingFilterNodeTest.java | 24 ++- .../engine/mail/TbMsgToEmailNodeTest.java | 9 +- .../rule/engine/math/TbMathNodeTest.java | 31 ++-- .../metadata/CalculateDeltaNodeTest.java | 29 ++-- .../TbFetchDeviceCredentialsNodeTest.java | 8 +- .../metadata/TbGetAttributesNodeTest.java | 5 +- .../TbGetCustomerAttributeNodeTest.java | 14 +- .../TbGetCustomerDetailsNodeTest.java | 6 +- .../TbGetOriginatorFieldsNodeTest.java | 14 +- .../TbGetRelatedAttributeNodeTest.java | 12 +- .../TbGetTenantAttributeNodeTest.java | 12 +- .../metadata/TbGetTenantDetailsNodeTest.java | 6 +- .../rule/engine/profile/DeviceStateTest.java | 24 ++- .../profile/TbDeviceProfileNodeTest.java | 118 ++++++------- .../rule/engine/rest/TbHttpClientTest.java | 13 +- .../engine/rest/TbRestApiCallNodeTest.java | 23 +-- .../engine/rpc/TbSendRPCReplyNodeTest.java | 4 +- .../TbMsgDeleteAttributesNodeTest.java | 17 +- .../transform/TbChangeOriginatorNodeTest.java | 17 +- .../engine/transform/TbCopyKeysNodeTest.java | 4 +- .../transform/TbDeleteKeysNodeTest.java | 4 +- .../engine/transform/TbJsonPathNodeTest.java | 4 +- .../transform/TbMsgDeduplicationNodeTest.java | 15 +- .../transform/TbRenameKeysNodeTest.java | 4 +- .../transform/TbSplitArrayMsgNodeTest.java | 4 +- .../transform/TbTransformMsgNodeTest.java | 7 +- 93 files changed, 794 insertions(+), 621 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index f9d1940714..dc03a97254 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -59,6 +59,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -345,8 +346,33 @@ class DefaultTbContext implements TbContext { return TbMsg.transformMsg(origMsg, type, originator, metaData, data); } + @Override + public TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { + return newMsg(queueName, type, originator, null, metaData, data); + } + + @Override + public TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { + return TbMsg.newMsg(queueName, type, originator, customerId, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); + } + + @Override + public TbMsg transformMsg(TbMsg origMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { + return TbMsg.transformMsg(origMsg, type, originator, metaData, data); + } + + @Override + public TbMsg transformMsg(TbMsg origMsg, TbMsgMetaData metaData, String data) { + return TbMsg.transformMsg(origMsg, metaData, data); + } + + @Override + public TbMsg transformMsgOriginator(TbMsg origMsg, EntityId originator) { + return TbMsg.transformMsgOriginator(origMsg, originator); + } + public TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId) { - return entityActionMsg(customer, customer.getId(), ruleNodeId, ENTITY_CREATED.name()); + return entityActionMsg(customer, customer.getId(), ruleNodeId, ENTITY_CREATED); } public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) { @@ -354,7 +380,7 @@ class DefaultTbContext implements TbContext { if (device.getDeviceProfileId() != null) { deviceProfile = mainCtx.getDeviceProfileCache().find(device.getDeviceProfileId()); } - return entityActionMsg(device, device.getId(), ruleNodeId, ENTITY_CREATED.name(), deviceProfile); + return entityActionMsg(device, device.getId(), ruleNodeId, ENTITY_CREATED, deviceProfile); } public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) { @@ -362,10 +388,10 @@ class DefaultTbContext implements TbContext { if (asset.getAssetProfileId() != null) { assetProfile = mainCtx.getAssetProfileCache().find(asset.getAssetProfileId()); } - return entityActionMsg(asset, asset.getId(), ruleNodeId, ENTITY_CREATED.name(), assetProfile); + return entityActionMsg(asset, asset.getId(), ruleNodeId, ENTITY_CREATED, assetProfile); } - public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) { + public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, TbMsgType actionMsgType) { HasRuleEngineProfile profile = null; if (EntityType.DEVICE.equals(alarm.getOriginator().getEntityType())) { DeviceId deviceId = new DeviceId(alarm.getOriginator().getId()); @@ -374,7 +400,7 @@ class DefaultTbContext implements TbContext { AssetId assetId = new AssetId(alarm.getOriginator().getId()); profile = mainCtx.getAssetProfileCache().get(getTenantId(), assetId); } - return entityActionMsg(alarm, alarm.getOriginator(), ruleNodeId, action, profile); + return entityActionMsg(alarm, alarm.getOriginator(), ruleNodeId, actionMsgType, profile); } public TbMsg attributesUpdatedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List attributes) { @@ -382,7 +408,7 @@ class DefaultTbContext implements TbContext { if (attributes != null) { attributes.forEach(attributeKvEntry -> JacksonUtil.addKvEntry(entityNode, attributeKvEntry)); } - return attributesActionMsg(originator, ruleNodeId, scope, ATTRIBUTES_UPDATED.name(), JacksonUtil.toString(entityNode)); + return attributesActionMsg(originator, ruleNodeId, scope, ATTRIBUTES_UPDATED, JacksonUtil.toString(entityNode)); } public TbMsg attributesDeletedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List keys) { @@ -391,10 +417,10 @@ class DefaultTbContext implements TbContext { if (keys != null) { keys.forEach(attrsArrayNode::add); } - return attributesActionMsg(originator, ruleNodeId, scope, ATTRIBUTES_DELETED.name(), JacksonUtil.toString(entityNode)); + return attributesActionMsg(originator, ruleNodeId, scope, ATTRIBUTES_DELETED, JacksonUtil.toString(entityNode)); } - private TbMsg attributesActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, String action, String msgData) { + private TbMsg attributesActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, TbMsgType actionMsgType, String msgData) { TbMsgMetaData tbMsgMetaData = getActionMetaData(ruleNodeId); tbMsgMetaData.putValue("scope", scope); HasRuleEngineProfile profile = null; @@ -405,7 +431,7 @@ class DefaultTbContext implements TbContext { AssetId assetId = new AssetId(originator.getId()); profile = mainCtx.getAssetProfileCache().get(getTenantId(), assetId); } - return entityActionMsg(originator, tbMsgMetaData, msgData, action, profile); + return entityActionMsg(originator, tbMsgMetaData, msgData, actionMsgType, profile); } @Override @@ -413,26 +439,26 @@ class DefaultTbContext implements TbContext { mainCtx.getClusterService().onEdgeEventUpdate(tenantId, edgeId); } - public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action) { - return entityActionMsg(entity, id, ruleNodeId, action, null); + public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, TbMsgType actionMsgType) { + return entityActionMsg(entity, id, ruleNodeId, actionMsgType, null); } - public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, K profile) { + public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, TbMsgType actionMsgType, K profile) { try { - return entityActionMsg(id, getActionMetaData(ruleNodeId), JacksonUtil.toString(JacksonUtil.valueToTree(entity)), action, profile); + return entityActionMsg(id, getActionMetaData(ruleNodeId), JacksonUtil.toString(JacksonUtil.valueToTree(entity)), actionMsgType, profile); } catch (IllegalArgumentException e) { - throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " " + action + " msg: " + e); + throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " " + actionMsgType.name() + " msg: " + e); } } - private TbMsg entityActionMsg(I id, TbMsgMetaData msgMetaData, String msgData, String action, K profile) { + private TbMsg entityActionMsg(I id, TbMsgMetaData msgMetaData, String msgData, TbMsgType actionMsgType, K profile) { String defaultQueueName = null; RuleChainId defaultRuleChainId = null; if (profile != null) { defaultQueueName = profile.getDefaultQueueName(); defaultRuleChainId = profile.getDefaultRuleChainId(); } - return TbMsg.newMsg(defaultQueueName, action, id, msgMetaData, msgData, defaultRuleChainId, null); + return TbMsg.newMsg(defaultQueueName, actionMsgType, id, msgMetaData, msgData, defaultRuleChainId, null); } @Override diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java index d65f87497d..451a5b7dc0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java +++ b/application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.RpcId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rpc.Rpc; @@ -52,7 +53,6 @@ import org.thingsboard.server.service.security.permission.Operation; import javax.annotation.Nullable; import java.util.UUID; -import static org.thingsboard.server.common.data.msg.TbMsgType.RPC_DELETED; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.MARKDOWN_CODE_BLOCK_END; @@ -239,7 +239,7 @@ public class RpcV2Controller extends AbstractRpcController { rpcService.deleteRpc(getTenantId(), rpcId); rpc.setStatus(RpcStatus.DELETED); - TbMsg msg = TbMsg.newMsg(RPC_DELETED.name(), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); + TbMsg msg = TbMsg.newMsg(TbMsgType.RPC_DELETED, rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); tbClusterService.pushMsgToRuleEngine(getTenantId(), rpc.getDeviceId(), msg, null); } } diff --git a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java index cea4a6922a..6c855a89c9 100644 --- a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java +++ b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java @@ -171,7 +171,7 @@ public class EntityActionService { if (tenantId != null && !tenantId.isSysTenantId()) { processNotificationRules(tenantId, entityId, entity, actionType, user, additionalInfo); } - TbMsg tbMsg = TbMsg.newMsg(msgType.get().name(), entityId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); + TbMsg tbMsg = TbMsg.newMsg(msgType.get(), entityId, customerId, metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); tbClusterService.pushMsgToRuleEngine(tenantId, entityId, tbMsg, null); } catch (Exception e) { log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e); diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java index d5614c2193..763ce01116 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java @@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @@ -35,6 +36,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.msg.TbMsg; @@ -68,11 +70,6 @@ import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED; -import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_FAILURE; -import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_SUCCESS; - @Service @Slf4j @@ -166,7 +163,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { if (targetProfile.getProfileData().getProvisionConfiguration().getProvisionDeviceSecret().equals(provisionRequestSecret)) { if (targetDevice != null) { log.warn("[{}] The device is present and could not be provisioned once more!", targetDevice.getName()); - notify(targetDevice, provisionRequest, PROVISION_FAILURE.name(), false); + notify(targetDevice, provisionRequest, TbMsgType.PROVISION_FAILURE, false); throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); } else { return createDevice(provisionRequest, targetProfile); @@ -192,13 +189,13 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { private ProvisionResponse processProvision(Device device, ProvisionRequest provisionRequest) { try { Optional provisionState = attributesService.find(device.getTenantId(), device.getId(), - SERVER_SCOPE, DEVICE_PROVISION_STATE).get(); + DataConstants.SERVER_SCOPE, DEVICE_PROVISION_STATE).get(); if (provisionState != null && provisionState.isPresent() && !provisionState.get().getValueAsString().equals(PROVISIONED_STATE)) { - notify(device, provisionRequest, PROVISION_FAILURE.name(), false); + notify(device, provisionRequest, TbMsgType.PROVISION_FAILURE, false); throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); } else { saveProvisionStateAttribute(device).get(); - notify(device, provisionRequest, PROVISION_SUCCESS.name(), true); + notify(device, provisionRequest, TbMsgType.PROVISION_SUCCESS, true); } } catch (InterruptedException | ExecutionException e) { throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); @@ -210,7 +207,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { return processCreateDevice(provisionRequest, profile); } - private void notify(Device device, ProvisionRequest provisionRequest, String type, boolean success) { + private void notify(Device device, ProvisionRequest provisionRequest, TbMsgType type, boolean success) { pushProvisionEventToRuleEngine(provisionRequest, device, type); logAction(device.getTenantId(), device.getCustomerId(), device, success, provisionRequest); } @@ -226,14 +223,14 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { clusterService.onDeviceUpdated(savedDevice, null); saveProvisionStateAttribute(savedDevice).get(); pushDeviceCreatedEventToRuleEngine(savedDevice); - notify(savedDevice, provisionRequest, PROVISION_SUCCESS.name(), true); + notify(savedDevice, provisionRequest, TbMsgType.PROVISION_SUCCESS, true); return new ProvisionResponse(getDeviceCredentials(savedDevice), ProvisionResponseStatus.SUCCESS); } catch (Exception e) { log.warn("[{}] Error during device creation from provision request: [{}]", provisionRequest.getDeviceName(), provisionRequest, e); Device device = deviceService.findDeviceByTenantIdAndName(profile.getTenantId(), provisionRequest.getDeviceName()); if (device != null) { - notify(device, provisionRequest, PROVISION_FAILURE.name(), false); + notify(device, provisionRequest, TbMsgType.PROVISION_FAILURE, false); } throw new ProvisionFailedException(ProvisionResponseStatus.FAILURE.name()); } @@ -248,7 +245,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { } private ListenableFuture> saveProvisionStateAttribute(Device device) { - return attributesService.save(device.getTenantId(), device.getId(), SERVER_SCOPE, + return attributesService.save(device.getTenantId(), device.getId(), DataConstants.SERVER_SCOPE, Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry(DEVICE_PROVISION_STATE, PROVISIONED_STATE), System.currentTimeMillis()))); } @@ -257,7 +254,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { return deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), device.getId()); } - private void pushProvisionEventToRuleEngine(ProvisionRequest request, Device device, String type) { + private void pushProvisionEventToRuleEngine(ProvisionRequest request, Device device, TbMsgType type) { try { JsonNode entityNode = JacksonUtil.valueToTree(request); TbMsg msg = TbMsg.newMsg(type, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.toString(entityNode)); @@ -270,10 +267,10 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { private void pushDeviceCreatedEventToRuleEngine(Device device) { try { ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device); - TbMsg msg = TbMsg.newMsg(ENTITY_CREATED.name(), device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); + TbMsg msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, device.getId(), device.getCustomerId(), createTbMsgMetaData(device), JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); sendToRuleEngine(device.getTenantId(), msg, null); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), ENTITY_CREATED.name(), e); + log.warn("[{}] Failed to push device action to rule engine: {}", device.getId(), TbMsgType.ENTITY_CREATED.name(), e); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index 233dcba2cc..73f968e05d 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -71,10 +72,6 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; -import static org.thingsboard.server.common.data.msg.TbMsgType.CONNECT_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.DISCONNECT_EVENT; - @Service @Slf4j @ConditionalOnProperty(prefix = "edges", value = "enabled", havingValue = "true") @@ -278,7 +275,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true); long lastConnectTs = System.currentTimeMillis(); save(edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, lastConnectTs); - pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, CONNECT_EVENT.name()); + pushRuleEngineMessage(edgeGrpcSession.getEdge().getTenantId(), edgeId, lastConnectTs, TbMsgType.CONNECT_EVENT); cancelScheduleEdgeEventsCheck(edgeId); scheduleEdgeEventsCheck(edgeGrpcSession); } @@ -395,7 +392,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false); long lastDisconnectTs = System.currentTimeMillis(); save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, lastDisconnectTs); - pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, DISCONNECT_EVENT.name()); + pushRuleEngineMessage(toRemove.getEdge().getTenantId(), edgeId, lastDisconnectTs, TbMsgType.DISCONNECT_EVENT); cancelScheduleEdgeEventsCheck(edgeId); } else { log.debug("[{}] edge session [{}] is not available anymore, nothing to remove. most probably this session is already outdated!", edgeId, sessionId); @@ -448,10 +445,10 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i } } - private void pushRuleEngineMessage(TenantId tenantId, EdgeId edgeId, long ts, String msgType) { + private void pushRuleEngineMessage(TenantId tenantId, EdgeId edgeId, long ts, TbMsgType msgType) { try { ObjectNode edgeState = JacksonUtil.newObjectNode(); - if (msgType.equals(CONNECT_EVENT.name())) { + if (msgType.equals(TbMsgType.CONNECT_EVENT)) { edgeState.put(DefaultDeviceStateService.ACTIVITY_STATE, true); edgeState.put(DefaultDeviceStateService.LAST_CONNECT_TIME, ts); } else { @@ -461,7 +458,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i String data = JacksonUtil.toString(edgeState); TbMsgMetaData md = new TbMsgMetaData(); if (!persistToTelemetry) { - md.putValue(DataConstants.SCOPE, SERVER_SCOPE); + md.putValue(DataConstants.SCOPE, DataConstants.SERVER_SCOPE); } TbMsg tbMsg = TbMsg.newMsg(msgType, edgeId, md, TbMsgDataType.JSON, data); clusterService.pushMsgToRuleEngine(tenantId, edgeId, tbMsg, null); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java index 49f2e0ead2..67194cb618 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java @@ -62,9 +62,6 @@ import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg; import java.util.UUID; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED; -import static org.thingsboard.server.common.data.msg.TbMsgType.TO_SERVER_RPC_REQUEST; - @Component @Slf4j @TbCoreComponent @@ -127,7 +124,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { try { Device device = deviceService.findDeviceById(tenantId, deviceId); ObjectNode entityNode = JacksonUtil.OBJECT_MAPPER.valueToTree(device); - TbMsg tbMsg = TbMsg.newMsg(ENTITY_CREATED.name(), deviceId, device.getCustomerId(), + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, device.getCustomerId(), getActionTbMsgMetaData(edge, device.getCustomerId()), TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(entityNode)); tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() { @Override @@ -141,7 +138,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { } }); } catch (JsonProcessingException | IllegalArgumentException e) { - log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, ENTITY_CREATED.name(), e); + log.warn("[{}] Failed to push device action to rule engine: {}", deviceId, TbMsgType.ENTITY_CREATED.name(), e); } } @@ -219,7 +216,7 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { ObjectNode data = JacksonUtil.newObjectNode(); data.put("method", deviceRpcCallMsg.getRequestMsg().getMethod()); data.put("params", deviceRpcCallMsg.getRequestMsg().getParams()); - TbMsg tbMsg = TbMsg.newMsg(TO_SERVER_RPC_REQUEST.name(), deviceId, null, metaData, + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.TO_SERVER_RPC_REQUEST, deviceId, null, metaData, TbMsgDataType.JSON, JacksonUtil.OBJECT_MAPPER.writeValueAsString(data)); tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, new TbQueueCallback() { @Override diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java index c55a931194..5942628bf3 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/telemetry/BaseTelemetryProcessor.java @@ -50,6 +50,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.ServiceType; @@ -72,10 +73,6 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; -import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; - @Slf4j public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { @@ -187,7 +184,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); metaData.putValue("ts", tsKv.getTs() + ""); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), POST_TELEMETRY_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); + TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_TELEMETRY_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { @@ -231,7 +228,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { SettableFuture futureToSet = SettableFuture.create(); JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), POST_ATTRIBUTES_REQUEST.name(), entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); + TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { @Override public void onSuccess(TbQueueMsgMetadata metadata) { @@ -260,7 +257,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor { @Override public void onSuccess(@Nullable Void tmp) { var defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); - TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), ATTRIBUTES_UPDATED.name(), entityId, + TbMsg tbMsg = TbMsg.newMsg(defaultQueueAndRuleChain.getKey(), TbMsgType.ATTRIBUTES_UPDATED, entityId, customerId, metaData, gson.toJson(json), defaultQueueAndRuleChain.getValue(), null); tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index 719158403c..68b9cdecbb 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rule.RuleChain; @@ -52,8 +53,6 @@ import org.thingsboard.server.service.gateway_device.GatewayNotificationsService import java.util.List; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED_FROM_TENANT; - @Slf4j @Service @RequiredArgsConstructor @@ -287,7 +286,7 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) { String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice)); if (data != null) { - TbMsg tbMsg = TbMsg.newMsg(ENTITY_ASSIGNED_FROM_TENANT.name(), assignedDevice.getId(), + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data); tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null); } diff --git a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java index 2ec8f09bd0..8ea7208c55 100644 --- a/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/rpc/DefaultTbCoreDeviceRpcService.java @@ -26,6 +26,7 @@ import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.rpc.RpcError; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; @@ -48,8 +49,6 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -import static org.thingsboard.server.common.data.msg.TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE; - /** * Created by ashvayka on 27.03.18. */ @@ -183,7 +182,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { entityNode.put(DataConstants.ADDITIONAL_INFO, msg.getAdditionalInfo()); try { - TbMsg tbMsg = TbMsg.newMsg(RPC_CALL_FROM_SERVER_TO_DEVICE.name(), msg.getDeviceId(), Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null), metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), Optional.ofNullable(currentUser).map(User::getCustomerId).orElse(null), metaData, TbMsgDataType.JSON, JacksonUtil.toString(entityNode)); clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null); } catch (IllegalArgumentException e) { throw new RuntimeException(e); diff --git a/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java b/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java index ad40176cef..8c6f0d768c 100644 --- a/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/rpc/TbRpcService.java @@ -24,6 +24,7 @@ import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.RpcId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rpc.Rpc; @@ -62,7 +63,7 @@ public class TbRpcService { } private void pushRpcMsgToRuleEngine(TenantId tenantId, Rpc rpc) { - TbMsg msg = TbMsg.newMsg("RPC_" + rpc.getStatus().name(), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); + TbMsg msg = TbMsg.newMsg(TbMsgType.valueOf("RPC_" + rpc.getStatus().name()), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); tbClusterService.pushMsgToRuleEngine(tenantId, rpc.getDeviceId(), msg, null); } diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 965b781fe9..05d71c4fca 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -51,6 +51,7 @@ import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageDataIterable; @@ -102,12 +103,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; -import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.CONNECT_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.DISCONNECT_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; - /** * Created by ashvayka on 01.05.18. */ @@ -229,7 +224,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService { attributes.flatMap(KvEntry::getLongValue).ifPresent((inactivityTimeout) -> { if (inactivityTimeout > 0) { @@ -771,11 +766,11 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService filterByCustomEvent() { - return event -> event.getBody().get("msgType").textValue().equals("CUSTOM"); + protected Predicate filterByPostTelemetryEventType() { + return event -> event.getBody().get("msgType").textValue().equals(TbMsgType.POST_TELEMETRY_REQUEST.name()); } } diff --git a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java index c448c4220f..e626adf5f4 100644 --- a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java @@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.event.Event; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.rule.NodeConnectionInfo; @@ -180,14 +181,14 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true); - TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback); QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); // Pushing Message to the system actorSystem.tell(qMsg); Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess(); PageData eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); - List events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList()); + List events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList()); Assert.assertEquals(2, events.size()); EventInfo inEvent = events.stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.IN)).findFirst().get(); @@ -204,7 +205,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule RuleNode lastRuleNode = metaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get(); eventsPage = getDebugEvents(savedTenant.getId(), lastRuleNode.getId(), 1000); - events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList()); + events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList()); Assert.assertEquals(2, events.size()); @@ -305,7 +306,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true); - TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback); QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); // Pushing Message to the system actorSystem.tell(qMsg); @@ -313,7 +314,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess(); PageData eventsPage = getDebugEvents(savedTenant.getId(), rootRuleChain.getFirstRuleNodeId(), 1000); - List events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList()); + List events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList()); Assert.assertEquals(2, events.size()); @@ -331,7 +332,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule RuleNode lastRuleNode = secondaryMetaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get(); eventsPage = getDebugEvents(savedTenant.getId(), lastRuleNode.getId(), 1000); - events = eventsPage.getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList()); + events = eventsPage.getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList()); Assert.assertEquals(2, events.size()); diff --git a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java index 9753f06aff..6216f993dc 100644 --- a/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.EventInfo; import org.thingsboard.server.common.data.event.EventType; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleNode; @@ -139,7 +140,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac log.warn("attr updated"); TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); Mockito.when(tbMsgCallback.isMsgValid()).thenReturn(true); - TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, tbMsgCallback); QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(tenantId, tbMsg, null, null); // Pushing Message to the system log.warn("before tell tbMsgCallback"); @@ -147,12 +148,12 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac log.warn("awaiting tbMsgCallback"); Mockito.verify(tbMsgCallback, Mockito.timeout(TimeUnit.SECONDS.toMillis(TIMEOUT))).onSuccess(); log.warn("awaiting events"); - List events = Awaitility.await("get debug by custom event") + List events = Awaitility.await("get debug by post telemetry event") .pollInterval(10, MILLISECONDS) .atMost(TIMEOUT, TimeUnit.SECONDS) .until(() -> { List debugEvents = getDebugEvents(tenantId, ruleChainFinal.getFirstRuleNodeId(), 1000) - .getData().stream().filter(filterByCustomEvent()).collect(Collectors.toList()); + .getData().stream().filter(filterByPostTelemetryEventType()).collect(Collectors.toList()); log.warn("filtered debug events [{}]", debugEvents.size()); debugEvents.forEach((e) -> log.warn("event: {}", e)); return debugEvents; diff --git a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java index 6c060feb14..654f934ed2 100644 --- a/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java @@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; @@ -50,7 +51,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @DaoSqlTest public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest { @@ -133,7 +133,7 @@ public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest void saveLatestTsForAssetAndDevice(List devices, Asset asset, int idx) throws ExecutionException, InterruptedException, TimeoutException { for (Device device : devices) { - TbMsg tbMsg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, device.getId(), getTbMsgMetadata(device.getName(), ts.get(idx)), TbMsgDataType.JSON, diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java index 1872fd676f..0084b391eb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java @@ -66,16 +66,44 @@ public enum TbMsgType { RELATION_DELETED("Relation Deleted"), RELATIONS_DELETED("All Relations Deleted"), PROVISION_SUCCESS(null), - PROVISION_FAILURE(null); + PROVISION_FAILURE(null), + SEND_EMAIL(null), + + // tellSelfOnly types + GENERATOR_NODE_SELF_MSG(null, true), + + DEVICE_PROFILE_PERIODIC_SELF_MSG(null, true), + DEVICE_PROFILE_UPDATE_SELF_MSG(null, true), + DEVICE_UPDATE_SELF_MSG(null, true), + + DEDUPLICATION_TIMEOUT_SELF_MSG(null, true), + + DELAY_TIMEOUT_SELF_MSG(null, true), + + MSG_COUNT_SELF_MSG(null, true); + + public static final List NODE_CONNECTIONS = EnumSet.allOf(TbMsgType.class).stream() - .map(TbMsgType::getRuleNodeConnection).filter(Objects::nonNull).collect(Collectors.toUnmodifiableList()); + .filter(tbMsgType -> !tbMsgType.isTellSelfOnly()) + .map(TbMsgType::getRuleNodeConnection) + .filter(Objects::nonNull) + .collect(Collectors.toUnmodifiableList()); @Getter private final String ruleNodeConnection; + @Getter + private final boolean tellSelfOnly; + + TbMsgType(String ruleNodeConnection, boolean tellSelfOnly) { + this.ruleNodeConnection = ruleNodeConnection; + this.tellSelfOnly = tellSelfOnly; + } + TbMsgType(String ruleNodeConnection) { this.ruleNodeConnection = ruleNodeConnection; + this.tellSelfOnly = false; } public static String getRuleNodeConnectionOrElseOther(String msgType) { diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java index c1f9dffd17..58f2089aed 100644 --- a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java +++ b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java @@ -22,10 +22,18 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM; import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE; +import static org.thingsboard.server.common.data.msg.TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG; +import static org.thingsboard.server.common.data.msg.TbMsgType.DELAY_TIMEOUT_SELF_MSG; import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED_TO_EDGE; import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UNASSIGNED_FROM_EDGE; +import static org.thingsboard.server.common.data.msg.TbMsgType.MSG_COUNT_SELF_MSG; import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_FAILURE; import static org.thingsboard.server.common.data.msg.TbMsgType.PROVISION_SUCCESS; +import static org.thingsboard.server.common.data.msg.TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG; +import static org.thingsboard.server.common.data.msg.TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG; +import static org.thingsboard.server.common.data.msg.TbMsgType.DEVICE_UPDATE_SELF_MSG; +import static org.thingsboard.server.common.data.msg.TbMsgType.GENERATOR_NODE_SELF_MSG; +import static org.thingsboard.server.common.data.msg.TbMsgType.SEND_EMAIL; class TbMsgTypeTest { @@ -35,7 +43,15 @@ class TbMsgTypeTest { ENTITY_ASSIGNED_TO_EDGE, ENTITY_UNASSIGNED_FROM_EDGE, PROVISION_FAILURE, - PROVISION_SUCCESS + PROVISION_SUCCESS, + SEND_EMAIL, + GENERATOR_NODE_SELF_MSG, + DEVICE_PROFILE_PERIODIC_SELF_MSG, + DEVICE_PROFILE_UPDATE_SELF_MSG, + DEVICE_UPDATE_SELF_MSG, + DEDUPLICATION_TIMEOUT_SELF_MSG, + DELAY_TIMEOUT_SELF_MSG, + MSG_COUNT_SELF_MSG ); diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index 9848046b11..c6c1a36694 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -29,10 +29,12 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.gen.MsgProtos; import org.thingsboard.server.common.msg.queue.TbMsgCallback; import java.io.Serializable; +import java.util.Objects; import java.util.UUID; /** @@ -42,7 +44,9 @@ import java.util.UUID; @Slf4j public final class TbMsg implements Serializable { - public static final String EMPTY = "{}"; + public static final String EMPTY_JSON_OBJECT = "{}"; + public static final String EMPTY_JSON_ARRAY = "[]"; + public static final String EMPTY_STRING = ""; private final String queueName; private final UUID id; @@ -68,61 +72,208 @@ public final class TbMsg implements Serializable { return ctx.getAndIncrementRuleNodeCounter(); } + @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId); } + /** + * Creates a new TbMsg instance with the specified parameters. + * + *

Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to + * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, + * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String, RuleChainId, RuleNodeId)} + * method instead.

+ * + * @param queueName the name of the queue where the message will be sent + * @param type the type of the message + * @param originator the originator of the message + * @param customerId the ID of the customer associated with the message + * @param metaData the metadata of the message + * @param data the data of the message + * @param ruleChainId the ID of the rule chain associated with the message + * @param ruleNodeId the ID of the rule node associated with the message + * @return new TbMsg instance + */ + @Deprecated(since = "3.5.2") public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); } + @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { return newMsg(type, originator, null, metaData, data); } + @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); } + public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { + return newMsg(queueName, type, originator, null, metaData, data, ruleChainId, ruleNodeId); + } + + public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId, + metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); + } + + public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { + return newMsg(type, originator, null, metaData, data); + } + + public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId, + metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); + } + // REALLY NEW MSG + /** + * Creates a new TbMsg instance with the specified parameters. + * + *

Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to + * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, + * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, TbMsgMetaData, String)} + * method instead.

+ * + * @param queueName the name of the queue where the message will be sent + * @param type the type of the message + * @param originator the originator of the message + * @param metaData the metadata of the message + * @param data the data of the message + * @return new TbMsg instance + */ + @Deprecated(since = "3.5.2") public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) { return newMsg(queueName, type, originator, null, metaData, data); } + /** + * Creates a new TbMsg instance with the specified parameters. + * + *

Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to + * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, + * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String)} + * method instead.

+ * + * @param queueName the name of the queue where the message will be sent + * @param type the type of the message + * @param originator the originator of the message + * @param customerId the ID of the customer associated with the message + * @param metaData the metadata of the message + * @param data the data of the message + * @return new TbMsg instance + */ + @Deprecated(since = "3.5.2") public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); } + @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY); } + /** + * Creates a new TbMsg instance with the specified parameters. + * + *

Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to + * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, + * it is recommended to use the {@link #newMsg(TbMsgType, EntityId, TbMsgMetaData, TbMsgDataType, String)} + * method instead.

+ * + * @param type the type of the message + * @param originator the originator of the message + * @param metaData the metadata of the message + * @param dataType the dataType of the message + * @param data the data of the message + * @return new TbMsg instance + */ + @Deprecated(since = "3.5.2") public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { return newMsg(type, originator, null, metaData, dataType, data); } + public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { + return newMsg(queueName, type, originator, null, metaData, data); + } + + public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId, + metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); + } + + public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId, + metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY); + } + + public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { + return newMsg(type, originator, null, metaData, dataType, data); + } + // For Tests only + @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); } + @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback); } + /** + * Transforms an existing TbMsg instance by changing its message type, originator, metadata, and data. + * + *

Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to + * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, + * it is recommended to use the {@link #transformMsg(TbMsg, TbMsgType, EntityId, TbMsgMetaData, String)} + * method instead.

+ * + * + * @param tbMsg the TbMsg instance to transform + * @param type the new message type + * @param originator the new originator + * @param metaData the new metadata + * @param data the new data + * @return the transformed TbMsg instance + */ + @Deprecated(since = "3.5.2") public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback); } + public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, null, + metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); + } + + public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, null, + metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback); + } + + public static TbMsg transformMsg(TbMsg tbMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type.name(), originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, + data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback); + } + + public static TbMsg transformMsgOriginator(TbMsg tbMsg, EntityId originatorId) { + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, originatorId, tbMsg.getCustomerId(), tbMsg.metaData, tbMsg.dataType, + tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); + } + public static TbMsg transformMsgData(TbMsg tbMsg, String data) { return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); @@ -133,6 +284,11 @@ public final class TbMsg implements Serializable { tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } + public static TbMsg transformMsg(TbMsg tbMsg, TbMsgMetaData metadata, String data) { + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata, tbMsg.dataType, + data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); + } + public static TbMsg transformMsg(TbMsg tbMsg, CustomerId customerId) { return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); @@ -185,11 +341,7 @@ public final class TbMsg implements Serializable { this.ruleChainId = ruleChainId; this.ruleNodeId = ruleNodeId; this.ctx = ctx != null ? ctx : new TbMsgProcessingCtx(); - if (callback != null) { - this.callback = callback; - } else { - this.callback = TbMsgCallback.EMPTY; - } + this.callback = Objects.requireNonNullElse(callback, TbMsgCallback.EMPTY); } public static ByteString toByteString(TbMsg msg) { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java index 6500467af7..497540ee44 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java @@ -1151,7 +1151,7 @@ public class DefaultTransportService implements TransportService { queueName = deviceProfile.getDefaultQueueName(); } - TbMsg tbMsg = TbMsg.newMsg(queueName, tbMsgType.name(), deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null); + TbMsg tbMsg = TbMsg.newMsg(queueName, tbMsgType, deviceId, customerId, metaData, gson.toJson(json), ruleChainId, null); sendToRuleEngine(tenantId, tbMsg, callback); } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index 88bf80e9f9..be35e74321 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rule.RuleNode; @@ -183,12 +184,41 @@ public interface TbContext { void ack(TbMsg tbMsg); + @Deprecated(since = "3.5.2", forRemoval = true) TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data); + /** + * Creates a new TbMsg instance with the specified parameters. + * + *

Deprecated: This method is deprecated since version 3.5.2 and should only be used when you need to + * specify a custom message type that doesn't exist in the {@link TbMsgType} enum. For standard message types, + * it is recommended to use the {@link #newMsg(String, TbMsgType, EntityId, CustomerId, TbMsgMetaData, String)} + * method instead.

+ * + * @param queueName the name of the queue where the message will be sent + * @param type the type of the message + * @param originator the originator of the message + * @param customerId the ID of the customer associated with the message + * @param metaData the metadata of the message + * @param data the data of the message + * @return new TbMsg instance + */ + @Deprecated(since = "3.5.2") TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data); + @Deprecated(since = "3.5.2", forRemoval = true) TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data); + TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data); + + TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data); + + TbMsg transformMsg(TbMsg origMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data); + + TbMsg transformMsg(TbMsg origMsg, TbMsgMetaData metaData, String data); + + TbMsg transformMsgOriginator(TbMsg origMsg, EntityId originator); + TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId); TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId); @@ -196,7 +226,7 @@ public interface TbContext { TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId); // TODO: Does this changes the message? - TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action); + TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, TbMsgType actionMsgType); TbMsg attributesUpdatedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List attributes); diff --git a/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java b/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java index 956cfaf40c..cb5514a82b 100644 --- a/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java +++ b/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java @@ -22,6 +22,7 @@ import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -43,7 +44,7 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.put("data_key", "data_value"); - TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); String result = TbNodeUtils.processPattern(pattern, msg); Assert.assertEquals("ABC metadata_value data_value", result); } @@ -57,7 +58,7 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.put("key", "data_value"); - TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); String result = TbNodeUtils.processPattern(pattern, msg); Assert.assertEquals(pattern, result); } @@ -71,7 +72,7 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.put("key", "data_value"); - TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); String result = TbNodeUtils.processPattern(pattern, msg); Assert.assertEquals("ABC metadata_value data_value", result); } @@ -92,7 +93,7 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.set("key1", key1Node); - TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); String result = TbNodeUtils.processPattern(pattern, msg); Assert.assertEquals("ABC metadata_value value3", result); } @@ -113,7 +114,7 @@ public class TbNodeUtilsTest { ObjectNode node = JacksonUtil.newObjectNode(); node.set("key1", key1Node); - TbMsg msg = TbMsg.newMsg("CUSTOM", TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, md, JacksonUtil.toString(node)); String result = TbNodeUtils.processPattern(pattern, msg); Assert.assertEquals("ABC metadata_value $[key1.key2[0].key3]", result); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java index bc27154ad8..18317481bd 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java @@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.ScriptEngine; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.DataConstants; @@ -32,10 +33,6 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import static org.thingsboard.common.util.DonAsynchron.withCallback; -import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM; -import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_CLEAR; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UPDATED; @Slf4j @@ -62,11 +59,11 @@ public abstract class TbAbstractAlarmNode processAlarm(TbContext ctx, TbMsg msg); - protected ListenableFuture buildAlarmDetails(TbContext ctx, TbMsg msg, JsonNode previousDetails) { + protected ListenableFuture buildAlarmDetails(TbMsg msg, JsonNode previousDetails) { try { TbMsg dummyMsg = msg; if (previousDetails != null) { TbMsgMetaData metaData = msg.getMetaData().copy(); metaData.putValue(PREV_ALARM_DETAILS, JacksonUtil.toString(previousDetails)); - dummyMsg = ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, msg.getData()); + dummyMsg = TbMsg.transformMsg(msg, metaData); } return scriptEngine.executeJsonAsync(dummyMsg); } catch (Exception e) { @@ -101,7 +98,7 @@ public abstract class TbAbstractAlarmNode ctx.tellNext(toAlarmMsg(ctx, alarmResult, msg), alarmAction), throwable -> ctx.tellFailure(toAlarmMsg(ctx, alarmResult, msg), throwable)); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java index a8d7d4985f..d0215a441f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java @@ -71,7 +71,7 @@ public class TbClearAlarmNode extends TbAbstractAlarmNode clearAlarm(TbContext ctx, TbMsg msg, Alarm alarm) { ctx.logJsEvalRequest(); - ListenableFuture asyncDetails = buildAlarmDetails(ctx, msg, alarm.getDetails()); + ListenableFuture asyncDetails = buildAlarmDetails(msg, alarm.getDetails()); return Futures.transform(asyncDetails, details -> { ctx.logJsEvalResponse(); AlarmApiCallResult result = ctx.getAlarmService().clearAlarm(ctx.getTenantId(), alarm.getId(), System.currentTimeMillis(), details); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java index 84e82b76e8..b08fd1a562 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java @@ -120,7 +120,7 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode future = createRelationIfAbsent(ctx, msg, entity, relationType); return Futures.transform(future, result -> { if (result && config.isChangeOriginatorToRelatedEntity()) { - TbMsg tbMsg = ctx.transformMsg(msg, msg.getType(), entity.getEntityId(), msg.getMetaData(), msg.getData()); + TbMsg tbMsg = ctx.transformMsgOriginator(msg, entity.getEntityId()); return new RelationContainer(tbMsg, result); } return new RelationContainer(msg, result); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java index d9a99c3229..0fd99651a1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java @@ -24,6 +24,8 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -32,9 +34,6 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; -import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCESS; - @Slf4j @RuleNode( type = ComponentType.ACTION, @@ -48,8 +47,6 @@ import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCES ) public class TbMsgCountNode implements TbNode { - private static final String TB_MSG_COUNT_NODE_MSG = "TbMsgCountNodeMsg"; - private AtomicLong messagesProcessed = new AtomicLong(0); private final Gson gson = new Gson(); private UUID nextTickId; @@ -68,7 +65,7 @@ public class TbMsgCountNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (msg.getType().equals(TB_MSG_COUNT_NODE_MSG) && msg.getId().equals(nextTickId)) { + if (msg.getType().equals(TbMsgType.MSG_COUNT_SELF_MSG.name()) && msg.getId().equals(nextTickId)) { JsonObject telemetryJson = new JsonObject(); telemetryJson.addProperty(this.telemetryPrefix + "_" + ctx.getServiceId(), messagesProcessed.longValue()); @@ -77,8 +74,8 @@ public class TbMsgCountNode implements TbNode { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("delta", Long.toString(System.currentTimeMillis() - lastScheduledTs + delay)); - TbMsg tbMsg = TbMsg.newMsg(msg.getQueueName(), POST_TELEMETRY_REQUEST.name(), ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson)); - ctx.enqueueForTellNext(tbMsg, SUCCESS); + TbMsg tbMsg = TbMsg.newMsg(msg.getQueueName(), TbMsgType.POST_TELEMETRY_REQUEST, ctx.getTenantId(), msg.getCustomerId(), metaData, gson.toJson(telemetryJson)); + ctx.enqueueForTellNext(tbMsg, TbNodeConnectionType.SUCCESS); scheduleTickMsg(ctx, tbMsg); } else { messagesProcessed.incrementAndGet(); @@ -93,7 +90,7 @@ public class TbMsgCountNode implements TbNode { } lastScheduledTs = lastScheduledTs + delay; long curDelay = Math.max(0L, (lastScheduledTs - curTs)); - TbMsg tickMsg = ctx.newMsg(null, TB_MSG_COUNT_NODE_MSG, ctx.getSelfId(), msg != null ? msg.getCustomerId() : null, new TbMsgMetaData(), ""); + TbMsg tickMsg = ctx.newMsg(null, TbMsgType.MSG_COUNT_SELF_MSG, ctx.getSelfId(), msg != null ? msg.getCustomerId() : null, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); nextTickId = tickMsg.getId(); ctx.tellSelf(tickMsg, curDelay); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java index 4c8a5b28e1..1c487b2352 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java @@ -101,13 +101,13 @@ public class TbSnsNode extends TbAbstractExternalNode { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(MESSAGE_ID, result.getMessageId()); metaData.putValue(REQUEST_ID, result.getSdkResponseMetadata().getRequestId()); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java index f8ebc8e295..d5f3f842e9 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java @@ -27,7 +27,6 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; @@ -88,15 +87,15 @@ public class TbSqsNode extends TbAbstractExternalNode { public void onMsg(TbContext ctx, TbMsg msg) { withCallback(publishMessageAsync(ctx, msg), m -> tellSuccess(ctx, m), - t -> tellFailure(ctx, processException(ctx, msg, t), t)); + t -> tellFailure(ctx, processException(msg, t), t)); ackIfNeeded(ctx, msg); } private ListenableFuture publishMessageAsync(TbContext ctx, TbMsg msg) { - return ctx.getExternalCallExecutor().executeAsync(() -> publishMessage(ctx, msg)); + return ctx.getExternalCallExecutor().executeAsync(() -> publishMessage(msg)); } - private TbMsg publishMessage(TbContext ctx, TbMsg msg) { + private TbMsg publishMessage(TbMsg msg) { String queueUrl = TbNodeUtils.processPattern(this.config.getQueueUrlPattern(), msg); SendMessageRequest sendMsgRequest = new SendMessageRequest(); sendMsgRequest.withQueueUrl(queueUrl); @@ -115,10 +114,10 @@ public class TbSqsNode extends TbAbstractExternalNode { sendMsgRequest.withMessageGroupId(msg.getOriginator().toString()); } SendMessageResult result = this.sqsClient.sendMessage(sendMsgRequest); - return processSendMessageResult(ctx, msg, result); + return processSendMessageResult(msg, result); } - private TbMsg processSendMessageResult(TbContext ctx, TbMsg origMsg, SendMessageResult result) { + private TbMsg processSendMessageResult(TbMsg origMsg, SendMessageResult result) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(MESSAGE_ID, result.getMessageId()); metaData.putValue(REQUEST_ID, result.getSdkResponseMetadata().getRequestId()); @@ -131,13 +130,13 @@ public class TbSqsNode extends TbAbstractExternalNode { if (!StringUtils.isEmpty(result.getSequenceNumber())) { metaData.putValue(SEQUENCE_NUMBER, result.getSequenceNumber()); } - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } - private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable t) { + private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java index 75b63c59e9..7c3d6424e5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java @@ -30,6 +30,8 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; @@ -41,7 +43,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import static org.thingsboard.common.util.DonAsynchron.withCallback; -import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCESS; @Slf4j @RuleNode( @@ -58,8 +59,6 @@ import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCES public class TbMsgGeneratorNode implements TbNode { - private static final String TB_MSG_GENERATOR_NODE_MSG = "TbMsgGeneratorNodeMsg"; - private TbMsgGeneratorNodeConfiguration config; private ScriptEngine scriptEngine; private long delay; @@ -107,13 +106,13 @@ public class TbMsgGeneratorNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { log.trace("onMsg, config {}, msg {}", config, msg); - if (initialized.get() && msg.getType().equals(TB_MSG_GENERATOR_NODE_MSG) && msg.getId().equals(nextTickId)) { + if (initialized.get() && msg.getType().equals(TbMsgType.GENERATOR_NODE_SELF_MSG.name()) && msg.getId().equals(nextTickId)) { TbStopWatch sw = TbStopWatch.create(); withCallback(generate(ctx, msg), m -> { log.trace("onMsg onSuccess callback, took {}ms, config {}, msg {}", sw.stopAndGetTotalTimeMillis(), config, msg); if (initialized.get() && (config.getMsgCount() == TbMsgGeneratorNodeConfiguration.UNLIMITED_MSG_COUNT || currentMsgCount < config.getMsgCount())) { - ctx.enqueueForTellNext(m, SUCCESS); + ctx.enqueueForTellNext(m, TbNodeConnectionType.SUCCESS); scheduleTickMsg(ctx); currentMsgCount++; } @@ -137,7 +136,7 @@ public class TbMsgGeneratorNode implements TbNode { } lastScheduledTs = lastScheduledTs + delay; long curDelay = Math.max(0L, (lastScheduledTs - curTs)); - TbMsg tickMsg = ctx.newMsg(config.getQueueName(), TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), ""); + TbMsg tickMsg = ctx.newMsg(config.getQueueName(), TbMsgType.GENERATOR_NODE_SELF_MSG, ctx.getSelfId(), new TbMsgMetaData(), TbMsg.EMPTY_STRING); nextTickId = tickMsg.getId(); ctx.tellSelf(tickMsg, curDelay); } @@ -145,7 +144,7 @@ public class TbMsgGeneratorNode implements TbNode { private ListenableFuture generate(TbContext ctx, TbMsg msg) { log.trace("generate, config {}", config); if (prevMsg == null) { - prevMsg = ctx.newMsg(config.getQueueName(), "", originatorId, msg.getCustomerId(), new TbMsgMetaData(), "{}"); + prevMsg = ctx.newMsg(config.getQueueName(), "", originatorId, msg.getCustomerId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); } if (initialized.get()) { ctx.logJsEvalRequest(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java index 5654b4095a..fae40ff5f5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java @@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.id.EntityId; @@ -60,10 +61,7 @@ import java.util.concurrent.TimeUnit; @Slf4j public class TbMsgDeduplicationNode implements TbNode { - private static final String TB_MSG_DEDUPLICATION_TIMEOUT_MSG = "TbMsgDeduplicationNodeMsg"; public static final int TB_MSG_DEDUPLICATION_RETRY_DELAY = 10; - private static final String EMPTY_DATA = ""; - private static final TbMsgMetaData EMPTY_META_DATA = new TbMsgMetaData(); private TbMsgDeduplicationNodeConfiguration config; @@ -82,7 +80,7 @@ public class TbMsgDeduplicationNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { - if (TB_MSG_DEDUPLICATION_TIMEOUT_MSG.equals(msg.getType())) { + if (TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG.name().equals(msg.getType())) { processDeduplication(ctx, msg.getOriginator()); } else { processOnRegularMsg(ctx, msg); @@ -210,7 +208,7 @@ public class TbMsgDeduplicationNode implements TbNode { } private void scheduleTickMsg(TbContext ctx, EntityId deduplicationId) { - ctx.tellSelf(ctx.newMsg(null, TB_MSG_DEDUPLICATION_TIMEOUT_MSG, deduplicationId, EMPTY_META_DATA, EMPTY_DATA), deduplicationInterval + 1); + ctx.tellSelf(ctx.newMsg(null, TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG, deduplicationId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING), deduplicationInterval + 1); } private String getMergedData(List msgs) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index 00ba3acc50..dabba5970a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -23,6 +23,8 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -32,8 +34,6 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; -import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCESS; - @Slf4j @RuleNode( type = ComponentType.ACTION, @@ -50,8 +50,6 @@ import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCES ) public class TbMsgDelayNode implements TbNode { - private static final String TB_MSG_DELAY_NODE_MSG = "TbMsgDelayNodeMsg"; - private TbMsgDelayNodeConfiguration config; private Map pendingMsgs; @@ -63,7 +61,7 @@ public class TbMsgDelayNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (msg.getType().equals(TB_MSG_DELAY_NODE_MSG)) { + if (msg.getType().equals(TbMsgType.DELAY_TIMEOUT_SELF_MSG.name())) { TbMsg pendingMsg = pendingMsgs.remove(UUID.fromString(msg.getData())); if (pendingMsg != null) { ctx.enqueueForTellNext( @@ -75,13 +73,13 @@ public class TbMsgDelayNode implements TbNode { pendingMsg.getMetaData(), pendingMsg.getData() ), - SUCCESS + TbNodeConnectionType.SUCCESS ); } } else { if (pendingMsgs.size() < config.getMaxPendingMsgs()) { pendingMsgs.put(msg.getId(), msg); - TbMsg tickMsg = ctx.newMsg(null, TB_MSG_DELAY_NODE_MSG, ctx.getSelfId(), msg.getCustomerId(), new TbMsgMetaData(), msg.getId().toString()); + TbMsg tickMsg = ctx.newMsg(null, TbMsgType.DELAY_TIMEOUT_SELF_MSG, ctx.getSelfId(), msg.getCustomerId(), TbMsgMetaData.EMPTY, msg.getId().toString()); ctx.tellSelf(tickMsg, getDelay(msg)); ctx.ack(msg); } else { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java index 3b927f05a6..b3f1c87171 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java @@ -28,7 +28,6 @@ import com.google.pubsub.v1.PubsubMessage; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; @@ -103,28 +102,28 @@ public class TbPubSubNode extends TbAbstractExternalNode { ApiFuture messageIdFuture = this.pubSubClient.publish(pubsubMessageBuilder.build()); ApiFutures.addCallback(messageIdFuture, new ApiFutureCallback() { public void onSuccess(String messageId) { - TbMsg next = processPublishResult(ctx, msg, messageId); + TbMsg next = processPublishResult(msg, messageId); tellSuccess(ctx, next); } public void onFailure(Throwable t) { - TbMsg next = processException(ctx, msg, t); + TbMsg next = processException(msg, t); tellFailure(ctx, next, t); } }, ctx.getExternalCallExecutor()); } - private TbMsg processPublishResult(TbContext ctx, TbMsg origMsg, String messageId) { + private TbMsg processPublishResult(TbMsg origMsg, String messageId) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(MESSAGE_ID, messageId); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } - private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable t) { + private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } private Publisher initPubSubClient() throws IOException { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java index 80baa86505..a336fc1f77 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java @@ -165,24 +165,24 @@ public class TbKafkaNode extends TbAbstractExternalNode { private void processRecord(TbContext ctx, TbMsg msg, RecordMetadata metadata, Exception e) { if (e == null) { - tellSuccess(ctx, processResponse(ctx, msg, metadata)); + tellSuccess(ctx, processResponse(msg, metadata)); } else { - tellFailure(ctx, processException(ctx, msg, e), e); + tellFailure(ctx, processException(msg, e), e); } } - private TbMsg processResponse(TbContext ctx, TbMsg origMsg, RecordMetadata recordMetadata) { + private TbMsg processResponse(TbMsg origMsg, RecordMetadata recordMetadata) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(OFFSET, String.valueOf(recordMetadata.offset())); metaData.putValue(PARTITION, String.valueOf(recordMetadata.partition())); metaData.putValue(TOPIC, recordMetadata.topic()); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } - private TbMsg processException(TbContext ctx, TbMsg origMsg, Exception e) { + private TbMsg processException(TbMsg origMsg, Exception e) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage()); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java index ae661e48e4..a52641bedc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java @@ -19,7 +19,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbEmail; @@ -27,6 +26,9 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -34,9 +36,6 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; -import static org.thingsboard.server.common.data.msg.TbNodeConnectionType.SUCCESS; -import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE; - @Slf4j @RuleNode( type = ComponentType.TRANSFORMATION, @@ -68,7 +67,7 @@ public class TbMsgToEmailNode implements TbNode { try { TbEmail email = convert(msg); TbMsg emailMsg = buildEmailMsg(ctx, msg, email); - ctx.tellNext(emailMsg, SUCCESS); + ctx.tellNext(emailMsg, TbNodeConnectionType.SUCCESS); } catch (Exception ex) { log.warn("Can not convert message to email " + ex.getMessage()); ctx.tellFailure(msg, ex); @@ -77,7 +76,7 @@ public class TbMsgToEmailNode implements TbNode { private TbMsg buildEmailMsg(TbContext ctx, TbMsg msg, TbEmail email) throws JsonProcessingException { String emailJson = JacksonUtil.toString(email); - return ctx.transformMsg(msg, SEND_EMAIL_TYPE, msg.getOriginator(), msg.getMetaData().copy(), emailJson); + return ctx.transformMsg(msg, TbMsgType.SEND_EMAIL, msg.getOriginator(), msg.getMetaData().copy(), emailJson); } private TbEmail convert(TbMsg msg) throws IOException { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java index eec403cdb9..66b23a29af 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java @@ -16,9 +16,8 @@ package org.thingsboard.rule.engine.mail; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.StringUtils; import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbEmail; @@ -26,6 +25,8 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.external.TbAbstractExternalNode; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -50,7 +51,6 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; public class TbSendEmailNode extends TbAbstractExternalNode { private static final String MAIL_PROP = "mail."; - static final String SEND_EMAIL_TYPE = "SEND_EMAIL"; private TbSendEmailNodeConfiguration config; private JavaMailSenderImpl mailSender; @@ -101,7 +101,7 @@ public class TbSendEmailNode extends TbAbstractExternalNode { } private void validateType(String type) { - if (!SEND_EMAIL_TYPE.equals(type)) { + if (!TbMsgType.SEND_EMAIL.name().equals(type)) { log.warn("Not expected msg type [{}] for SendEmail Node", type); throw new IllegalStateException("Not expected msg type " + type + " for SendEmail Node"); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java index d4bdd320d1..25b9205602 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java @@ -115,7 +115,7 @@ public class CalculateDeltaNode implements TbNode { long period = previousData != null ? currentTs - previousData.ts : 0; result.put(config.getPeriodValueKey(), period); } - ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(result))); + ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(result))); }, t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java index 569c76c2a2..4cf564fd7b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java @@ -43,10 +43,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static org.thingsboard.rule.engine.metadata.TbGetTelemetryNodeConfiguration.FETCH_MODE_ALL; -import static org.thingsboard.rule.engine.metadata.TbGetTelemetryNodeConfiguration.FETCH_MODE_FIRST; -import static org.thingsboard.rule.engine.metadata.TbGetTelemetryNodeConfiguration.MAX_FETCH_SIZE; - /** * Created by mshvayka on 04.09.18. */ @@ -76,7 +72,7 @@ public class TbGetTelemetryNode implements TbNode { public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbGetTelemetryNodeConfiguration.class); tsKeyNames = config.getLatestTsKeyNames(); - limit = config.getFetchMode().equals(FETCH_MODE_ALL) ? validateLimit(config.getLimit()) : 1; + limit = config.getFetchMode().equals(TbGetTelemetryNodeConfiguration.FETCH_MODE_ALL) ? validateLimit(config.getLimit()) : 1; fetchMode = config.getFetchMode(); orderByFetchAll = config.getOrderBy(); if (StringUtils.isEmpty(orderByFetchAll)) { @@ -86,7 +82,7 @@ public class TbGetTelemetryNode implements TbNode { } Aggregation parseAggregationConfig(String aggName) { - if (StringUtils.isEmpty(aggName) || !fetchMode.equals(FETCH_MODE_ALL)) { + if (StringUtils.isEmpty(aggName) || !fetchMode.equals(TbGetTelemetryNodeConfiguration.FETCH_MODE_ALL)) { return Aggregation.NONE; } return Aggregation.valueOf(aggName); @@ -103,7 +99,7 @@ public class TbGetTelemetryNode implements TbNode { ListenableFuture> list = ctx.getTimeseriesService().findAll(ctx.getTenantId(), msg.getOriginator(), buildQueries(interval, keys)); DonAsynchron.withCallback(list, data -> { process(data, msg, keys); - ctx.tellSuccess(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), msg.getData())); + ctx.tellSuccess(msg); }, error -> ctx.tellFailure(msg, error), ctx.getDbCallbackExecutor()); } catch (Exception e) { ctx.tellFailure(msg, e); @@ -124,9 +120,9 @@ public class TbGetTelemetryNode implements TbNode { private String getOrderBy() { switch (fetchMode) { - case FETCH_MODE_ALL: + case TbGetTelemetryNodeConfiguration.FETCH_MODE_ALL: return orderByFetchAll; - case FETCH_MODE_FIRST: + case TbGetTelemetryNodeConfiguration.FETCH_MODE_FIRST: return ASC_ORDER; default: return DESC_ORDER; @@ -135,7 +131,7 @@ public class TbGetTelemetryNode implements TbNode { private void process(List entries, TbMsg msg, List keys) { ObjectNode resultNode = JacksonUtil.newObjectNode(JacksonUtil.ALLOW_UNQUOTED_FIELD_NAMES_MAPPER); - if (FETCH_MODE_ALL.equals(fetchMode)) { + if (TbGetTelemetryNodeConfiguration.FETCH_MODE_ALL.equals(fetchMode)) { entries.forEach(entry -> processArray(resultNode, entry)); } else { entries.forEach(entry -> processSingle(resultNode, entry)); @@ -216,7 +212,7 @@ public class TbGetTelemetryNode implements TbNode { if (limit != 0) { return limit; } else { - return MAX_FETCH_SIZE; + return TbGetTelemetryNodeConfiguration.MAX_FETCH_SIZE; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 8fac7b1683..ccb7082e01 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -25,7 +25,6 @@ import org.thingsboard.mqtt.MqttClientConfig; import org.thingsboard.mqtt.MqttConnectResult; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; @@ -41,6 +40,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; import javax.net.ssl.SSLException; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -58,7 +58,7 @@ import java.util.concurrent.TimeoutException; ) public class TbMqttNode extends TbAbstractExternalNode { - private static final Charset UTF8 = Charset.forName("UTF-8"); + private static final Charset UTF8 = StandardCharsets.UTF_8; private static final String ERROR = "error"; @@ -85,17 +85,17 @@ public class TbMqttNode extends TbAbstractExternalNode { if (future.isSuccess()) { tellSuccess(ctx, msg); } else { - tellFailure(ctx, processException(ctx, msg, future.cause()), future.cause()); + tellFailure(ctx, processException(msg, future.cause()), future.cause()); } } ); ackIfNeeded(ctx, msg); } - private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable e) { + private TbMsg processException(TbMsg origMsg, Throwable e) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage()); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index 70f15935fc..9e2719bf53 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.device.profile.AlarmConditionSpecType; import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -189,7 +190,7 @@ class AlarmState { metaData.putValue(DataConstants.IS_CLEARED_ALARM, Boolean.TRUE.toString()); } setAlarmConditionMetadata(ruleState, metaData); - TbMsg newMsg = ctx.newMsg(lastMsgQueueName != null ? lastMsgQueueName : null, "ALARM", + TbMsg newMsg = ctx.newMsg(lastMsgQueueName != null ? lastMsgQueueName : null, TbMsgType.ALARM, originator, msg != null ? msg.getCustomerId() : null, metaData, data); ctx.enqueueForTellNext(newMsg, relationType); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java index 4397200fe4..e368358299 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java @@ -224,7 +224,7 @@ class DeviceState { private boolean processAttributesDeleteNotification(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { boolean stateChanged = false; List keys = new ArrayList<>(); - new JsonParser().parse(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray().forEach(e -> keys.add(e.getAsString())); + JsonParser.parseString(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray().forEach(e -> keys.add(e.getAsString())); String scope = msg.getMetaData().getValue(DataConstants.SCOPE); if (StringUtils.isEmpty(scope)) { scope = DataConstants.CLIENT_SCOPE; @@ -252,7 +252,7 @@ class DeviceState { private boolean processAttributes(TbContext ctx, TbMsg msg, String scope) throws ExecutionException, InterruptedException { boolean stateChanged = false; - Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())); + Set attributes = JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData())); if (!attributes.isEmpty()) { SnapshotUpdate update = merge(latestValues, attributes, scope); for (DeviceProfileAlarm alarm : deviceProfile.getAlarmSettings()) { @@ -267,7 +267,7 @@ class DeviceState { protected boolean processTelemetry(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { boolean stateChanged = false; - Map> tsKvMap = JsonConverter.convertToSortedTelemetry(new JsonParser().parse(msg.getData()), msg.getMetaDataTs()); + Map> tsKvMap = JsonConverter.convertToSortedTelemetry(JsonParser.parseString(msg.getData()), msg.getMetaDataTs()); // iterate over data by ts (ASC order). for (Map.Entry> entry : tsKvMap.entrySet()) { Long ts = entry.getKey(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index a8b3ef4f5f..0abb15f279 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -45,9 +46,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_DELETED; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UPDATED; - @Slf4j @RuleNode( type = ComponentType.ACTION, @@ -62,9 +60,6 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UPDATED; configDirective = "tbDeviceProfileConfig" ) public class TbDeviceProfileNode implements TbNode { - private static final String PERIODIC_MSG_TYPE = "TbDeviceProfilePeriodicMsg"; - private static final String PROFILE_UPDATE_MSG_TYPE = "TbDeviceProfileUpdateMsg"; - private static final String DEVICE_UPDATE_MSG_TYPE = "TbDeviceUpdateMsg"; private TbDeviceProfileNodeConfiguration config; private RuleEngineDeviceProfileCache cache; @@ -109,12 +104,16 @@ public class TbDeviceProfileNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { EntityType originatorType = msg.getOriginator().getEntityType(); - if (msg.getType().equals(PERIODIC_MSG_TYPE)) { + if (msg.getType().equals(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG.name())) { scheduleAlarmHarvesting(ctx, msg); harvestAlarms(ctx, System.currentTimeMillis()); - } else if (msg.getType().equals(PROFILE_UPDATE_MSG_TYPE)) { + return; + } + if (msg.getType().equals(TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG.name())) { updateProfile(ctx, new DeviceProfileId(UUID.fromString(msg.getData()))); - } else if (msg.getType().equals(DEVICE_UPDATE_MSG_TYPE)) { + return; + } + if (msg.getType().equals(TbMsgType.DEVICE_UPDATE_SELF_MSG.name())) { JsonNode data = JacksonUtil.toJsonNode(msg.getData()); DeviceId deviceId = new DeviceId(UUID.fromString(data.get("deviceId").asText())); if (data.has("profileId")) { @@ -122,28 +121,28 @@ public class TbDeviceProfileNode implements TbNode { } else { removeDeviceState(deviceId); } - } else { - if (EntityType.DEVICE.equals(originatorType)) { - DeviceId deviceId = new DeviceId(msg.getOriginator().getId()); - if (msg.getType().equals(ENTITY_UPDATED.name())) { - invalidateDeviceProfileCache(deviceId, msg.getData()); - ctx.tellSuccess(msg); - } else if (msg.getType().equals(ENTITY_DELETED.name())) { - removeDeviceState(deviceId); - ctx.tellSuccess(msg); + return; + } + if (EntityType.DEVICE.equals(originatorType)) { + DeviceId deviceId = new DeviceId(msg.getOriginator().getId()); + if (msg.getType().equals(TbMsgType.ENTITY_UPDATED.name())) { + invalidateDeviceProfileCache(deviceId, msg.getData()); + ctx.tellSuccess(msg); + } else if (msg.getType().equals(TbMsgType.ENTITY_DELETED.name())) { + removeDeviceState(deviceId); + ctx.tellSuccess(msg); + } else { + DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId, null); + if (deviceState != null) { + deviceState.process(ctx, msg); } else { - DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId, null); - if (deviceState != null) { - deviceState.process(ctx, msg); - } else { - log.info("Device was not found! Most probably device [" + deviceId + "] has been removed from the database. Acknowledging msg."); - ctx.ack(msg); - } + log.info("Device was not found! Most probably device [" + deviceId + "] has been removed from the database. Acknowledging msg."); + ctx.ack(msg); } - } else { - ctx.tellSuccess(msg); } + return; } + ctx.tellSuccess(msg); } @Override @@ -171,7 +170,7 @@ public class TbDeviceProfileNode implements TbNode { } protected void scheduleAlarmHarvesting(TbContext ctx, TbMsg msg) { - TbMsg periodicCheck = TbMsg.newMsg(PERIODIC_MSG_TYPE, ctx.getTenantId(), msg != null ? msg.getCustomerId() : null, TbMsgMetaData.EMPTY, "{}"); + TbMsg periodicCheck = TbMsg.newMsg(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG, ctx.getTenantId(), msg != null ? msg.getCustomerId() : null, TbMsgMetaData.EMPTY, "{}"); ctx.tellSelf(periodicCheck, TimeUnit.MINUTES.toMillis(1)); } @@ -196,7 +195,7 @@ public class TbDeviceProfileNode implements TbNode { } protected void onProfileUpdate(DeviceProfile profile) { - ctx.tellSelf(TbMsg.newMsg(PROFILE_UPDATE_MSG_TYPE, ctx.getTenantId(), TbMsgMetaData.EMPTY, profile.getId().getId().toString()), 0L); + ctx.tellSelf(TbMsg.newMsg(TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG, ctx.getTenantId(), TbMsgMetaData.EMPTY, profile.getId().getId().toString()), 0L); } private void onDeviceUpdate(DeviceId deviceId, DeviceProfile deviceProfile) { @@ -205,7 +204,7 @@ public class TbDeviceProfileNode implements TbNode { if (deviceProfile != null) { msgData.put("deviceProfileId", deviceProfile.getId().getId().toString()); } - ctx.tellSelf(TbMsg.newMsg(DEVICE_UPDATE_MSG_TYPE, ctx.getTenantId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(msgData)), 0L); + ctx.tellSelf(TbMsg.newMsg(TbMsgType.DEVICE_UPDATE_SELF_MSG, ctx.getTenantId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(msgData)), 0L); } protected void invalidateDeviceProfileCache(DeviceId deviceId, String deviceJson) { @@ -218,7 +217,7 @@ public class TbDeviceProfileNode implements TbNode { removeDeviceState(deviceId); } } catch (IllegalArgumentException e) { - log.debug("[{}] Received device update notification with non-device msg body: [{}][{}]", ctx.getSelfId(), deviceId, e); + log.debug("[{}] Received device update notification with non-device msg body: [{}]", ctx.getSelfId(), deviceId, e); } } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java index 4ae634902f..b9cc8209a7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java @@ -24,7 +24,6 @@ import com.rabbitmq.client.MessageProperties; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; @@ -86,7 +85,7 @@ public class TbRabbitMqNode extends TbAbstractExternalNode { public void onMsg(TbContext ctx, TbMsg msg) { withCallback(publishMessageAsync(ctx, msg), m -> tellSuccess(ctx, m), - t -> tellFailure(ctx, processException(ctx, msg, t), t)); + t -> tellFailure(ctx, processException(msg, t), t)); ackIfNeeded(ctx, msg); } @@ -115,10 +114,10 @@ public class TbRabbitMqNode extends TbAbstractExternalNode { return msg; } - private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable t) { + private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 81033191d6..70a22a692e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -203,7 +203,7 @@ public class TbHttpClient { future.addCallback(new ListenableFutureCallback<>() { @Override public void onFailure(Throwable throwable) { - onFailure.accept(processException(ctx, msg, throwable), throwable); + onFailure.accept(processException(msg, throwable), throwable); } @Override @@ -211,7 +211,7 @@ public class TbHttpClient { if (responseEntity.getStatusCode().is2xxSuccessful()) { onSuccess.accept(processResponse(ctx, msg, responseEntity)); } else { - onFailure.accept(processFailureResponse(ctx, msg, responseEntity), null); + onFailure.accept(processFailureResponse(msg, responseEntity), null); } } }); @@ -260,8 +260,8 @@ public class TbHttpClient { metaData.putValue(STATUS_CODE, response.getStatusCode().value() + ""); metaData.putValue(STATUS_REASON, response.getStatusCode().getReasonPhrase()); headersToMetaData(response.getHeaders(), metaData::putValue); - String body = response.getBody() == null ? "{}" : response.getBody(); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, body); + String body = response.getBody() == null ? TbMsg.EMPTY_JSON_OBJECT : response.getBody(); + return ctx.transformMsg(origMsg, metaData, body); } void headersToMetaData(Map> headers, BiConsumer consumer) { @@ -279,17 +279,17 @@ public class TbHttpClient { }); } - private TbMsg processFailureResponse(TbContext ctx, TbMsg origMsg, ResponseEntity response) { + private TbMsg processFailureResponse(TbMsg origMsg, ResponseEntity response) { TbMsgMetaData metaData = origMsg.getMetaData(); metaData.putValue(STATUS, response.getStatusCode().name()); metaData.putValue(STATUS_CODE, response.getStatusCode().value() + ""); metaData.putValue(STATUS_REASON, response.getStatusCode().getReasonPhrase()); metaData.putValue(ERROR_BODY, response.getBody()); headersToMetaData(response.getHeaders(), metaData::putValue); - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } - private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable e) { + private TbMsg processException(TbMsg origMsg, Throwable e) { TbMsgMetaData metaData = origMsg.getMetaData(); metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage()); if (e instanceof RestClientResponseException) { @@ -298,7 +298,7 @@ public class TbHttpClient { metaData.putValue(STATUS_CODE, restClientResponseException.getRawStatusCode() + ""); metaData.putValue(ERROR_BODY, restClientResponseException.getResponseBodyAsString()); } - return ctx.transformMsg(origMsg, origMsg.getType(), origMsg.getOriginator(), metaData, origMsg.getData()); + return TbMsg.transformMsg(origMsg, metaData); } private HttpHeaders prepareHeaders(TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java index 94b0e5d078..2a4df82715 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java @@ -18,7 +18,6 @@ package org.thingsboard.rule.engine.rest; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java index 5f9a2f63ed..26d22b5ef2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java @@ -57,7 +57,6 @@ public class TbSendRPCRequestNode implements TbNode { private Random random = new Random(); private Gson gson = new Gson(); - private JsonParser jsonParser = new JsonParser(); private TbSendRpcRequestNodeConfiguration config; @Override @@ -67,7 +66,7 @@ public class TbSendRPCRequestNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - JsonObject json = jsonParser.parse(msg.getData()).getAsJsonObject(); + JsonObject json = JsonParser.parseString(msg.getData()).getAsJsonObject(); String tmp; if (msg.getOriginator().getEntityType() != EntityType.DEVICE) { ctx.tellFailure(msg, new RuntimeException("Message originator is not a device entity!")); @@ -117,7 +116,7 @@ public class TbSendRPCRequestNode implements TbNode { ctx.getRpcService().sendRpcRequestToDevice(request, ruleEngineDeviceRpcResponse -> { if (ruleEngineDeviceRpcResponse.getError().isEmpty()) { - TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse("{}")); + TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), ruleEngineDeviceRpcResponse.getResponse().orElse(TbMsg.EMPTY_JSON_OBJECT)); ctx.enqueueForTellNext(next, TbNodeConnectionType.SUCCESS); } else { TbMsg next = ctx.newMsg(msg.getQueueName(), msg.getType(), msg.getOriginator(), msg.getCustomerId(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name())); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java index 5cc5dfe23f..4d1a092097 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java @@ -34,7 +34,6 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.NoSuchElementException; @@ -74,14 +73,7 @@ public class TbChangeOriginatorNode extends TbAbstractTransformNode metaDataMap.remove(key)); + keysToDelete.forEach(metaDataMap::remove); metaData = new TbMsgMetaData(metaDataMap); } else { JsonNode dataNode = JacksonUtil.toJsonNode(msgData); @@ -94,7 +94,7 @@ public class TbDeleteKeysNode implements TbNode { if (keysToDelete.isEmpty()) { ctx.tellSuccess(msg); } else { - ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, msgData)); + ctx.tellSuccess(TbMsg.transformMsg(msg, metaData, msgData)); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java index da7d765a95..0e85a50c34 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbJsonPathNode.java @@ -70,7 +70,7 @@ public class TbJsonPathNode implements TbNode { if (!TbJsonPathNodeConfiguration.DEFAULT_JSON_PATH.equals(this.jsonPathValue)) { try { Object jsonPathData = jsonPath.read(msg.getData(), this.configurationJsonPath); - ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(jsonPathData))); + ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(jsonPathData))); } catch (PathNotFoundException e) { ctx.tellFailure(msg, e); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java index 3fce7494ea..88e6dc1a8b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbRenameKeysNode.java @@ -74,7 +74,7 @@ public class TbRenameKeysNode implements TbNode { } metaData = new TbMsgMetaData(metaDataMap); } else { - JsonNode dataNode = JacksonUtil.toJsonNode(msg.getData()); + JsonNode dataNode = JacksonUtil.toJsonNode(data); if (dataNode.isObject()) { ObjectNode msgData = (ObjectNode) dataNode; for (Map.Entry entry : renameKeysMapping.entrySet()) { @@ -89,7 +89,7 @@ public class TbRenameKeysNode implements TbNode { } } if (msgChanged) { - ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, data)); + ctx.tellSuccess(TbMsg.transformMsg(msg, metaData, data)); } else { ctx.tellSuccess(msg); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java index 1ee7ab7b03..8959d12c9f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNode.java @@ -64,7 +64,7 @@ public class TbSplitArrayMsgNode implements TbNode { if (data.isEmpty()) { ctx.ack(msg); } else if (data.size() == 1) { - ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(data.get(0)))); + ctx.tellSuccess(TbMsg.transformMsgData(msg, JacksonUtil.toString(data.get(0)))); } else { TbMsgCallbackWrapper wrapper = new MultipleTbMsgsCallbackWrapper(data.size(), new TbMsgCallback() { @Override @@ -78,7 +78,7 @@ public class TbSplitArrayMsgNode implements TbNode { } }); data.forEach(msgNode -> { - TbMsg outMsg = TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), JacksonUtil.toString(msgNode)); + TbMsg outMsg = TbMsg.transformMsgData(msg, JacksonUtil.toString(msgNode)); ctx.enqueueForTellNext(outMsg, TbNodeConnectionType.SUCCESS, wrapper::onSuccess, wrapper::onFailure); }); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java index 9173b7143c..33c6071769 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java @@ -34,10 +34,12 @@ import org.thingsboard.rule.engine.api.ScriptEngine; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; import org.thingsboard.server.common.data.alarm.AlarmCreateOrUpdateActiveRequest; import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.DeviceId; @@ -45,6 +47,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; @@ -67,11 +70,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.DataConstants.IS_CLEARED_ALARM; -import static org.thingsboard.server.common.data.DataConstants.IS_EXISTING_ALARM; -import static org.thingsboard.server.common.data.DataConstants.IS_NEW_ALARM; -import static org.thingsboard.server.common.data.alarm.AlarmSeverity.CRITICAL; -import static org.thingsboard.server.common.data.alarm.AlarmSeverity.WARNING; @RunWith(MockitoJUnitRunner.class) public class TbAlarmNodeTest { @@ -108,10 +106,10 @@ public class TbAlarmNodeTest { } @Test - public void newAlarmCanBeCreated() throws ScriptException, IOException { + public void newAlarmCanBeCreated() { initWithCreateAlarmScript(); metaData.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); long ts = msg.getTs(); when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); @@ -121,7 +119,7 @@ public class TbAlarmNodeTest { .endTs(ts) .tenantId(tenantId) .originator(originator) - .severity(CRITICAL) + .severity(AlarmSeverity.CRITICAL) .propagate(true) .type("SomeType") .details(null) @@ -139,16 +137,16 @@ public class TbAlarmNodeTest { verify(ctx).tellNext(any(), eq("Created")); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("ALARM", typeCaptor.getValue()); + assertEquals(TbMsgType.ALARM, typeCaptor.getValue()); assertEquals(originator, originatorCaptor.getValue()); assertEquals("value", metadataCaptor.getValue().getValue("key")); - assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_NEW_ALARM)); + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(DataConstants.IS_NEW_ALARM)); assertNotSame(metaData, metadataCaptor.getValue()); Alarm actualAlarm = JacksonUtil.fromBytes(dataCaptor.getValue().getBytes(), Alarm.class); @@ -156,10 +154,10 @@ public class TbAlarmNodeTest { } @Test - public void buildDetailsThrowsException() throws ScriptException, IOException { + public void buildDetailsThrowsException() { initWithCreateAlarmScript(); metaData.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFailedFuture(new NotImplementedException("message"))); when(alarmService.findLatestActiveByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(null); @@ -179,10 +177,10 @@ public class TbAlarmNodeTest { } @Test - public void ifAlarmClearedCreateNew() throws ScriptException, IOException { + public void ifAlarmClearedCreateNew() { initWithCreateAlarmScript(); metaData.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); long ts = msg.getTs(); Alarm clearedAlarm = Alarm.builder().cleared(true).acknowledged(true).build(); @@ -194,7 +192,7 @@ public class TbAlarmNodeTest { .endTs(ts) .tenantId(tenantId) .originator(originator) - .severity(CRITICAL) + .severity(AlarmSeverity.CRITICAL) .propagate(true) .type("SomeType") .details(null) @@ -213,16 +211,16 @@ public class TbAlarmNodeTest { verify(ctx).tellNext(any(), eq("Created")); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("ALARM", typeCaptor.getValue()); + assertEquals(TbMsgType.ALARM, typeCaptor.getValue()); assertEquals(originator, originatorCaptor.getValue()); assertEquals("value", metadataCaptor.getValue().getValue("key")); - assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_NEW_ALARM)); + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(DataConstants.IS_NEW_ALARM)); assertNotSame(metaData, metadataCaptor.getValue()); @@ -231,13 +229,13 @@ public class TbAlarmNodeTest { } @Test - public void alarmCanBeUpdated() throws IOException { + public void alarmCanBeUpdated() { initWithCreateAlarmScript(); metaData.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); long oldEndDate = System.currentTimeMillis(); - Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).severity(WARNING).endTs(oldEndDate).build(); + Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).severity(AlarmSeverity.WARNING).endTs(oldEndDate).build(); when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestActiveByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(activeAlarm); @@ -245,7 +243,7 @@ public class TbAlarmNodeTest { Alarm expectedAlarm = Alarm.builder() .tenantId(tenantId) .originator(originator) - .severity(CRITICAL) + .severity(AlarmSeverity.CRITICAL) .propagate(true) .type("SomeType") .details(null) @@ -264,16 +262,16 @@ public class TbAlarmNodeTest { verify(ctx).tellNext(any(), eq("Updated")); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("ALARM", typeCaptor.getValue()); + assertEquals(TbMsgType.ALARM, typeCaptor.getValue()); assertEquals(originator, originatorCaptor.getValue()); assertEquals("value", metadataCaptor.getValue().getValue("key")); - assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_EXISTING_ALARM)); + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(DataConstants.IS_EXISTING_ALARM)); assertNotSame(metaData, metadataCaptor.getValue()); Alarm actualAlarm = JacksonUtil.fromBytes(dataCaptor.getValue().getBytes(), Alarm.class); @@ -282,19 +280,19 @@ public class TbAlarmNodeTest { } @Test - public void alarmCanBeCleared() throws ScriptException, IOException { + public void alarmCanBeCleared() { initWithClearAlarmScript(); metaData.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); long oldEndDate = System.currentTimeMillis(); - Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).severity(WARNING).endTs(oldEndDate).build(); + Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).severity(AlarmSeverity.WARNING).endTs(oldEndDate).build(); Alarm expectedAlarm = Alarm.builder() .tenantId(tenantId) .originator(originator) .cleared(true) - .severity(WARNING) + .severity(AlarmSeverity.WARNING) .propagate(false) .type("SomeType") .details(null) @@ -317,16 +315,16 @@ public class TbAlarmNodeTest { verify(ctx).tellNext(any(), eq("Cleared")); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("ALARM", typeCaptor.getValue()); + assertEquals(TbMsgType.ALARM, typeCaptor.getValue()); assertEquals(originator, originatorCaptor.getValue()); assertEquals("value", metadataCaptor.getValue().getValue("key")); - assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_CLEARED_ALARM)); + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(DataConstants.IS_CLEARED_ALARM)); assertNotSame(metaData, metadataCaptor.getValue()); Alarm actualAlarm = JacksonUtil.fromBytes(dataCaptor.getValue().getBytes(), Alarm.class); @@ -337,18 +335,18 @@ public class TbAlarmNodeTest { public void alarmCanBeClearedWithAlarmOriginator() throws ScriptException, IOException { initWithClearAlarmScript(); metaData.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg("USER", alarmOriginator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, alarmOriginator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); long oldEndDate = System.currentTimeMillis(); AlarmId id = new AlarmId(alarmOriginator.getId()); - Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).severity(WARNING).endTs(oldEndDate).build(); + Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).severity(AlarmSeverity.WARNING).endTs(oldEndDate).build(); activeAlarm.setId(id); Alarm expectedAlarm = Alarm.builder() .tenantId(tenantId) .originator(originator) .cleared(true) - .severity(WARNING) + .severity(AlarmSeverity.WARNING) .propagate(false) .type("SomeType") .details(null) @@ -372,16 +370,16 @@ public class TbAlarmNodeTest { verify(ctx).tellNext(any(), eq("Cleared")); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("ALARM", typeCaptor.getValue()); + assertEquals(TbMsgType.ALARM, typeCaptor.getValue()); assertEquals(alarmOriginator, originatorCaptor.getValue()); assertEquals("value", metadataCaptor.getValue().getValue("key")); - assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_CLEARED_ALARM)); + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(DataConstants.IS_CLEARED_ALARM)); assertNotSame(metaData, metadataCaptor.getValue()); Alarm actualAlarm = JacksonUtil.fromBytes(dataCaptor.getValue().getBytes(), Alarm.class); @@ -410,14 +408,14 @@ public class TbAlarmNodeTest { String rawJson = "{\"alarmSeverity\": \"WARNING\", \"passed\": 5}"; metaData.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); long ts = msg.getTs(); Alarm expectedAlarm = Alarm.builder() .startTs(ts) .endTs(ts) .tenantId(tenantId) .originator(originator) - .severity(WARNING) + .severity(AlarmSeverity.WARNING) .propagate(true) .type("SomeType") .details(null) @@ -439,16 +437,16 @@ public class TbAlarmNodeTest { verify(ctx).tellNext(any(), eq("Created")); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("ALARM", typeCaptor.getValue()); + assertEquals(TbMsgType.ALARM, typeCaptor.getValue()); assertEquals(originator, originatorCaptor.getValue()); assertEquals("value", metadataCaptor.getValue().getValue("key")); - assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_NEW_ALARM)); + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(DataConstants.IS_NEW_ALARM)); assertNotSame(metaData, metadataCaptor.getValue()); Alarm actualAlarm = JacksonUtil.fromBytes(dataCaptor.getValue().getBytes(), Alarm.class); @@ -476,14 +474,14 @@ public class TbAlarmNodeTest { node.init(ctx, nodeConfiguration); metaData.putValue("alarmSeverity", "WARNING"); - TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); long ts = msg.getTs(); Alarm expectedAlarm = Alarm.builder() .startTs(ts) .endTs(ts) .tenantId(tenantId) .originator(originator) - .severity(WARNING) + .severity(AlarmSeverity.WARNING) .propagate(true) .type("SomeType") .details(null) @@ -505,15 +503,15 @@ public class TbAlarmNodeTest { verify(ctx).tellNext(any(), eq("Created")); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("ALARM", typeCaptor.getValue()); + assertEquals(TbMsgType.ALARM, typeCaptor.getValue()); assertEquals(originator, originatorCaptor.getValue()); - assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_NEW_ALARM)); + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(DataConstants.IS_NEW_ALARM)); assertNotSame(metaData, metadataCaptor.getValue()); Alarm actualAlarm = JacksonUtil.fromBytes(dataCaptor.getValue().getBytes(), Alarm.class); @@ -525,7 +523,7 @@ public class TbAlarmNodeTest { for (int i = 0; i < 10; i++) { var config = new TbCreateAlarmNodeConfiguration(); config.setPropagateToTenant(true); - config.setSeverity(CRITICAL.name()); + config.setSeverity(AlarmSeverity.CRITICAL.name()); config.setAlarmType("SomeType" + i); config.setScriptLang(ScriptLanguage.JS); config.setAlarmDetailsBuildJs("DETAILS"); @@ -542,14 +540,14 @@ public class TbAlarmNodeTest { node.init(ctx, nodeConfiguration); metaData.putValue("key", "value"); - TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); long ts = msg.getTs(); Alarm expectedAlarm = Alarm.builder() .startTs(ts) .endTs(ts) .tenantId(tenantId) .originator(originator) - .severity(CRITICAL) + .severity(AlarmSeverity.CRITICAL) .propagateToTenant(true) .type("SomeType" + i) .details(null) @@ -570,16 +568,16 @@ public class TbAlarmNodeTest { verify(ctx, atMost(10)).tellNext(any(), eq("Created")); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); verify(ctx, atMost(10)).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("ALARM", typeCaptor.getValue()); + assertEquals(TbMsgType.ALARM, typeCaptor.getValue()); assertEquals(originator, originatorCaptor.getValue()); assertEquals("value", metadataCaptor.getValue().getValue("key")); - assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_NEW_ALARM)); + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(DataConstants.IS_NEW_ALARM)); assertNotSame(metaData, metadataCaptor.getValue()); Alarm actualAlarm = JacksonUtil.fromBytes(dataCaptor.getValue().getBytes(), Alarm.class); @@ -591,7 +589,7 @@ public class TbAlarmNodeTest { try { TbCreateAlarmNodeConfiguration config = new TbCreateAlarmNodeConfiguration(); config.setPropagate(true); - config.setSeverity(CRITICAL.name()); + config.setSeverity(AlarmSeverity.CRITICAL.name()); config.setAlarmType("SomeType"); config.setScriptLang(ScriptLanguage.JS); config.setAlarmDetailsBuildJs("DETAILS"); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java index 542ca75a51..7a9d95cad4 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java @@ -17,7 +17,6 @@ package org.thingsboard.rule.engine.action; import com.datastax.oss.driver.api.core.uuid.Uuids; import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -30,12 +29,14 @@ import org.thingsboard.rule.engine.TestDbCallbackExecutor; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; @@ -47,20 +48,16 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.relation.RelationService; import java.util.Collections; -import java.util.concurrent.Callable; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_CREATED; @RunWith(MockitoJUnitRunner.class) public class TbCreateRelationNodeTest { - private static final String RELATION_TYPE_CONTAINS = "Contains"; - private TbCreateRelationNode node; @Mock @@ -98,11 +95,11 @@ public class TbCreateRelationNodeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("name", "AssetName"); metaData.putValue("type", "AssetType"); - msg = TbMsg.newMsg(ENTITY_CREATED.name(), deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); - when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(EntityRelation.CONTAINS_TYPE), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(false)); - when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, RELATION_TYPE_CONTAINS, RelationTypeGroup.COMMON)))) + when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)))) .thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); @@ -125,15 +122,15 @@ public class TbCreateRelationNodeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("name", "AssetName"); metaData.putValue("type", "AssetType"); - msg = TbMsg.newMsg(ENTITY_CREATED.name(), deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); EntityRelation relation = new EntityRelation(); - when(ctx.getRelationService().findByToAndTypeAsync(any(), eq(msg.getOriginator()), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + when(ctx.getRelationService().findByToAndTypeAsync(any(), eq(msg.getOriginator()), eq(EntityRelation.CONTAINS_TYPE), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(Collections.singletonList(relation))); when(ctx.getRelationService().deleteRelationAsync(any(), eq(relation))).thenReturn(Futures.immediateFuture(true)); - when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(EntityRelation.CONTAINS_TYPE), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(false)); - when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, RELATION_TYPE_CONTAINS, RelationTypeGroup.COMMON)))) + when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)))) .thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); @@ -156,20 +153,17 @@ public class TbCreateRelationNodeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("name", "AssetName"); metaData.putValue("type", "AssetType"); - msg = TbMsg.newMsg(ENTITY_CREATED.name(), deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); - when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(EntityRelation.CONTAINS_TYPE), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(false)); - when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, RELATION_TYPE_CONTAINS, RelationTypeGroup.COMMON)))) + when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)))) .thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); - ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); - ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); - verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); + verify(ctx).transformMsgOriginator(msgCaptor.capture(), originatorCaptor.capture()); assertEquals(assetId, originatorCaptor.getValue()); } @@ -188,9 +182,9 @@ public class TbCreateRelationNodeTest { private TbCreateRelationNodeConfiguration createRelationNodeConfig() { TbCreateRelationNodeConfiguration configuration = new TbCreateRelationNodeConfiguration(); configuration.setDirection(EntitySearchDirection.FROM.name()); - configuration.setRelationType(RELATION_TYPE_CONTAINS); + configuration.setRelationType(EntityRelation.CONTAINS_TYPE); configuration.setEntityCacheExpiration(300); - configuration.setEntityType("ASSET"); + configuration.setEntityType(EntityType.ASSET.name()); configuration.setEntityNamePattern("${name}"); configuration.setEntityTypePattern("${type}"); configuration.setCreateEntityIfNotExists(false); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java index f12288da3a..885002a694 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbLogNodeTest.java @@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -49,7 +50,7 @@ public class TbLogNodeTest { TbLogNode node = new TbLogNode(); String data = "{\"key\": \"value\"}"; TbMsgMetaData metaData = new TbMsgMetaData(Map.of("mdKey1", "mdValue1", "mdKey2", "23")); - TbMsg msg = TbMsg.newMsg("POST_TELEMETRY", TenantId.SYS_TENANT_ID, metaData, data); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, metaData, data); String logMessage = node.toLogMessage(msg); log.info(logMessage); @@ -65,7 +66,7 @@ public class TbLogNodeTest { void givenEmptyDataMsg_whenToLog_thenReturnString() { TbLogNode node = new TbLogNode(); TbMsgMetaData metaData = new TbMsgMetaData(Collections.emptyMap()); - TbMsg msg = TbMsg.newMsg("POST_TELEMETRY", TenantId.SYS_TENANT_ID, metaData, ""); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, metaData, ""); String logMessage = node.toLogMessage(msg); log.info(logMessage); @@ -81,7 +82,7 @@ public class TbLogNodeTest { void givenNullDataMsg_whenToLog_thenReturnString() { TbLogNode node = new TbLogNode(); TbMsgMetaData metaData = new TbMsgMetaData(Collections.emptyMap()); - TbMsg msg = TbMsg.newMsg("POST_TELEMETRY", TenantId.SYS_TENANT_ID, metaData, null); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, TenantId.SYS_TENANT_ID, metaData, null); String logMessage = node.toLogMessage(msg); log.info(logMessage); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java index f44c58e663..0c51462429 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.msg.TbMsg; @@ -48,18 +49,12 @@ import java.util.UUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; -import static org.thingsboard.server.common.data.msg.TbMsgType.CONNECT_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.DISCONNECT_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @RunWith(MockitoJUnitRunner.class) public class TbMsgPushToEdgeNodeTest { - private static final List MISC_EVENTS = List.of(CONNECT_EVENT.name(), DISCONNECT_EVENT.name(), - ACTIVITY_EVENT.name(), INACTIVITY_EVENT.name()); + private static final List MISC_EVENTS = List.of(TbMsgType.CONNECT_EVENT, TbMsgType.DISCONNECT_EVENT, + TbMsgType.ACTIVITY_EVENT, TbMsgType.INACTIVITY_EVENT); TbMsgPushToEdgeNode node; @@ -89,8 +84,8 @@ public class TbMsgPushToEdgeNodeTest { Mockito.when(ctx.getEdgeService()).thenReturn(edgeService); Mockito.when(edgeService.findRelatedEdgeIdsByEntityId(tenantId, deviceId, new PageLink(TbMsgPushToEdgeNode.DEFAULT_PAGE_SIZE))).thenReturn(new PageData<>()); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), - TbMsgDataType.JSON, "{}", null, null); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, + TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, null, null); node.onMsg(ctx, msg); @@ -110,8 +105,8 @@ public class TbMsgPushToEdgeNodeTest { PageData edgePageData = new PageData<>(List.of(edgeId), 1, 1, false); Mockito.when(edgeService.findRelatedEdgeIdsByEntityId(tenantId, userId, new PageLink(TbMsgPushToEdgeNode.DEFAULT_PAGE_SIZE))).thenReturn(edgePageData); - TbMsg msg = TbMsg.newMsg(ATTRIBUTES_UPDATED.name(), userId, new TbMsgMetaData(), - TbMsgDataType.JSON, "{}", null, null); + TbMsg msg = TbMsg.newMsg(TbMsgType.ATTRIBUTES_UPDATED, userId, TbMsgMetaData.EMPTY, + TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, null, null); node.onMsg(ctx, msg); @@ -120,7 +115,7 @@ public class TbMsgPushToEdgeNodeTest { @Test public void testMiscEventsProcessedAsAttributesUpdated() { - for (String event : MISC_EVENTS) { + for (var event : MISC_EVENTS) { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue(DataConstants.SCOPE, DataConstants.SERVER_SCOPE); testEvent(event, metaData, EdgeEventActionType.ATTRIBUTES_UPDATED, "kv"); @@ -129,12 +124,12 @@ public class TbMsgPushToEdgeNodeTest { @Test public void testMiscEventsProcessedAsTimeseriesUpdated() { - for (String event : MISC_EVENTS) { + for (var event : MISC_EVENTS) { testEvent(event, new TbMsgMetaData(), EdgeEventActionType.TIMESERIES_UPDATED, "data"); } } - private void testEvent(String event, TbMsgMetaData metaData, EdgeEventActionType expectedType, String dataKey) { + private void testEvent(TbMsgType event, TbMsgMetaData metaData, EdgeEventActionType expectedType, String dataKey) { Mockito.when(ctx.getTenantId()).thenReturn(tenantId); Mockito.when(ctx.getEdgeService()).thenReturn(edgeService); Mockito.when(ctx.getEdgeEventService()).thenReturn(edgeEventService); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java index 772d278ee8..785be659fd 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -46,7 +47,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; class TbAssetTypeSwitchNodeTest { @@ -118,7 +118,7 @@ class TbAssetTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY, callback); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java index 7bb8365895..a146b95ee1 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckAlarmStatusNodeTest.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -44,7 +45,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; class TbCheckAlarmStatusNodeTest { @@ -159,7 +159,7 @@ class TbCheckAlarmStatusNodeTest { } private TbMsg getTbMsg(String msgData) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, TbMsgMetaData.EMPTY, msgData); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, msgData); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java index 8926f36054..e69cc55d7e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckMessageNodeTest.java @@ -23,7 +23,9 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -38,15 +40,11 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.DataConstants.DEFAULT_DEVICE_TYPE; -import static org.thingsboard.server.common.data.DataConstants.DEVICE_NAME; -import static org.thingsboard.server.common.data.DataConstants.DEVICE_TYPE; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; class TbCheckMessageNodeTest { private static final DeviceId DEVICE_ID = new DeviceId(UUID.randomUUID()); - private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY); + private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); private TbCheckMessageNode node; @@ -193,12 +191,12 @@ class TbCheckMessageNodeTest { } private TbMsg getTbMsg(boolean emptyData) { - String data = emptyData ? TbMsg.EMPTY : "{\"temperature-0\": 25}"; + String data = emptyData ? TbMsg.EMPTY_JSON_OBJECT : "{\"temperature-0\": 25}"; var metadata = new TbMsgMetaData(); - metadata.putValue(DEVICE_NAME, "Test Device"); - metadata.putValue(DEVICE_TYPE, DEFAULT_DEVICE_TYPE); + metadata.putValue(DataConstants.DEVICE_NAME, "Test Device"); + metadata.putValue(DataConstants.DEVICE_TYPE, DataConstants.DEFAULT_DEVICE_TYPE); metadata.putValue("ts", String.valueOf(System.currentTimeMillis())); - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DEVICE_ID, metadata, data); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DEVICE_ID, metadata, data); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java index 926d3b654b..bf7fa31f18 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeTest.java @@ -29,6 +29,7 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; @@ -54,14 +55,13 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; class TbCheckRelationNodeTest { private static final TenantId TENANT_ID = new TenantId(UUID.randomUUID()); private static final DeviceId ORIGINATOR_ID = new DeviceId(UUID.randomUUID()); private static final TestDbCallbackExecutor DB_EXECUTOR = new TestDbCallbackExecutor(); - private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), ORIGINATOR_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY); + private static final TbMsg EMPTY_POST_ATTRIBUTES_MSG = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, ORIGINATOR_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); private TbCheckRelationNode node; diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java index 3fe2e44f5d..a6f4a6e3cf 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -46,7 +47,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; class TbDeviceTypeSwitchNodeTest { @@ -118,6 +118,6 @@ class TbDeviceTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY, callback); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java index 2f75bbfe1b..6ce33fd009 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java @@ -27,10 +27,10 @@ import org.thingsboard.rule.engine.api.ScriptEngine; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.server.common.data.msg.TbNodeConnectionType; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; @@ -59,7 +59,7 @@ public class TbJsFilterNodeTest { @Test public void falseEvaluationDoNotSendMsg() throws TbNodeException { initWithScript(); - TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, new TbMsgMetaData(), TbMsgDataType.JSON, TbMsg.EMPTY, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, new TbMsgMetaData(), TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(false)); node.onMsg(ctx, msg); @@ -71,7 +71,7 @@ public class TbJsFilterNodeTest { public void exceptionInJsThrowsException() throws TbNodeException { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, metaData, TbMsgDataType.JSON, TbMsg.EMPTY, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFailedFuture(new ScriptException("error"))); @@ -83,7 +83,7 @@ public class TbJsFilterNodeTest { public void metadataConditionCanBeTrue() throws TbNodeException { initWithScript(); TbMsgMetaData metaData = new TbMsgMetaData(); - TbMsg msg = TbMsg.newMsg(EntityType.USER.name(), null, metaData, TbMsgDataType.JSON, TbMsg.EMPTY, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(true)); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java index 763af2b1ee..3343c5fb92 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsSwitchNodeTest.java @@ -29,6 +29,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; @@ -58,7 +59,7 @@ public class TbJsSwitchNodeTest { metaData.putValue("humidity", "99"); String rawJson = "{\"name\": \"Vit\", \"passed\": 5}"; - TbMsg msg = TbMsg.newMsg( "USER", null, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); when(scriptEngine.executeSwitchAsync(msg)).thenReturn(Futures.immediateFuture(Sets.newHashSet("one", "three"))); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java index e79e2b77eb..4e2e5dc430 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNodeTest.java @@ -97,7 +97,7 @@ class TbMsgTypeFilterNodeTest { } private TbMsg getTbMsg(EntityId entityId, TbMsgType msgType) { - return TbMsg.newMsg(msgType.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY); + return TbMsg.newMsg(msgType, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java index cd4e21182f..c4fc8cd76d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java @@ -88,7 +88,7 @@ class TbMsgTypeSwitchNodeTest { } private TbMsg getTbMsg(TbMsgType msgType) { - return TbMsg.newMsg(msgType.name(), DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY); + return TbMsg.newMsg(msgType, DEVICE_ID, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java index 852552537f..3ed566b7e6 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNodeTest.java @@ -26,6 +26,7 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -39,7 +40,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; class TbOriginatorTypeFilterNodeTest { @@ -96,7 +96,7 @@ class TbOriginatorTypeFilterNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java index 64eb40fc41..796a7106fc 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNodeTest.java @@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -37,7 +38,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; class TbOriginatorTypeSwitchNodeTest { @@ -90,7 +90,7 @@ class TbOriginatorTypeSwitchNodeTest { } private TbMsg getTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java index 1a01dda8c2..64a239d57f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java @@ -26,6 +26,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -40,9 +41,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.rule.engine.geo.GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER; -import static org.thingsboard.rule.engine.geo.GeoUtilTest.POINT_OUTSIDE_SIMPLE_RECT; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; class TbGpsGeofencingFilterNodeTest { @@ -91,7 +89,7 @@ class TbGpsGeofencingFilterNodeTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, - POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); // WHEN var exception = assertThrows(TbNodeException.class, () -> node.onMsg(ctx, msg)); @@ -109,7 +107,7 @@ class TbGpsGeofencingFilterNodeTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, - POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); // WHEN var exception = assertThrows(TbNodeException.class, () -> node.onMsg(ctx, msg)); @@ -130,7 +128,7 @@ class TbGpsGeofencingFilterNodeTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); TbMsgMetaData metadata = getMetadataForOldVersionPolygonPerimeter(); TbMsg msg = getTbMsg(deviceId, metadata, - POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); // WHEN node.onMsg(ctx, msg); @@ -154,7 +152,7 @@ class TbGpsGeofencingFilterNodeTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); TbMsgMetaData metadata = getMetadataForOldVersionPolygonPerimeter(); TbMsg msg = getTbMsg(deviceId, metadata, - POINT_OUTSIDE_SIMPLE_RECT.getLatitude(), POINT_OUTSIDE_SIMPLE_RECT.getLongitude()); + GeoUtilTest.POINT_OUTSIDE_SIMPLE_RECT.getLatitude(), GeoUtilTest.POINT_OUTSIDE_SIMPLE_RECT.getLongitude()); // WHEN node.onMsg(ctx, msg); @@ -177,7 +175,7 @@ class TbGpsGeofencingFilterNodeTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); TbMsgMetaData metadata = getMetadataForNewVersionPolygonPerimeter(); TbMsg msg = getTbMsg(deviceId, metadata, - POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); // WHEN node.onMsg(ctx, msg); @@ -200,7 +198,7 @@ class TbGpsGeofencingFilterNodeTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); TbMsgMetaData metadata = getMetadataForNewVersionPolygonPerimeter(); TbMsg msg = getTbMsg(deviceId, metadata, - POINT_OUTSIDE_SIMPLE_RECT.getLatitude(), POINT_OUTSIDE_SIMPLE_RECT.getLongitude()); + GeoUtilTest.POINT_OUTSIDE_SIMPLE_RECT.getLatitude(), GeoUtilTest.POINT_OUTSIDE_SIMPLE_RECT.getLongitude()); // WHEN node.onMsg(ctx, msg); @@ -224,7 +222,7 @@ class TbGpsGeofencingFilterNodeTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, - POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); + GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLatitude(), GeoUtilTest.POINT_INSIDE_SIMPLE_RECT_CENTER.getLongitude()); // WHEN node.onMsg(ctx, msg); @@ -248,7 +246,7 @@ class TbGpsGeofencingFilterNodeTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); TbMsg msg = getTbMsg(deviceId, TbMsgMetaData.EMPTY, - POINT_OUTSIDE_SIMPLE_RECT.getLatitude(), POINT_OUTSIDE_SIMPLE_RECT.getLongitude()); + GeoUtilTest.POINT_OUTSIDE_SIMPLE_RECT.getLatitude(), GeoUtilTest.POINT_OUTSIDE_SIMPLE_RECT.getLongitude()); // WHEN node.onMsg(ctx, msg); @@ -450,11 +448,11 @@ class TbGpsGeofencingFilterNodeTest { private TbMsg getTbMsg(EntityId entityId, TbMsgMetaData metadata, double latitude, double longitude) { String data = "{\"latitude\": " + latitude + ", \"longitude\": " + longitude + "}"; - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, metadata, data); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, metadata, data); } private TbMsg getEmptyArrayTbMsg(EntityId entityId) { - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, TbMsgMetaData.EMPTY, "[]"); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, "[]"); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java index c95183717f..bf4d090c1c 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeTest.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -56,26 +57,26 @@ public class TbMsgToEmailNodeTest { private RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); @Test - public void msgCanBeConverted() throws IOException { + public void msgCanBeConverted() { initWithScript(); metaData.putValue("username", "oreo"); metaData.putValue("userEmail", "user@email.io"); metaData.putValue("name", "temp"); metaData.putValue("passed", "5"); metaData.putValue("count", "100"); - TbMsg msg = TbMsg.newMsg( "USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); emailNode.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(TbMsgType.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("SEND_EMAIL", typeCaptor.getValue()); + assertEquals(TbMsgType.SEND_EMAIL, typeCaptor.getValue()); assertEquals(originator, originatorCaptor.getValue()); assertEquals("oreo", metadataCaptor.getValue().getValue("username")); assertNotSame(metaData, metadataCaptor.getValue()); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java index 2efc438f8f..3e19c7a736 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java @@ -45,6 +45,7 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.DoubleDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.attributes.AttributesService; @@ -149,7 +150,7 @@ public class TbMathNodeTest { metaData.putValue("key2", "argumentA"); ObjectNode msgNode = JacksonUtil.newObjectNode() .put("key3", "argumentB").put("argumentA", 2).put("argumentB", 2); - TbMsg msg = TbMsg.newMsg("TEST", originator, metaData, msgNode.toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, msgNode.toString()); node.onMsg(ctx, msg); @@ -162,7 +163,7 @@ public class TbMathNodeTest { metaData.putValue("key2", "argumentC"); msgNode = JacksonUtil.newObjectNode() .put("key3", "argumentD").put("argumentC", 4).put("argumentD", 3); - msg = TbMsg.newMsg("TEST", originator, metaData, msgNode.toString()); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, msgNode.toString()); node.onMsg(ctx, msg); @@ -246,7 +247,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", arg1).put("b", arg2).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", arg1).put("b", arg2).toString()); node.onMsg(ctx, msg); @@ -269,7 +270,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", arg1).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", arg1).toString()); node.onMsg(ctx, msg); @@ -292,7 +293,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); node.onMsg(ctx, msg); @@ -315,7 +316,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); node.onMsg(ctx, msg); @@ -339,7 +340,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.TIME_SERIES, "b") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().toString()); Mockito.when(attributesService.find(tenantId, originator, DataConstants.SERVER_SCOPE, "a")) .thenReturn(Futures.immediateFuture(Optional.of(new BaseAttributeKvEntry(System.currentTimeMillis(), new DoubleDataEntry("a", 2.0))))); @@ -367,7 +368,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); node.onMsg(ctx, msg); @@ -389,7 +390,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); node.onMsg(ctx, msg); @@ -411,7 +412,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); Mockito.when(telemetryService.saveAttrAndNotify(any(), any(), anyString(), anyString(), anyDouble())) .thenReturn(Futures.immediateFuture(null)); @@ -437,7 +438,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); Mockito.when(telemetryService.saveAndNotify(any(), any(), any(TsKvEntry.class))) .thenReturn(Futures.immediateFuture(null)); @@ -462,7 +463,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); Mockito.when(telemetryService.saveAndNotify(any(), any(), any(TsKvEntry.class))) .thenReturn(Futures.immediateFuture(null)); @@ -493,7 +494,7 @@ public class TbMathNodeTest { new TbMathResult(TbMathArgumentType.MESSAGE_METADATA, "result", 3, false, false, null), tbMathArgument ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 10).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 10).toString()); node.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); @@ -513,7 +514,7 @@ public class TbMathNodeTest { new TbMathResult(TbMathArgumentType.TIME_SERIES, "result", 3, true, false, DataConstants.SERVER_SCOPE), new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "TestKey") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 10).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 10).toString()); Throwable thrown = assertThrows(RuntimeException.class, () -> { node.onMsg(ctx, msg); }); @@ -527,7 +528,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), "[]"); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), "[]"); Throwable thrown = assertThrows(RuntimeException.class, () -> { node.onMsg(ctx, msg); }); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java index 6182d8cca5..9dbae201ac 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java @@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -63,8 +64,6 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @ExtendWith(MockitoExtension.class) public class CalculateDeltaNodeTest { @@ -104,7 +103,7 @@ public class CalculateDeltaNodeTest { public void givenInvalidMsgType_whenOnMsg_thenShouldTellNextOther() { // GIVEN var msgData = "{\"pulseCounter\": 42}"; - var msg = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN node.onMsg(ctxMock, msg); @@ -119,7 +118,7 @@ public class CalculateDeltaNodeTest { public void givenInvalidMsgDataType_whenOnMsg_thenShouldTellNextOther() { // GIVEN var msgData = "[]"; - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN node.onMsg(ctxMock, msg); @@ -134,7 +133,7 @@ public class CalculateDeltaNodeTest { @Test public void givenInputKeyIsNotPresent_whenOnMsg_thenShouldTellNextOther() { // GIVEN - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "{}"); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); // WHEN node.onMsg(ctxMock, msg); @@ -158,7 +157,7 @@ public class CalculateDeltaNodeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry("temperature", 40.5))); var msgData = "{\"temperature\": 42,\"airPressure\":123}"; - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN node.onMsg(ctxMock, msg); @@ -188,7 +187,7 @@ public class CalculateDeltaNodeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry("temperature", 40L))); var msgData = "{\"temperature\": 42,\"airPressure\":123}"; - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN node.onMsg(ctxMock, msg); @@ -218,7 +217,7 @@ public class CalculateDeltaNodeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry("temperature", "40.0"))); var msgData = "{\"temperature\": 42,\"airPressure\":123}"; - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN node.onMsg(ctxMock, msg); @@ -252,7 +251,7 @@ public class CalculateDeltaNodeTest { var msgData = "{\"temperature\": 42,\"airPressure\":123}"; var firstMsgMetaData = new TbMsgMetaData(); firstMsgMetaData.putValue("ts", String.valueOf(3L)); - var firstMsg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, firstMsgMetaData, msgData); + var firstMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, firstMsgMetaData, msgData); // WHEN node.onMsg(ctxMock, firstMsg); @@ -276,7 +275,7 @@ public class CalculateDeltaNodeTest { var secondMsgMetaData = new TbMsgMetaData(); secondMsgMetaData.putValue("ts", String.valueOf(6L)); - var secondMsg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, secondMsgMetaData, msgData); + var secondMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, secondMsgMetaData, msgData); // WHEN node.onMsg(ctxMock, secondMsg); @@ -307,7 +306,7 @@ public class CalculateDeltaNodeTest { mockFindLatestAsync(new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry("temperature", null))); var msgData = "{\"temperature\": 42,\"airPressure\":123}"; - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN node.onMsg(ctxMock, msg); @@ -335,7 +334,7 @@ public class CalculateDeltaNodeTest { mockFindLatest(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry("pulseCounter", 200L))); var msgData = "{\"pulseCounter\":\"123\"}"; - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN node.onMsg(ctxMock, msg); @@ -364,7 +363,7 @@ public class CalculateDeltaNodeTest { mockFindLatest(new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry("pulseCounter", "high"))); var msgData = "{\"pulseCounter\":\"123\"}"; - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN-THEN Assertions.assertThatThrownBy(() -> node.onMsg(ctxMock, msg)) @@ -378,7 +377,7 @@ public class CalculateDeltaNodeTest { mockFindLatest(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry("pulseCounter", false))); var msgData = "{\"pulseCounter\":true}"; - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN-THEN Assertions.assertThatThrownBy(() -> node.onMsg(ctxMock, msg)) @@ -392,7 +391,7 @@ public class CalculateDeltaNodeTest { mockFindLatest(new BasicTsKvEntry(System.currentTimeMillis(), new JsonDataEntry("pulseCounter", "{\"isActive\":false}"))); var msgData = "{\"pulseCounter\":{\"isActive\":true}}"; - var msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); // WHEN-THEN Assertions.assertThatThrownBy(() -> node.onMsg(ctxMock, msg)) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java index dfd054edc7..5de25ebfc2 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java @@ -31,7 +31,9 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -51,8 +53,6 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; -import static org.thingsboard.server.common.data.security.DeviceCredentialsType.ACCESS_TOKEN; @ExtendWith(MockitoExtension.class) public class TbFetchDeviceCredentialsNodeTest { @@ -98,7 +98,7 @@ public class TbFetchDeviceCredentialsNodeTest { doReturn(deviceCredentialsServiceMock).when(ctxMock).getDeviceCredentialsService(); doAnswer(invocation -> { DeviceCredentials deviceCredentials = new DeviceCredentials(); - deviceCredentials.setCredentialsType(ACCESS_TOKEN); + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); return deviceCredentials; }).when(deviceCredentialsServiceMock).findDeviceCredentialsByDeviceId(any(), any()); doAnswer(invocation -> JacksonUtil.newObjectNode()).when(deviceCredentialsServiceMock).toCredentialsInfo(any()); @@ -172,7 +172,7 @@ public class TbFetchDeviceCredentialsNodeTest { final var metaData = new TbMsgMetaData(mdMap); final String data = "{\"TestAttribute_1\": \"humidity\", \"TestAttribute_2\": \"voltage\"}"; - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, metaData, data, callbackMock); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, metaData, data, callbackMock); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java index cb36982b20..a889f91b77 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java @@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -240,7 +241,7 @@ public class TbGetAttributesNodeTest { public void givenFetchLatestTimeseriesToDataAndDataIsNotJsonObject_whenOnMsg_thenException() throws Exception { // GIVEN node = initNode(FetchTo.DATA, true, true); - var msg = TbMsg.newMsg("TEST", ORIGINATOR, new TbMsgMetaData(), "[]"); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -369,7 +370,7 @@ public class TbGetAttributesNodeTest { msgMetaData.putValue("client_attr_metadata", "client_attr_3"); msgMetaData.putValue("server_attr_metadata", "server_attr_3"); - return TbMsg.newMsg("TEST", entityId, msgMetaData, JacksonUtil.toString(msgData)); + return TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, entityId, msgMetaData, JacksonUtil.toString(msgData)); } private List getAttributeNames(String prefix) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 12385f6e28..3a8f36f5dc 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -33,6 +33,7 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.asset.Asset; @@ -47,6 +48,7 @@ import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -74,8 +76,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @ExtendWith(MockitoExtension.class) public class TbGetCustomerAttributeNodeTest { @@ -208,7 +208,7 @@ public class TbGetCustomerAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -223,7 +223,7 @@ public class TbGetCustomerAttributeNodeTest { // GIVEN var userId = new UserId(UUID.randomUUID()); - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), userId, new TbMsgMetaData(), "{}"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, userId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); when(ctxMock.getTenantId()).thenReturn(TENANT_ID); @@ -276,7 +276,7 @@ public class TbGetCustomerAttributeNodeTest { doReturn(device).when(deviceServiceMock).findDeviceById(eq(TENANT_ID), eq(device.getId())); when(ctxMock.getAttributesService()).thenReturn(attributesServiceMock); - when(attributesServiceMock.find(eq(TENANT_ID), eq(CUSTOMER_ID), eq(SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) + when(attributesServiceMock.find(eq(TENANT_ID), eq(CUSTOMER_ID), eq(DataConstants.SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) .thenReturn(Futures.immediateFuture(attributesList)); when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); @@ -323,7 +323,7 @@ public class TbGetCustomerAttributeNodeTest { doReturn(Futures.immediateFuture(user)).when(userServiceMock).findUserByIdAsync(eq(TENANT_ID), eq(user.getId())); when(ctxMock.getAttributesService()).thenReturn(attributesServiceMock); - when(attributesServiceMock.find(eq(TENANT_ID), eq(CUSTOMER_ID), eq(SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) + when(attributesServiceMock.find(eq(TENANT_ID), eq(CUSTOMER_ID), eq(DataConstants.SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) .thenReturn(Futures.immediateFuture(attributesList)); when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); @@ -467,7 +467,7 @@ public class TbGetCustomerAttributeNodeTest { var msgData = "{\"temp\":42,\"humidity\":77,\"messageBodyPattern1\":\"targetKey2\",\"messageBodyPattern2\":\"sourceKey3\"}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), originator, msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, msgMetaData, msgData); } @RequiredArgsConstructor diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java index 540a260338..8b958bcc3c 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java @@ -45,6 +45,7 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -68,7 +69,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @ExtendWith(MockitoExtension.class) public class TbGetCustomerDetailsNodeTest { @@ -157,7 +157,7 @@ public class TbGetCustomerDetailsNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg("SOME_MESSAGE_TYPE", DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -456,7 +456,7 @@ public class TbGetCustomerDetailsNodeTest { var msgData = "{\"dataKey1\":123,\"dataKey2\":\"dataValue2\"}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), originator, msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, msgMetaData, msgData); } private void mockFindCustomer() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java index addd05bd0e..0057ec7c61 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java @@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -51,7 +52,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @ExtendWith(MockitoExtension.class) public class TbGetOriginatorFieldsNodeTest { @@ -133,7 +133,7 @@ public class TbGetOriginatorFieldsNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg("SOME_MESSAGE_TYPE", DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -162,7 +162,7 @@ public class TbGetOriginatorFieldsNodeTest { node.fetchTo = FetchTo.DATA; var msgMetaData = new TbMsgMetaData(); var msgData = "{\"temp\":42,\"humidity\":77}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -204,7 +204,7 @@ public class TbGetOriginatorFieldsNodeTest { node.fetchTo = FetchTo.DATA; var msgMetaData = new TbMsgMetaData(); var msgData = "{\"temp\":42,\"humidity\":77}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -247,7 +247,7 @@ public class TbGetOriginatorFieldsNodeTest { "testKey1", "testValue1", "testKey2", "123")); var msgData = "[\"value1\",\"value2\"]"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -295,7 +295,7 @@ public class TbGetOriginatorFieldsNodeTest { "testKey1", "testValue1", "testKey2", "123")); var msgData = "[\"value1\",\"value2\"]"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); when(ctxMock.getDeviceService()).thenReturn(deviceServiceMock); when(ctxMock.getTenantId()).thenReturn(DUMMY_TENANT_ID); @@ -353,7 +353,7 @@ public class TbGetOriginatorFieldsNodeTest { "testKey1", "testValue1", "testKey2", "123")); var msgData = "[\"value1\",\"value2\"]"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), new DashboardId(UUID.randomUUID()), msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, new DashboardId(UUID.randomUUID()), msgMetaData, msgData); when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index 1a638eca39..6b3a225eac 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -35,6 +35,7 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.data.RelationsQuery; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; @@ -53,6 +54,7 @@ import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; @@ -83,8 +85,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @ExtendWith(MockitoExtension.class) public class TbGetRelatedAttributeNodeTest { @@ -222,7 +222,7 @@ public class TbGetRelatedAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -290,7 +290,7 @@ public class TbGetRelatedAttributeNodeTest { doReturn(Futures.immediateFuture(List.of(entityRelation))).when(relationServiceMock).findByQuery(eq(TENANT_ID), any()); when(ctxMock.getAttributesService()).thenReturn(attributesServiceMock); - when(attributesServiceMock.find(eq(TENANT_ID), eq(user.getId()), eq(SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) + when(attributesServiceMock.find(eq(TENANT_ID), eq(user.getId()), eq(DataConstants.SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) .thenReturn(Futures.immediateFuture(attributes)); when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); @@ -341,7 +341,7 @@ public class TbGetRelatedAttributeNodeTest { doReturn(Futures.immediateFuture(List.of(entityRelation))).when(relationServiceMock).findByQuery(eq(TENANT_ID), any()); when(ctxMock.getAttributesService()).thenReturn(attributesServiceMock); - when(attributesServiceMock.find(eq(TENANT_ID), eq(secondCustomer.getId()), eq(SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) + when(attributesServiceMock.find(eq(TENANT_ID), eq(secondCustomer.getId()), eq(DataConstants.SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) .thenReturn(Futures.immediateFuture(attributes)); when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); @@ -591,7 +591,7 @@ public class TbGetRelatedAttributeNodeTest { msgData = "{\"temp\":42,\"humidity\":77,\"messageBodyPattern1\":\"targetKey2\",\"messageBodyPattern2\":\"sourceKey3\"}"; } - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), originator, msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, msgMetaData, msgData); } @RequiredArgsConstructor diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index c163d68733..ffb053c93a 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -31,6 +31,7 @@ import org.thingsboard.rule.engine.TestDbCallbackExecutor; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; @@ -41,6 +42,7 @@ import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -61,8 +63,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @ExtendWith(MockitoExtension.class) public class TbGetTenantAttributeNodeTest { @@ -188,7 +188,7 @@ public class TbGetTenantAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -215,7 +215,7 @@ public class TbGetTenantAttributeNodeTest { when(ctxMock.getTenantId()).thenReturn(TENANT_ID); when(ctxMock.getAttributesService()).thenReturn(attributesServiceMock); - when(attributesServiceMock.find(eq(TENANT_ID), eq(TENANT_ID), eq(SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) + when(attributesServiceMock.find(eq(TENANT_ID), eq(TENANT_ID), eq(DataConstants.SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) .thenReturn(Futures.immediateFuture(attributesList)); when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); @@ -256,7 +256,7 @@ public class TbGetTenantAttributeNodeTest { when(ctxMock.getTenantId()).thenReturn(TENANT_ID); when(ctxMock.getAttributesService()).thenReturn(attributesServiceMock); - when(attributesServiceMock.find(eq(TENANT_ID), eq(TENANT_ID), eq(SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) + when(attributesServiceMock.find(eq(TENANT_ID), eq(TENANT_ID), eq(DataConstants.SERVER_SCOPE), argThat(new ListMatcher<>(expectedPatternProcessedKeysList)))) .thenReturn(Futures.immediateFuture(attributesList)); when(ctxMock.getDbCallbackExecutor()).thenReturn(DB_EXECUTOR); @@ -396,7 +396,7 @@ public class TbGetTenantAttributeNodeTest { var msgData = "{\"temp\":42,\"humidity\":77,\"messageBodyPattern1\":\"targetKey2\",\"messageBodyPattern2\":\"sourceKey3\"}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), originator, msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, msgMetaData, msgData); } @RequiredArgsConstructor diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java index 430a772269..2dda9ffaf0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java @@ -32,6 +32,7 @@ import org.thingsboard.rule.engine.util.ContactBasedEntityDetails; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -49,7 +50,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @ExtendWith(MockitoExtension.class) public class TbGetTenantDetailsNodeTest { @@ -127,7 +127,7 @@ public class TbGetTenantDetailsNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg("SOME_MESSAGE_TYPE", DUMMY_DEVICE_ORIGINATOR, new TbMsgMetaData(), "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); @@ -287,7 +287,7 @@ public class TbGetTenantDetailsNodeTest { var msgData = "{\"dataKey1\":123,\"dataKey2\":\"dataValue2\"}"; - msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, msgMetaData, msgData); } private void mockFindTenant() { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java index 0d94d9de16..6bc4a59610 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.query.BooleanFilterPredicate; import org.thingsboard.server.common.data.query.EntityKeyValueType; import org.thingsboard.server.common.data.query.FilterPredicateValue; @@ -62,10 +63,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_CLEAR; -import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE; -import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; public class DeviceStateTest { @@ -94,9 +91,10 @@ public class DeviceStateTest { }); when(ctx.getAlarmService()).thenReturn(alarmService); - when(ctx.newMsg(any(), any(), any(), any(), any(), any())).thenAnswer(invocationOnMock -> { + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), any())).thenAnswer(invocationOnMock -> { + TbMsgType type = invocationOnMock.getArgument(1); String data = invocationOnMock.getArgument(invocationOnMock.getArguments().length - 1); - return TbMsg.newMsg(null, null, new TbMsgMetaData(), data); + return TbMsg.newMsg(type, null, TbMsgMetaData.EMPTY, data); }); } @@ -108,7 +106,7 @@ public class DeviceStateTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); DeviceState deviceState = createDeviceState(deviceId, alarmConfig); - TbMsg attributeUpdateMsg = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), + TbMsg attributeUpdateMsg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, deviceId, new TbMsgMetaData(), "{ \"enabled\": false }"); deviceState.process(ctx, attributeUpdateMsg); @@ -117,11 +115,11 @@ public class DeviceStateTest { verify(ctx).enqueueForTellNext(resultMsgCaptor.capture(), eq("Alarm Created")); Alarm alarm = JacksonUtil.fromString(resultMsgCaptor.getValue().getData(), Alarm.class); - deviceState.process(ctx, TbMsg.newMsg(ALARM_CLEAR.name(), deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm))); + deviceState.process(ctx, TbMsg.newMsg(TbMsgType.ALARM_CLEAR, deviceId, TbMsgMetaData.EMPTY, JacksonUtil.toString(alarm))); reset(ctx); String deletedAttributes = "{ \"attributes\": [ \"other\" ] }"; - deviceState.process(ctx, TbMsg.newMsg(ATTRIBUTES_DELETED.name(), deviceId, new TbMsgMetaData(), deletedAttributes)); + deviceState.process(ctx, TbMsg.newMsg(TbMsgType.ATTRIBUTES_DELETED, deviceId, new TbMsgMetaData(), deletedAttributes)); verify(ctx, never()).enqueueForTellNext(any(), anyString()); } @@ -131,17 +129,17 @@ public class DeviceStateTest { DeviceId deviceId = new DeviceId(UUID.randomUUID()); DeviceState deviceState = createDeviceState(deviceId, alarmConfig); - TbMsg attributeUpdateMsg = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), - deviceId, new TbMsgMetaData(), "{ \"enabled\": false }"); + TbMsg attributeUpdateMsg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, + deviceId, TbMsgMetaData.EMPTY, "{ \"enabled\": false }"); deviceState.process(ctx, attributeUpdateMsg); ArgumentCaptor resultMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx).enqueueForTellNext(resultMsgCaptor.capture(), eq("Alarm Created")); Alarm alarm = JacksonUtil.fromString(resultMsgCaptor.getValue().getData(), Alarm.class); - deviceState.process(ctx, TbMsg.newMsg(ALARM_CLEAR.name(), deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm))); + deviceState.process(ctx, TbMsg.newMsg(TbMsgType.ALARM_CLEAR, deviceId, TbMsgMetaData.EMPTY, JacksonUtil.toString(alarm))); - TbMsg alarmDeleteNotification = TbMsg.newMsg(ALARM_DELETE.name(), deviceId, new TbMsgMetaData(), JacksonUtil.toString(alarm)); + TbMsg alarmDeleteNotification = TbMsg.newMsg(TbMsgType.ALARM_DELETE, deviceId, TbMsgMetaData.EMPTY, JacksonUtil.toString(alarm)); assertDoesNotThrow(() -> { deviceState.process(ctx, alarmDeleteNotification); }); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java index 20c529646c..03a9c17a60 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeTest.java @@ -54,6 +54,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.query.BooleanFilterPredicate; import org.thingsboard.server.common.data.query.DynamicValue; import org.thingsboard.server.common.data.query.DynamicValueSourceType; @@ -85,7 +86,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @RunWith(MockitoJUnitRunner.class) public class TbDeviceProfileNodeTest { @@ -122,8 +122,8 @@ public class TbDeviceProfileNodeTest { Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 42); - TbMsg msg = TbMsg.newMsg("123456789", deviceId, new TbMsgMetaData(), - TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + TbMsg msg = TbMsg.newMsg("123456789", deviceId, TbMsgMetaData.EMPTY, + TbMsgDataType.JSON, JacksonUtil.toString(data)); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); @@ -141,7 +141,7 @@ public class TbDeviceProfileNodeTest { Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 42); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); @@ -193,25 +193,25 @@ public class TbDeviceProfileNodeTest { Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm")).thenReturn(null); registerCreateAlarmMock(alarmService.createAlarm(any()), true); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg); + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())).thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 42); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); verify(ctx).tellSuccess(msg); verify(ctx).enqueueForTellNext(theMsg, "Alarm Created"); verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); - TbMsg theMsg2 = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), "2"); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())).thenReturn(theMsg2); + TbMsg theMsg2 = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, "2"); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())).thenReturn(theMsg2); registerCreateAlarmMock(alarmService.updateAlarm(any()), false); - TbMsg msg2 = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg2); verify(ctx).tellSuccess(msg2); @@ -286,13 +286,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(attrListListenableFuture); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + Mockito.when(ctx.newMsg(Mockito.any(), Mockito.any(TbMsgType.class), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 21); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -373,13 +373,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), Mockito.anyString(), Mockito.anyString())) .thenReturn(attrListListenableFuture); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 21); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -442,13 +442,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(listListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -536,13 +536,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(listListenableFuture); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -557,7 +557,7 @@ public class TbDeviceProfileNodeTest { Thread.sleep(halfOfAlarmDelay); - TbMsg msg2 = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg2); @@ -660,13 +660,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(listNoDurationAttribute); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -681,7 +681,7 @@ public class TbDeviceProfileNodeTest { Thread.sleep(halfOfAlarmDelay); - TbMsg msg2 = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg2); @@ -769,13 +769,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(listListenableFuture); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -784,7 +784,7 @@ public class TbDeviceProfileNodeTest { verify(ctx, Mockito.never()).tellNext(theMsg, "Alarm Created"); data.put("temperature", 151); - TbMsg msg2 = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg2); @@ -885,13 +885,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(listNoDurationAttribute); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -900,7 +900,7 @@ public class TbDeviceProfileNodeTest { verify(ctx, Mockito.never()).tellNext(theMsg, "Alarm Created"); data.put("temperature", 151); - TbMsg msg2 = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg2); @@ -981,13 +981,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(listListenableFuture); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -1002,7 +1002,7 @@ public class TbDeviceProfileNodeTest { Thread.sleep(halfOfAlarmDelay); - TbMsg msg2 = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg2); @@ -1079,13 +1079,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(listListenableFuture); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -1161,13 +1161,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(listListenableFutureActiveSchedule); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); // Mockito.reset(ctx); @@ -1257,11 +1257,11 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(deviceId), Mockito.anyString(), Mockito.anySet())) .thenReturn(listListenableFutureInactiveSchedule); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 35); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -1335,13 +1335,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(customerId), eq(DataConstants.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 25); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -1408,13 +1408,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(DataConstants.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 40); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -1491,13 +1491,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(DataConstants.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150L); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); @@ -1576,13 +1576,13 @@ public class TbDeviceProfileNodeTest { Mockito.when(attributesService.find(eq(tenantId), eq(tenantId), eq(DataConstants.SERVER_SCOPE), Mockito.anyString())) .thenReturn(optionalListenableFutureWithLess); - TbMsg theMsg = TbMsg.newMsg("ALARM", deviceId, new TbMsgMetaData(), ""); - Mockito.when(ctx.newMsg(Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyString())) + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())) .thenReturn(theMsg); ObjectNode data = JacksonUtil.newObjectNode(); data.put("temperature", 150L); - TbMsg msg = TbMsg.newMsg(POST_TELEMETRY_REQUEST.name(), deviceId, new TbMsgMetaData(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java index 7b6a54ae0b..2ddc20d5ed 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java @@ -32,6 +32,7 @@ import org.springframework.web.client.AsyncRestTemplate; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -144,16 +145,15 @@ public class TbHttpClientTest { var httpClient = new TbHttpClient(config, eventLoop); httpClient.setHttpClient(asyncRestTemplate); - var msg = TbMsg.newMsg("GET", new DeviceId(EntityId.NULL_UUID), TbMsgMetaData.EMPTY, "{}"); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, new DeviceId(EntityId.NULL_UUID), TbMsgMetaData.EMPTY, "{}"); var successMsg = TbMsg.newMsg( - "SUCCESS", msg.getOriginator(), + TbMsgType.POST_TELEMETRY_REQUEST, msg.getOriginator(), msg.getMetaData(), msg.getData() ); var ctx = mock(TbContext.class); when(ctx.transformMsg( - eq(msg), eq(msg.getType()), - eq(msg.getOriginator()), + eq(msg), eq(msg.getMetaData()), eq(msg.getData()) )).thenReturn(successMsg); @@ -161,15 +161,14 @@ public class TbHttpClientTest { var capturedData = ArgumentCaptor.forClass(String.class); when(ctx.transformMsg( - eq(msg), eq(msg.getType()), - eq(msg.getOriginator()), + eq(msg), any(), capturedData.capture() )).thenReturn(successMsg); httpClient.processMessage(ctx, msg, m -> ctx.tellSuccess(msg), - (m, t) -> ctx.tellFailure(m, t)); + ctx::tellFailure); Awaitility.await() .atMost(30, TimeUnit.SECONDS) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java index 9185a31118..705f298513 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbRestApiCallNodeTest.java @@ -16,7 +16,6 @@ package org.thingsboard.rule.engine.rest; import com.datastax.oss.driver.api.core.uuid.Uuids; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; @@ -39,6 +38,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -136,23 +136,18 @@ public class TbRestApiCallNodeTest { config.setRestEndpointUrlPattern(String.format("http://localhost:%d%s", server.getLocalPort(), path)); initWithConfig(config); - TbMsg msg = TbMsg.newMsg( "USER", originator, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); restNode.onMsg(ctx, msg); assertTrue("Server handled request", latch.await(10, TimeUnit.SECONDS)); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); - verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); + verify(ctx).transformMsg(msgCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - - assertEquals("USER", typeCaptor.getValue()); - assertEquals(originator, originatorCaptor.getValue()); assertNotSame(metaData, metadataCaptor.getValue()); - assertEquals("{}", dataCaptor.getValue()); + assertEquals(TbMsg.EMPTY_JSON_OBJECT, dataCaptor.getValue()); } @Test @@ -202,22 +197,18 @@ public class TbRestApiCallNodeTest { config.setRestEndpointUrlPattern(String.format("http://localhost:%d%s", server.getLocalPort(), path)); initWithConfig(config); - TbMsg msg = TbMsg.newMsg( "USER", originator, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); restNode.onMsg(ctx, msg); assertTrue("Server handled request", latch.await(10, TimeUnit.SECONDS)); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); - ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); - verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); + verify(ctx).transformMsg(msgCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); - assertEquals("USER", typeCaptor.getValue()); - assertEquals(originator, originatorCaptor.getValue()); assertNotSame(metaData, metadataCaptor.getValue()); - assertEquals("{}", dataCaptor.getValue()); + assertEquals(TbMsg.EMPTY_JSON_OBJECT, dataCaptor.getValue()); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNodeTest.java index a72d343d10..7b12dbb2b1 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNodeTest.java @@ -80,7 +80,7 @@ public class TbSendRPCReplyNodeTest { Mockito.when(ctx.getRpcService()).thenReturn(rpcService); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, getDefaultMetadata(), + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, getDefaultMetadata(), TbMsgDataType.JSON, DUMMY_DATA, null, null); node.onMsg(ctx, msg); @@ -99,7 +99,7 @@ public class TbSendRPCReplyNodeTest { TbMsgMetaData defaultMetadata = getDefaultMetadata(); defaultMetadata.putValue(DataConstants.EDGE_ID, UUID.randomUUID().toString()); defaultMetadata.putValue(DataConstants.DEVICE_ID, UUID.randomUUID().toString()); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, defaultMetadata, + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, defaultMetadata, TbMsgDataType.JSON, DUMMY_DATA, null, null); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNodeTest.java index 9b23a3aa31..632243676f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/telemetry/TbMsgDeleteAttributesNodeTest.java @@ -25,7 +25,9 @@ import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -49,11 +51,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.DataConstants.NOTIFY_DEVICE_METADATA_KEY; -import static org.thingsboard.server.common.data.DataConstants.SCOPE; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; -import static org.thingsboard.server.common.data.DataConstants.SHARED_SCOPE; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; @Slf4j public class TbMsgDeleteAttributesNodeTest { @@ -95,7 +92,7 @@ public class TbMsgDeleteAttributesNodeTest { @Test void givenDefaultConfig_whenVerify_thenOK() { TbMsgDeleteAttributesNodeConfiguration defaultConfig = new TbMsgDeleteAttributesNodeConfiguration().defaultConfiguration(); - assertThat(defaultConfig.getScope()).isEqualTo(SERVER_SCOPE); + assertThat(defaultConfig.getScope()).isEqualTo(DataConstants.SERVER_SCOPE); assertThat(defaultConfig.getKeys()).isEqualTo(Collections.emptyList()); } @@ -116,7 +113,7 @@ public class TbMsgDeleteAttributesNodeTest { void givenMsg_whenOnMsg_thenVerifyOutput_SendAttributesDeletedNotification_NotifyDevice() throws Exception { config.setSendAttributesDeletedNotification(true); config.setNotifyDevice(true); - config.setScope(SHARED_SCOPE); + config.setScope(DataConstants.SHARED_SCOPE); nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); node.init(ctx, nodeConfiguration); onMsg_thenVerifyOutput(true, true, false); @@ -136,12 +133,12 @@ public class TbMsgDeleteAttributesNodeTest { ); TbMsgMetaData metaData = new TbMsgMetaData(mdMap); if (notifyDeviceMetadata) { - metaData.putValue(NOTIFY_DEVICE_METADATA_KEY, "true"); - metaData.putValue(SCOPE, SHARED_SCOPE); + metaData.putValue(DataConstants.NOTIFY_DEVICE_METADATA_KEY, "true"); + metaData.putValue(DataConstants.SCOPE, DataConstants.SHARED_SCOPE); } final String data = "{\"TestAttribute_2\": \"humidity\", \"TestAttribute_3\": \"voltage\"}"; - TbMsg msg = TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), deviceId, metaData, data, callback); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, deviceId, metaData, data, callback); node.onMsg(ctx, msg); ArgumentCaptor successCaptor = ArgumentCaptor.forClass(Runnable.class); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java index 071ae9ce96..8ea7806ae2 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNodeTest.java @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -79,7 +80,7 @@ public class TbChangeOriginatorNodeTest { RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - TbMsg msg = TbMsg.newMsg( "ASSET", assetId, new TbMsgMetaData(), TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, assetId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); when(ctx.getAssetService()).thenReturn(assetService); when(assetService.findAssetByIdAsync(any(),eq( assetId))).thenReturn(Futures.immediateFuture(asset)); @@ -87,11 +88,8 @@ public class TbChangeOriginatorNodeTest { node.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); - ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); - ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); - verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); + verify(ctx).transformMsgOriginator(msgCaptor.capture(), originatorCaptor.capture()); assertEquals(customerId, originatorCaptor.getValue()); } @@ -107,18 +105,15 @@ public class TbChangeOriginatorNodeTest { RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - TbMsg msg = TbMsg.newMsg( "ASSET", assetId, new TbMsgMetaData(), TbMsgDataType.JSON,"{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, assetId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON,TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); when(ctx.getAssetService()).thenReturn(assetService); when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(asset)); node.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); - ArgumentCaptor typeCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor originatorCaptor = ArgumentCaptor.forClass(EntityId.class); - ArgumentCaptor metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); - ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(String.class); - verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); + verify(ctx).transformMsgOriginator(msgCaptor.capture(), originatorCaptor.capture()); assertEquals(customerId, originatorCaptor.getValue()); } @@ -134,7 +129,7 @@ public class TbChangeOriginatorNodeTest { RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - TbMsg msg = TbMsg.newMsg( "ASSET", assetId, new TbMsgMetaData(), TbMsgDataType.JSON,"{}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, assetId, TbMsgMetaData.EMPTY, TbMsgDataType.JSON,TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); when(ctx.getAssetService()).thenReturn(assetService); when(assetService.findAssetByIdAsync(any(), eq(assetId))).thenReturn(Futures.immediateFuture(null)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java index a2bfb26b4e..5d8901dcad 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java @@ -26,6 +26,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -42,7 +43,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; public class TbCopyKeysNodeTest { DeviceId deviceId; @@ -158,7 +158,7 @@ public class TbCopyKeysNodeTest { "voltageDataValue", "220", "city", "NY" ); - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java index c73e1eec15..838f35e25e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java @@ -26,6 +26,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -42,7 +43,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; public class TbDeleteKeysNodeTest { DeviceId deviceId; @@ -141,7 +141,7 @@ public class TbDeleteKeysNodeTest { "voltageDataValue", "220", "city", "NY" ); - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java index 91db8dfd26..a86d902007 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbJsonPathNodeTest.java @@ -27,6 +27,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -42,7 +43,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; public class TbJsonPathNodeTest { DeviceId deviceId; @@ -171,6 +171,6 @@ public class TbJsonPathNodeTest { Map mdMap = Map.of("country", "US", "city", "NY" ); - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java index ba17187297..be6aea6fa5 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbMsgDeduplicationNodeTest.java @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -65,14 +66,10 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @Slf4j public class TbMsgDeduplicationNodeTest { - private static final String TB_MSG_DEDUPLICATION_TIMEOUT_MSG = "TbMsgDeduplicationNodeMsg"; - private TbContext ctx; private final ThingsBoardThreadFactory factory = ThingsBoardThreadFactory.forName("de-duplication-node-test"); @@ -98,12 +95,12 @@ public class TbMsgDeduplicationNodeTest { when(ctx.getTenantId()).thenReturn(tenantId); doAnswer((Answer) invocationOnMock -> { - String type = (String) (invocationOnMock.getArguments())[1]; + TbMsgType type = (TbMsgType) (invocationOnMock.getArguments())[1]; EntityId originator = (EntityId) (invocationOnMock.getArguments())[2]; TbMsgMetaData metaData = (TbMsgMetaData) (invocationOnMock.getArguments())[3]; String data = (String) (invocationOnMock.getArguments())[4]; return TbMsg.newMsg(type, originator, metaData.copy(), data); - }).when(ctx).newMsg(isNull(), eq(TB_MSG_DEDUPLICATION_TIMEOUT_MSG), nullable(EntityId.class), any(TbMsgMetaData.class), any(String.class)); + }).when(ctx).newMsg(isNull(), eq(TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG), nullable(EntityId.class), any(TbMsgMetaData.class), any(String.class)); node = spy(new TbMsgDeduplicationNode()); config = new TbMsgDeduplicationNodeConfiguration().defaultConfiguration(); } @@ -243,7 +240,7 @@ public class TbMsgDeduplicationNodeTest { config.setInterval(deduplicationInterval); config.setStrategy(DeduplicationStrategy.ALL); - config.setOutMsgType(POST_ATTRIBUTES_REQUEST.name()); + config.setOutMsgType(TbMsgType.POST_ATTRIBUTES_REQUEST.name()); config.setQueueName(DataConstants.HP_QUEUE_NAME); nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); node.init(ctx, nodeConfiguration); @@ -283,7 +280,7 @@ public class TbMsgDeduplicationNodeTest { config.setInterval(deduplicationInterval); config.setStrategy(DeduplicationStrategy.ALL); - config.setOutMsgType(POST_ATTRIBUTES_REQUEST.name()); + config.setOutMsgType(TbMsgType.POST_ATTRIBUTES_REQUEST.name()); config.setQueueName(DataConstants.HP_QUEUE_NAME); nodeConfiguration = new TbNodeConfiguration(JacksonUtil.valueToTree(config)); node.init(ctx, nodeConfiguration); @@ -415,7 +412,7 @@ public class TbMsgDeduplicationNodeTest { metaData.putValue("ts", String.valueOf(ts)); return TbMsg.newMsg( DataConstants.MAIN_QUEUE_NAME, - POST_TELEMETRY_REQUEST.name(), + TbMsgType.POST_TELEMETRY_REQUEST, deviceId, metaData, JacksonUtil.toString(dataNode)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java index 0caa7f74f3..f226f2e166 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java @@ -26,6 +26,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -40,7 +41,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; public class TbRenameKeysNodeTest { DeviceId deviceId; @@ -155,6 +155,6 @@ public class TbRenameKeysNodeTest { "country", "US", "city", "NY" ); - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java index cf1eee085c..5cdb0d305b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java @@ -27,6 +27,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; @@ -43,7 +44,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; public class TbSplitArrayMsgNodeTest { DeviceId deviceId; @@ -133,6 +133,6 @@ public class TbSplitArrayMsgNodeTest { "country", "US", "city", "NY" ); - return TbMsg.newMsg(POST_ATTRIBUTES_REQUEST.name(), entityId, new TbMsgMetaData(mdMap), data, callback); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, new TbMsgMetaData(mdMap), data, callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java index 71348a1a23..56c94fd4ff 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbTransformMsgNodeTest.java @@ -29,6 +29,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; @@ -60,8 +61,8 @@ public class TbTransformMsgNodeTest { RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - TbMsg msg = TbMsg.newMsg( "USER", null, metaData, TbMsgDataType.JSON,rawJson, ruleChainId, ruleNodeId); - TbMsg transformedMsg = TbMsg.newMsg( "USER", null, metaData, TbMsgDataType.JSON, "{new}", ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON,rawJson, ruleChainId, ruleNodeId); + TbMsg transformedMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, "{new}", ruleChainId, ruleNodeId); when(scriptEngine.executeUpdateAsync(msg)).thenReturn(Futures.immediateFuture(Collections.singletonList(transformedMsg))); node.onMsg(ctx, msg); @@ -80,7 +81,7 @@ public class TbTransformMsgNodeTest { RuleChainId ruleChainId = new RuleChainId(Uuids.timeBased()); RuleNodeId ruleNodeId = new RuleNodeId(Uuids.timeBased()); - TbMsg msg = TbMsg.newMsg( "USER", null, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); when(scriptEngine.executeUpdateAsync(msg)).thenReturn(Futures.immediateFailedFuture(new IllegalStateException("error"))); node.onMsg(ctx, msg); From c3293f556e77a54afdad1ade4a0b8fc557a29ddd Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 6 Jul 2023 11:40:50 +0200 Subject: [PATCH 210/421] inactivity improvements --- .../state/DefaultDeviceStateService.java | 12 +++++-- .../state/DefaultDeviceStateServiceTest.java | 35 ++++++++++++++++--- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 57765b613d..65bb01533b 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -284,6 +284,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService= deviceState.getLastActivityTime()) { + deviceState.setLastInactivityAlarmTime(0L); + save(deviceId, INACTIVITY_ALARM_TIME, 0L); + } } } } diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index 5a69702405..631a82f518 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -141,12 +141,12 @@ public class DefaultDeviceStateServiceTest { } @Test - public void givenUpdateInactivityTimeoutAndThenNoStateChange() throws Exception { + public void givenIncreaseInactivityTimeoutAndThenStateIsActive() throws Exception { TelemetrySubscriptionService telemetrySubscriptionService = Mockito.mock(TelemetrySubscriptionService.class); ReflectionTestUtils.setField(service, "tsSubService", telemetrySubscriptionService); ReflectionTestUtils.setField(service, "defaultStateCheckIntervalInSec", 60); ReflectionTestUtils.setField(service, "defaultActivityStatsIntervalInSec", 60); - ReflectionTestUtils.setField(service, "defaultInactivityTimeoutMs", 60000); + ReflectionTestUtils.setField(service, "defaultInactivityTimeoutMs", 1); ReflectionTestUtils.setField(service, "initFetchPackSize", 10); Mockito.when(entityQueryRepository.findEntityDataByQueryInternal(Mockito.any())).thenReturn(new PageData<>()); @@ -178,18 +178,43 @@ public class DefaultDeviceStateServiceTest { service.deviceStates.put(deviceId, deviceStateData); + service.getPartitionedEntities(tpi).add(deviceId); + service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + Thread.sleep(1); + + service.checkStates(); + + Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(false), Mockito.any()); + Mockito.reset(telemetrySubscriptionService); - service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, 1); + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, System.currentTimeMillis() - deviceState.getLastActivityTime() + 1000); - Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(false), Mockito.any()); - service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, 60000); + Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + + Thread.sleep(2000); + + service.checkStates(); + + Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(false), Mockito.any()); + + Mockito.reset(telemetrySubscriptionService); + + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, 2000); Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + + service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); + + Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, 1); + + Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(false), Mockito.any()); } } \ No newline at end of file From 1d3a9a25b3161dc2161060b5475a8974b6599c4b Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 6 Jul 2023 12:43:15 +0300 Subject: [PATCH 211/421] UI: Introduce form styles. --- ui-ngx/angular.json | 1 + .../alarm/alarm-filter-config.component.html | 12 +- .../alarms-table-basic-config.component.html | 18 +- ...entities-table-basic-config.component.html | 14 +- .../simple-card-basic-config.component.html | 18 +- ...meseries-table-basic-config.component.html | 14 +- .../chart/flot-basic-config.component.html | 24 +- .../common/data-keys-panel.component.html | 4 +- .../widget-actions-panel.component.html | 4 +- .../config/data-key-config.component.html | 12 +- .../widget/config/datasources.component.html | 6 +- .../timewindow-config-panel.component.html | 6 +- .../alarms-table-key-settings.component.html | 16 +- ...larms-table-widget-settings.component.html | 32 +-- ...entities-table-key-settings.component.html | 16 +- ...ities-table-widget-settings.component.html | 34 +-- ...simple-card-widget-settings.component.html | 6 +- ...meseries-table-key-settings.component.html | 12 +- ...s-table-latest-key-settings.component.html | 14 +- ...eries-table-widget-settings.component.html | 22 +- .../chart/flot-key-settings.component.html | 52 ++-- .../flot-latest-key-settings.component.html | 8 +- .../chart/flot-threshold.component.html | 2 +- .../chart/flot-widget-settings.component.html | 104 +++---- .../common/legend-config.component.html | 6 +- .../common/value-source.component.html | 6 +- .../widget/widget-config.component.html | 68 ++--- ui-ngx/src/form.scss | 264 ++++++++++++++++++ ui-ngx/src/styles.scss | 252 ----------------- 29 files changed, 530 insertions(+), 517 deletions(-) create mode 100644 ui-ngx/src/form.scss diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index 86058d45ca..92981aa90f 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -82,6 +82,7 @@ ], "styles": [ "src/styles.scss", + "src/form.scss", "node_modules/jquery.terminal/css/jquery.terminal.min.css", "node_modules/tooltipster/dist/css/tooltipster.bundle.min.css", "node_modules/tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.css", diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html index 7502ea7791..c5ed4fe52a 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html @@ -55,8 +55,8 @@
-
-
+
+
alarm.alarm-status-list
@@ -64,7 +64,7 @@
-
+
alarm.alarm-severity-list
@@ -72,9 +72,9 @@
-
+
alarm.alarm-type-list
- + @@ -89,7 +89,7 @@
-
+
alarm.assignee
-
+
-
alarm.filter
+
alarm.filter
-
-
widgets.chart.comparison-settings
+
+
widgets.chart.comparison-settings
@@ -229,13 +229,13 @@ -
+
widgets.chart.comparison-values-label
-
+
{{ 'widgets.chart.comparison-line-color' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html index bd5d69a594..cdff37f492 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html @@ -16,8 +16,8 @@ --> -
-
widgets.chart.threshold-settings
+
+
widgets.chart.threshold-settings
@@ -29,14 +29,14 @@ -
+
widgets.chart.threshold-line-width
px
-
+
{{ 'widgets.chart.threshold-color' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html index 0aec3e0084..6f08b5f3f7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html @@ -29,7 +29,7 @@ -
+
widgets.chart.line-width
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html index e74126f309..defc26856a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html @@ -16,8 +16,8 @@ --> -
-
widgets.chart.common-settings
+
+
widgets.chart.common-settings
{{ 'widgets.chart.enable-stacking-mode' | translate }} @@ -27,19 +27,19 @@ {{ 'widgets.chart.display-smooth-lines' | translate }} -
+
widgets.chart.line-shadow-size
-
+
widgets.chart.default-bar-width
-
+
{{ 'widgets.chart.bar-alignment' | translate }}
@@ -55,13 +55,13 @@
-
+
widgets.chart.thresholds-line-width
-
+
{{ 'widgets.chart.default-font' | translate }}
@@ -75,8 +75,8 @@
-
-
widget-config.legend
+
+
widget-config.legend
@@ -95,30 +95,30 @@
-
-
widgets.chart.axis
-
-
widgets.chart.vertical-axis
-
+
+
widgets.chart.axis
+
+
widgets.chart.vertical-axis
+
widgets.chart.axis-title
-
+
widgets.chart.min-scale-value
-
+
widgets.chart.max-scale-value
-
-
widgets.chart.ticks
+
+
widgets.chart.ticks
@@ -132,7 +132,7 @@ -
+
{{ 'widget-config.color' | translate }}
@@ -141,13 +141,13 @@
-
+
widget-config.decimals-short
-
+
widgets.chart.tick-step-size
@@ -164,16 +164,16 @@
-
-
widgets.chart.horizontal-axis
-
+
+
widgets.chart.horizontal-axis
+
widgets.chart.axis-title
-
-
widgets.chart.ticks
+
+
widgets.chart.ticks
@@ -187,7 +187,7 @@ -
+
{{ 'widget-config.color' | translate }}
@@ -201,19 +201,19 @@
-
-
widgets.chart.chart-background
-
+
+
widgets.chart.chart-background
+
{{ 'widgets.chart.vertical-grid-lines' | translate }}
-
+
{{ 'widgets.chart.horizontal-grid-lines' | translate }}
-
+
{{ 'widgets.chart.grid-lines-color' | translate }}
@@ -222,7 +222,7 @@
-
+
{{ 'widgets.chart.border' | translate }}
@@ -235,7 +235,7 @@
-
+
{{ 'widgets.chart.background-color' | translate }}
@@ -245,8 +245,8 @@
-
-
widgets.chart.tooltip
+
+
widgets.chart.tooltip
@@ -260,17 +260,17 @@ -
+
{{ 'widgets.chart.hover-individual-points' | translate }}
-
+
{{ 'widgets.chart.show-cumulative-values' | translate }}
-
+
{{ 'widgets.chart.hide-zero-false-values' | translate }} @@ -285,8 +285,8 @@
-
-
widgets.chart.comparison-settings
+
+
widgets.chart.comparison-settings
@@ -300,7 +300,7 @@ -
+
{{ 'widgets.chart.time-for-comparison' | translate }}
@@ -325,26 +325,26 @@
-
+
widgets.chart.custom-interval-value
-
-
widgets.chart.comparison-x-axis-settings
-
+
+
widgets.chart.comparison-x-axis-settings
+
widgets.chart.axis-title
-
+
{{ 'widgets.chart.show-tick-labels' | translate }}
-
+
{{ 'widgets.chart.axis-position' | translate }}
@@ -361,8 +361,8 @@
-
-
widgets.chart.custom-legend-settings
+
+
widgets.chart.custom-legend-settings
@@ -376,8 +376,8 @@ -
-
widgets.chart.label-keys-list
+
+
widgets.chart.label-keys-list
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html index 70663fbad6..10bfa058da 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/legend-config.component.html @@ -16,7 +16,7 @@ --> -
+
{{ 'legend.direction' | translate }}
@@ -26,7 +26,7 @@
-
+
{{ 'legend.position' | translate }}
@@ -38,7 +38,7 @@
-
+
legend.show-values
{{ 'legend.min-option' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html index 460ced4950..3cc771e94f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html @@ -26,13 +26,13 @@
-
+
widgets.value-source.value
-
+
widgets.value-source.source-entity-alias
-
+
widgets.value-source.source-entity-attribute
-
-
widget-config.card-title
+
+
widget-config.card-title
{{ 'widget-config.display-title' | translate }} -
+
widget-config.title
-
+
widget-config.title-tooltip
-
+
{{ 'widget-config.display-icon' | translate }} @@ -82,9 +82,9 @@
-
-
widget-config.card-style
-
+
+
widget-config.card-style
+
{{ 'widget-config.text-color' | translate }}
@@ -93,7 +93,7 @@
-
+
{{ 'widget-config.background-color' | translate }}
@@ -102,19 +102,19 @@
-
+
{{ 'widget-config.padding' | translate }}
-
+
{{ 'widget-config.margin' | translate }}
-
+
{{ 'widget-config.border-radius' | translate }}
@@ -142,15 +142,15 @@
-
-
widget-config.card-buttons
+
+
widget-config.card-buttons
{{ 'widget-config.enable-fullscreen' | translate }}
-
+
-
+
{{ 'widget-config.mobile-hide' | translate }}
-
+
{{ 'widget-config.desktop-hide' | translate }}
-
-
+
+
widget-config.order
-
+
widget-config.height
@@ -212,9 +212,9 @@ formControlName="timewindowConfig"> -
+
-
alarm.filter
+
alarm.filter
-
-
widget-config.target-device
+
widget-config.target-device
-
widget-config.alarm-source
+ [formGroup]="dataSettings" class="tb-form-panel" > +
widget-config.alarm-source
-
-
widget-config.limits
-
+
+
widget-config.limits
+
widget-config.data-page-size
@@ -263,21 +263,21 @@
-
-
widget-config.data-settings
-
+
+
widget-config.data-settings
+
widget-config.units
-
+
widget-config.decimals
-
+
widget-config.no-data-display-message
diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss new file mode 100644 index 0000000000..0d66e09def --- /dev/null +++ b/ui-ngx/src/form.scss @@ -0,0 +1,264 @@ +/** + * Copyright © 2016-2023 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. + */ +.tb-default, .tb-dark { + .tb-form-panel { + box-shadow: 0 0 10px 6px rgba(11, 17, 51, 0.04); + border-radius: 4px; + padding: 16px; + gap: 16px; + display: flex; + flex-direction: column; + color: rgba(0, 0, 0, 0.87); + letter-spacing: 0.15px; + position: relative; + &.no-padding-bottom { + padding-bottom: 0; + } + &.no-padding { + padding: 0; + } + &.stroked { + box-shadow: none; + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 6px; + } + &.no-border { + box-shadow: none; + border-radius: 0; + } + &.tb-slide-toggle { + padding: 0; + gap: 0; + > .tb-form-panel-title { + padding-top: 16px; + padding-left: 16px; + } + > .mat-expansion-panel { + padding: 16px; + .mat-expansion-panel-header { + height: 32px; + .mat-slide { + margin: 0; + } + } + } + } + .mat-expansion-panel { + &.tb-settings { + box-shadow: none; + .mat-content { + overflow: visible; + } + > .mat-expansion-panel-header { + font-weight: 500; + font-size: 16px; + line-height: 24px; + letter-spacing: 0.25px; + padding: 0; + .mat-content { + flex: 0; + white-space: nowrap; + } + &.fill-width { + .mat-content { + flex: 1; + } + } + &:hover { + background: none; + } + .mat-expansion-indicator { + height: 32px; + padding: 2px; + } + } + > .mat-expansion-panel-header-description { + align-items: center; + } + > .mat-expansion-panel-content { + > .mat-expansion-panel-body { + display: flex; + flex-direction: column; + gap: 16px; + padding: 16px 0 0 !important; + } + } + .tb-json-object-panel, .tb-css-content-panel { + margin: 0 0 8px; + } + } + .mat-expansion-panel-content { + font: inherit; + } + } + .mat-slide { + margin: 0; + &.margin { + margin: 8px 0; + } + .mdc-form-field>label { + font-weight: 400; + font-size: 16px; + line-height: 24px; + margin-left: 12px; + } + } + } + + .tb-form-panel-title { + font-weight: 500; + font-size: 16px; + } + .tb-form-panel-hint { + font-size: 12px; + color: #808080; + } + .tb-form-row { + height: 100%; + padding-top: 7px; + padding-bottom: 7px; + display: flex; + flex-direction: row; + align-items: center; + gap: 16px; + padding-left: 16px; + padding-right: 12px; + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 6px; + &.same-padding { + padding-right: 16px; + } + &.space-between { + justify-content: space-between; + } + .mat-divider-vertical { + height: 56px; + margin-top: -7px; + margin-bottom: -7px; + } + .mat-mdc-form-field { + width: 106px; + &.medium-width { + width: 220px; + } + } + .fixed-title-width { + min-width: 200px; + } + .mat-slide:only-child { + margin: 8px 0; + } + } + + .tb-form-row .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { + &.mat-form-field-appearance-fill { + .mdc-text-field--filled:not(.mdc-text-field--disabled) { + &:before { + opacity: 0; + } + .mdc-line-ripple::before { + border-bottom-color: rgba(0, 0, 0, 0.12); + } + } + .mat-mdc-form-field-focus-overlay { + opacity: 0; + } + } + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + padding-right: 12px; + padding-left: 12px; + &:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(:hover) { + .mdc-notched-outline__leading, .mdc-notched-outline__trailing { + border-color: rgba(0, 0, 0, 0.12); + } + } + .mat-mdc-form-field-infix { + padding-top: 8px; + padding-bottom: 8px; + min-height: 40px; + width: auto; + .mdc-text-field__input, .mat-mdc-select { + font-weight: 400; + font-size: 14px; + line-height: 20px; + } + } + .mat-mdc-form-field-icon-suffix { + height: 40px; + font-size: 14px; + line-height: 40px; + letter-spacing: 0.2px; + color: rgba(0, 0, 0, 0.38); + > button.mat-mdc-icon-button { + width: 40px; + height: 40px; + padding: 8px; + .mat-icon { + width: 20px; + height: 20px; + font-size: 20px; + } + } + > .mat-icon { + width: 20px; + height: 20px; + padding: 10px; + font-size: 20px; + } + } + } + } + &.center { + .mat-mdc-text-field-wrapper { + .mat-mdc-form-field-infix { + .mdc-text-field__input { + text-align: center; + } + } + } + } + &.number { + .mat-mdc-text-field-wrapper { + padding-right: 4px; + .mat-mdc-form-field-infix { + input.mdc-text-field__input[type=number]::-webkit-inner-spin-button, + input.mdc-text-field__input[type=number]::-webkit-outer-spin-button { + opacity: 1; + } + } + } + } + &.tb-chips { + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + .mat-mdc-form-field-infix { + padding-top: 4px; + padding-bottom: 4px; + + .mdc-evolution-chip-set { + min-height: 32px; + + .mdc-evolution-chip { + height: 24px; + } + } + } + } + } + } + } +} diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index 0f1a64aa97..127d60e3e5 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -1186,256 +1186,4 @@ mat-label { color: inherit; } - // Widget config - - .tb-widget-config-panel { - box-shadow: 0 0 10px 6px rgba(11, 17, 51, 0.04); - border-radius: 4px; - padding: 16px; - gap: 16px; - display: flex; - flex-direction: column; - color: rgba(0, 0, 0, 0.87); - letter-spacing: 0.15px; - position: relative; - &.no-padding-bottom { - padding-bottom: 0; - } - &.no-padding { - padding: 0; - } - &.stroked { - box-shadow: none; - border: 1px solid rgba(0, 0, 0, 0.12); - border-radius: 6px; - } - &.no-border { - box-shadow: none; - border-radius: 0; - } - &.tb-slide-toggle { - padding: 0; - gap: 0; - > .tb-widget-config-panel-title { - padding-top: 16px; - padding-left: 16px; - } - > .mat-expansion-panel { - padding: 16px; - .mat-expansion-panel-header { - height: 32px; - .mat-slide { - margin: 0; - } - } - } - } - .mat-expansion-panel { - &.tb-settings { - box-shadow: none; - .mat-content { - overflow: visible; - } - > .mat-expansion-panel-header { - font-weight: 500; - font-size: 16px; - line-height: 24px; - letter-spacing: 0.25px; - padding: 0; - .mat-content { - flex: 0; - white-space: nowrap; - } - &.fill-width { - .mat-content { - flex: 1; - } - } - &:hover { - background: none; - } - .mat-expansion-indicator { - height: 32px; - padding: 2px; - } - } - > .mat-expansion-panel-header-description { - align-items: center; - } - > .mat-expansion-panel-content { - > .mat-expansion-panel-body { - display: flex; - flex-direction: column; - gap: 16px; - padding: 16px 0 0 !important; - } - } - .tb-json-object-panel, .tb-css-content-panel { - margin: 0 0 8px; - } - } - .mat-expansion-panel-content { - font: inherit; - } - } - .mat-slide { - margin: 0; - &.margin { - margin: 8px 0; - } - .mdc-form-field>label { - font-weight: 400; - font-size: 16px; - line-height: 24px; - margin-left: 12px; - } - } - } - - .tb-widget-config-panel-title { - font-weight: 500; - font-size: 16px; - } - .tb-widget-config-panel-hint { - font-size: 12px; - color: #808080; - } - .tb-widget-config-row { - height: 100%; - padding-top: 7px; - padding-bottom: 7px; - display: flex; - flex-direction: row; - align-items: center; - gap: 16px; - padding-left: 16px; - padding-right: 12px; - border: 1px solid rgba(0, 0, 0, 0.12); - border-radius: 6px; - &.same-padding { - padding-right: 16px; - } - &.space-between { - justify-content: space-between; - } - .mat-divider-vertical { - height: 56px; - margin-top: -7px; - margin-bottom: -7px; - } - .mat-mdc-form-field { - width: 106px; - &.medium-width { - width: 220px; - } - } - .fixed-title-width { - min-width: 200px; - } - .mat-slide:only-child { - margin: 8px 0; - } - &.tb-chips { - .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { - .mat-mdc-text-field-wrapper { - &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { - .mat-mdc-form-field-infix { - padding-top: 4px; - padding-bottom: 4px; - - .mdc-evolution-chip-set { - min-height: 32px; - - .mdc-evolution-chip { - height: 24px; - } - } - } - } - } - } - } - } - - .tb-widget-config-row .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { - &.mat-form-field-appearance-fill { - .mdc-text-field--filled:not(.mdc-text-field--disabled) { - &:before { - opacity: 0; - } - .mdc-line-ripple::before { - border-bottom-color: rgba(0, 0, 0, 0.12); - } - } - .mat-mdc-form-field-focus-overlay { - opacity: 0; - } - } - .mat-mdc-text-field-wrapper { - &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { - padding-right: 12px; - padding-left: 12px; - &:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(:hover) { - .mdc-notched-outline__leading, .mdc-notched-outline__trailing { - border-color: rgba(0, 0, 0, 0.12); - } - } - .mat-mdc-form-field-infix { - padding-top: 8px; - padding-bottom: 8px; - min-height: 40px; - width: auto; - .mdc-text-field__input, .mat-mdc-select { - font-weight: 400; - font-size: 14px; - line-height: 20px; - } - } - .mat-mdc-form-field-icon-suffix { - height: 40px; - font-size: 14px; - line-height: 40px; - letter-spacing: 0.2px; - color: rgba(0, 0, 0, 0.38); - > button.mat-mdc-icon-button { - width: 40px; - height: 40px; - padding: 8px; - .mat-icon { - width: 20px; - height: 20px; - font-size: 20px; - } - } - > .mat-icon { - width: 20px; - height: 20px; - padding: 10px; - font-size: 20px; - } - } - } - } - &.center { - .mat-mdc-text-field-wrapper { - .mat-mdc-form-field-infix { - .mdc-text-field__input { - text-align: center; - } - } - } - } - &.number { - .mat-mdc-text-field-wrapper { - padding-right: 4px; - .mat-mdc-form-field-infix { - input.mdc-text-field__input[type=number]::-webkit-inner-spin-button, - input.mdc-text-field__input[type=number]::-webkit-outer-spin-button { - opacity: 1; - } - } - } - } - } - } From 4528348143b67e14d502069cac0d663d72ecdfac Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 6 Jul 2023 13:18:02 +0300 Subject: [PATCH 212/421] replaced new TbMsgMetaData() with TbMsgMetaData.EMPTY and added additional refactoring after review of changes --- .../server/common/data/msg/TbMsgType.java | 6 ---- .../server/common/data/msg/TbMsgTypeTest.java | 1 - .../rule/engine/debug/TbMsgGeneratorNode.java | 2 +- .../engine/metadata/TbGetTelemetryNode.java | 12 ++++--- .../rule/engine/profile/DeviceState.java | 31 ++++++------------- .../engine/profile/TbDeviceProfileNode.java | 2 +- .../action/TbCreateRelationNodeTest.java | 2 +- .../engine/edge/TbMsgPushToEdgeNodeTest.java | 2 +- .../engine/filter/TbJsFilterNodeTest.java | 2 +- .../geo/TbGpsGeofencingFilterNodeTest.java | 2 +- .../rule/engine/math/TbMathNodeTest.java | 26 ++++++++-------- .../metadata/CalculateDeltaNodeTest.java | 3 +- .../metadata/TbGetAttributesNodeTest.java | 2 +- .../TbGetCustomerAttributeNodeTest.java | 2 +- .../TbGetCustomerDetailsNodeTest.java | 2 +- .../TbGetOriginatorFieldsNodeTest.java | 2 +- .../TbGetRelatedAttributeNodeTest.java | 2 +- .../TbGetTenantAttributeNodeTest.java | 2 +- .../metadata/TbGetTenantDetailsNodeTest.java | 2 +- .../rule/engine/profile/DeviceStateTest.java | 4 +-- .../rule/engine/rest/TbHttpClientTest.java | 2 +- .../engine/transform/TbCopyKeysNodeTest.java | 6 ++-- .../transform/TbDeleteKeysNodeTest.java | 3 +- .../transform/TbRenameKeysNodeTest.java | 3 +- .../transform/TbSplitArrayMsgNodeTest.java | 3 +- 25 files changed, 52 insertions(+), 74 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java index 0084b391eb..206b203682 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java @@ -71,19 +71,13 @@ public enum TbMsgType { // tellSelfOnly types GENERATOR_NODE_SELF_MSG(null, true), - DEVICE_PROFILE_PERIODIC_SELF_MSG(null, true), DEVICE_PROFILE_UPDATE_SELF_MSG(null, true), DEVICE_UPDATE_SELF_MSG(null, true), - DEDUPLICATION_TIMEOUT_SELF_MSG(null, true), - DELAY_TIMEOUT_SELF_MSG(null, true), - MSG_COUNT_SELF_MSG(null, true); - - public static final List NODE_CONNECTIONS = EnumSet.allOf(TbMsgType.class).stream() .filter(tbMsgType -> !tbMsgType.isTellSelfOnly()) .map(TbMsgType::getRuleNodeConnection) diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java index 58f2089aed..1323b7359d 100644 --- a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java +++ b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java @@ -54,7 +54,6 @@ class TbMsgTypeTest { MSG_COUNT_SELF_MSG ); - // backward-compatibility tests @Test diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java index 7c3d6424e5..2f1aae5000 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java @@ -136,7 +136,7 @@ public class TbMsgGeneratorNode implements TbNode { } lastScheduledTs = lastScheduledTs + delay; long curDelay = Math.max(0L, (lastScheduledTs - curTs)); - TbMsg tickMsg = ctx.newMsg(config.getQueueName(), TbMsgType.GENERATOR_NODE_SELF_MSG, ctx.getSelfId(), new TbMsgMetaData(), TbMsg.EMPTY_STRING); + TbMsg tickMsg = ctx.newMsg(config.getQueueName(), TbMsgType.GENERATOR_NODE_SELF_MSG, ctx.getSelfId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); nextTickId = tickMsg.getId(); ctx.tellSelf(tickMsg, curDelay); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java index 4cf564fd7b..a7ddf2a76b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; import java.util.List; import java.util.concurrent.ExecutionException; @@ -98,8 +99,8 @@ public class TbGetTelemetryNode implements TbNode { List keys = TbNodeUtils.processPatterns(tsKeyNames, msg); ListenableFuture> list = ctx.getTimeseriesService().findAll(ctx.getTenantId(), msg.getOriginator(), buildQueries(interval, keys)); DonAsynchron.withCallback(list, data -> { - process(data, msg, keys); - ctx.tellSuccess(msg); + var metaData = updateMetadata(data, msg, keys); + ctx.tellSuccess(TbMsg.transformMsg(msg, metaData)); }, error -> ctx.tellFailure(msg, error), ctx.getDbCallbackExecutor()); } catch (Exception e) { ctx.tellFailure(msg, e); @@ -129,19 +130,20 @@ public class TbGetTelemetryNode implements TbNode { } } - private void process(List entries, TbMsg msg, List keys) { + private TbMsgMetaData updateMetadata(List entries, TbMsg msg, List keys) { ObjectNode resultNode = JacksonUtil.newObjectNode(JacksonUtil.ALLOW_UNQUOTED_FIELD_NAMES_MAPPER); if (TbGetTelemetryNodeConfiguration.FETCH_MODE_ALL.equals(fetchMode)) { entries.forEach(entry -> processArray(resultNode, entry)); } else { entries.forEach(entry -> processSingle(resultNode, entry)); } - + var copy = msg.getMetaData().copy(); for (String key : keys) { if (resultNode.has(key)) { - msg.getMetaData().putValue(key, resultNode.get(key).toString()); + copy.putValue(key, resultNode.get(key).toString()); } } + return copy; } private void processSingle(ObjectNode node, TsKvEntry entry) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java index e368358299..8cccc51258 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.query.EntityKey; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.rule.RuleNodeState; @@ -54,18 +55,6 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; -import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_ACK; -import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_CLEAR; -import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE; -import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; -import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED; -import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UNASSIGNED; -import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; - @Slf4j class DeviceState { @@ -147,24 +136,24 @@ class DeviceState { latestValues = fetchLatestValues(ctx, deviceId); } boolean stateChanged = false; - if (msg.getType().equals(POST_TELEMETRY_REQUEST.name())) { + if (msg.getType().equals(TbMsgType.POST_TELEMETRY_REQUEST.name())) { stateChanged = processTelemetry(ctx, msg); - } else if (msg.getType().equals(POST_ATTRIBUTES_REQUEST.name())) { + } else if (msg.getType().equals(TbMsgType.POST_ATTRIBUTES_REQUEST.name())) { stateChanged = processAttributesUpdateRequest(ctx, msg); - } else if (msg.getType().equals(ACTIVITY_EVENT.name()) || msg.getType().equals(INACTIVITY_EVENT.name())) { + } else if (msg.getType().equals(TbMsgType.ACTIVITY_EVENT.name()) || msg.getType().equals(TbMsgType.INACTIVITY_EVENT.name())) { stateChanged = processDeviceActivityEvent(ctx, msg); - } else if (msg.getType().equals(ATTRIBUTES_UPDATED.name())) { + } else if (msg.getType().equals(TbMsgType.ATTRIBUTES_UPDATED.name())) { stateChanged = processAttributesUpdateNotification(ctx, msg); - } else if (msg.getType().equals(ATTRIBUTES_DELETED.name())) { + } else if (msg.getType().equals(TbMsgType.ATTRIBUTES_DELETED.name())) { stateChanged = processAttributesDeleteNotification(ctx, msg); - } else if (msg.getType().equals(ALARM_CLEAR.name())) { + } else if (msg.getType().equals(TbMsgType.ALARM_CLEAR.name())) { stateChanged = processAlarmClearNotification(ctx, msg); - } else if (msg.getType().equals(ALARM_ACK.name())) { + } else if (msg.getType().equals(TbMsgType.ALARM_ACK.name())) { processAlarmAckNotification(ctx, msg); - } else if (msg.getType().equals(ALARM_DELETE.name())) { + } else if (msg.getType().equals(TbMsgType.ALARM_DELETE.name())) { processAlarmDeleteNotification(ctx, msg); } else { - if (msg.getType().equals(ENTITY_ASSIGNED.name()) || msg.getType().equals(ENTITY_UNASSIGNED.name())) { + if (msg.getType().equals(TbMsgType.ENTITY_ASSIGNED.name()) || msg.getType().equals(TbMsgType.ENTITY_UNASSIGNED.name())) { dynamicPredicateValueCtx.resetCustomer(); } ctx.tellSuccess(msg); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index 0abb15f279..0475728c4d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -170,7 +170,7 @@ public class TbDeviceProfileNode implements TbNode { } protected void scheduleAlarmHarvesting(TbContext ctx, TbMsg msg) { - TbMsg periodicCheck = TbMsg.newMsg(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG, ctx.getTenantId(), msg != null ? msg.getCustomerId() : null, TbMsgMetaData.EMPTY, "{}"); + TbMsg periodicCheck = TbMsg.newMsg(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG, ctx.getTenantId(), msg != null ? msg.getCustomerId() : null, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); ctx.tellSelf(periodicCheck, TimeUnit.MINUTES.toMillis(1)); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java index 7a9d95cad4..f36cc94540 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java @@ -122,7 +122,7 @@ public class TbCreateRelationNodeTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("name", "AssetName"); metaData.putValue("type", "AssetType"); - msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); + msg = TbMsg.newMsg(TbMsgType.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); EntityRelation relation = new EntityRelation(); when(ctx.getRelationService().findByToAndTypeAsync(any(), eq(msg.getOriginator()), eq(EntityRelation.CONTAINS_TYPE), eq(RelationTypeGroup.COMMON))) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java index 0c51462429..f44326a8d5 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNodeTest.java @@ -125,7 +125,7 @@ public class TbMsgPushToEdgeNodeTest { @Test public void testMiscEventsProcessedAsTimeseriesUpdated() { for (var event : MISC_EVENTS) { - testEvent(event, new TbMsgMetaData(), EdgeEventActionType.TIMESERIES_UPDATED, "data"); + testEvent(event, TbMsgMetaData.EMPTY, EdgeEventActionType.TIMESERIES_UPDATED, "data"); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java index 6ce33fd009..639c1a7b1a 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbJsFilterNodeTest.java @@ -59,7 +59,7 @@ public class TbJsFilterNodeTest { @Test public void falseEvaluationDoNotSendMsg() throws TbNodeException { initWithScript(); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, new TbMsgMetaData(), TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, null, TbMsgMetaData.EMPTY, TbMsgDataType.JSON, TbMsg.EMPTY_JSON_OBJECT, ruleChainId, ruleNodeId); when(scriptEngine.executeFilterAsync(msg)).thenReturn(Futures.immediateFuture(false)); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java index 64a239d57f..f4585d0f96 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNodeTest.java @@ -452,7 +452,7 @@ class TbGpsGeofencingFilterNodeTest { } private TbMsg getEmptyArrayTbMsg(EntityId entityId) { - return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, "[]"); + return TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, entityId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java index 3e19c7a736..0a42349433 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java @@ -247,7 +247,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", arg1).put("b", arg2).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", arg1).put("b", arg2).toString()); node.onMsg(ctx, msg); @@ -270,7 +270,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", arg1).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", arg1).toString()); node.onMsg(ctx, msg); @@ -293,7 +293,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); node.onMsg(ctx, msg); @@ -316,7 +316,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); node.onMsg(ctx, msg); @@ -340,7 +340,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.TIME_SERIES, "b") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().toString()); Mockito.when(attributesService.find(tenantId, originator, DataConstants.SERVER_SCOPE, "a")) .thenReturn(Futures.immediateFuture(Optional.of(new BaseAttributeKvEntry(System.currentTimeMillis(), new DoubleDataEntry("a", 2.0))))); @@ -368,7 +368,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); node.onMsg(ctx, msg); @@ -390,7 +390,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); node.onMsg(ctx, msg); @@ -412,7 +412,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); Mockito.when(telemetryService.saveAttrAndNotify(any(), any(), anyString(), anyString(), anyDouble())) .thenReturn(Futures.immediateFuture(null)); @@ -438,7 +438,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); Mockito.when(telemetryService.saveAndNotify(any(), any(), any(TsKvEntry.class))) .thenReturn(Futures.immediateFuture(null)); @@ -463,7 +463,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 5).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString()); Mockito.when(telemetryService.saveAndNotify(any(), any(), any(TsKvEntry.class))) .thenReturn(Futures.immediateFuture(null)); @@ -494,7 +494,7 @@ public class TbMathNodeTest { new TbMathResult(TbMathArgumentType.MESSAGE_METADATA, "result", 3, false, false, null), tbMathArgument ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 10).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 10).toString()); node.onMsg(ctx, msg); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); @@ -514,7 +514,7 @@ public class TbMathNodeTest { new TbMathResult(TbMathArgumentType.TIME_SERIES, "result", 3, true, false, DataConstants.SERVER_SCOPE), new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "TestKey") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 10).toString()); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 10).toString()); Throwable thrown = assertThrows(RuntimeException.class, () -> { node.onMsg(ctx, msg); }); @@ -528,7 +528,7 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a") ); - TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, new TbMsgMetaData(), "[]"); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); Throwable thrown = assertThrows(RuntimeException.class, () -> { node.onMsg(ctx, msg); }); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java index 9dbae201ac..2f99fbb43c 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNodeTest.java @@ -117,8 +117,7 @@ public class CalculateDeltaNodeTest { @Test public void givenInvalidMsgDataType_whenOnMsg_thenShouldTellNextOther() { // GIVEN - var msgData = "[]"; - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, msgData); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); // WHEN node.onMsg(ctxMock, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java index a889f91b77..2263b272b9 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNodeTest.java @@ -241,7 +241,7 @@ public class TbGetAttributesNodeTest { public void givenFetchLatestTimeseriesToDataAndDataIsNotJsonObject_whenOnMsg_thenException() throws Exception { // GIVEN node = initNode(FetchTo.DATA, true, true); - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 3a8f36f5dc..b413d2c576 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -208,7 +208,7 @@ public class TbGetCustomerAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java index 8b958bcc3c..1908578801 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNodeTest.java @@ -157,7 +157,7 @@ public class TbGetCustomerDetailsNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java index 0057ec7c61..dfc80d1752 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNodeTest.java @@ -133,7 +133,7 @@ public class TbGetOriginatorFieldsNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java index 6b3a225eac..0965327df0 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNodeTest.java @@ -222,7 +222,7 @@ public class TbGetRelatedAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java index ffb053c93a..c7a23a512b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNodeTest.java @@ -188,7 +188,7 @@ public class TbGetTenantAttributeNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java index 2dda9ffaf0..23b1abea73 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNodeTest.java @@ -127,7 +127,7 @@ public class TbGetTenantDetailsNodeTest { public void givenMsgDataIsNotAnJsonObjectAndFetchToData_whenOnMsg_thenException() { // GIVEN node.fetchTo = FetchTo.DATA; - msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, "[]"); + msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, DUMMY_DEVICE_ORIGINATOR, TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_ARRAY); // WHEN var exception = assertThrows(IllegalArgumentException.class, () -> node.onMsg(ctxMock, msg)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java index 6bc4a59610..eef77a5304 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/profile/DeviceStateTest.java @@ -107,7 +107,7 @@ public class DeviceStateTest { DeviceState deviceState = createDeviceState(deviceId, alarmConfig); TbMsg attributeUpdateMsg = TbMsg.newMsg(TbMsgType.POST_ATTRIBUTES_REQUEST, - deviceId, new TbMsgMetaData(), "{ \"enabled\": false }"); + deviceId, TbMsgMetaData.EMPTY, "{ \"enabled\": false }"); deviceState.process(ctx, attributeUpdateMsg); @@ -119,7 +119,7 @@ public class DeviceStateTest { reset(ctx); String deletedAttributes = "{ \"attributes\": [ \"other\" ] }"; - deviceState.process(ctx, TbMsg.newMsg(TbMsgType.ATTRIBUTES_DELETED, deviceId, new TbMsgMetaData(), deletedAttributes)); + deviceState.process(ctx, TbMsg.newMsg(TbMsgType.ATTRIBUTES_DELETED, deviceId, TbMsgMetaData.EMPTY, deletedAttributes)); verify(ctx, never()).enqueueForTellNext(any(), anyString()); } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java index 2ddc20d5ed..48aca3b573 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java @@ -145,7 +145,7 @@ public class TbHttpClientTest { var httpClient = new TbHttpClient(config, eventLoop); httpClient.setHttpClient(asyncRestTemplate); - var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, new DeviceId(EntityId.NULL_UUID), TbMsgMetaData.EMPTY, "{}"); + var msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, new DeviceId(EntityId.NULL_UUID), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); var successMsg = TbMsg.newMsg( TbMsgType.POST_TELEMETRY_REQUEST, msg.getOriginator(), msg.getMetaData(), msg.getData() diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java index 5d8901dcad..e0ab34e35b 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbCopyKeysNodeTest.java @@ -79,8 +79,7 @@ public class TbCopyKeysNodeTest { @Test void givenMsgFromMetadata_whenOnMsg_thenVerifyOutput() throws Exception { - String data = "{}"; - node.onMsg(ctx, getTbMsg(deviceId, data)); + node.onMsg(ctx, getTbMsg(deviceId, TbMsg.EMPTY_JSON_OBJECT)); ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); @@ -137,8 +136,7 @@ public class TbCopyKeysNodeTest { @Test void givenMsgDataNotJSONObject_whenOnMsg_thenTVerifyOutput() throws Exception { - String data = "[]"; - TbMsg msg = getTbMsg(deviceId, data); + TbMsg msg = getTbMsg(deviceId, TbMsg.EMPTY_JSON_ARRAY); node.onMsg(ctx, msg); ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java index 838f35e25e..6eee16e7d3 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbDeleteKeysNodeTest.java @@ -79,8 +79,7 @@ public class TbDeleteKeysNodeTest { @Test void givenMsgFromMetadata_whenOnMsg_thenVerifyOutput() throws Exception { - String data = "{}"; - node.onMsg(ctx, getTbMsg(deviceId, data)); + node.onMsg(ctx, getTbMsg(deviceId, TbMsg.EMPTY_JSON_OBJECT)); ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture()); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java index f226f2e166..c602aab5df 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbRenameKeysNodeTest.java @@ -135,8 +135,7 @@ public class TbRenameKeysNodeTest { @Test void givenMsgDataNotJSONObject_whenOnMsg_thenVerifyOutput() throws Exception { - String data = "[]"; - TbMsg msg = getTbMsg(deviceId, data); + TbMsg msg = getTbMsg(deviceId, TbMsg.EMPTY_JSON_ARRAY); node.onMsg(ctx, msg); ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java index 5cdb0d305b..e7e2ae16b2 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/transform/TbSplitArrayMsgNodeTest.java @@ -83,8 +83,7 @@ public class TbSplitArrayMsgNodeTest { @Test void givenZeroMsg_whenOnMsg_thenVerifyOutput() throws Exception { - String data = "[]"; - VerifyOutputMsg(data); + VerifyOutputMsg(TbMsg.EMPTY_JSON_ARRAY); } @Test From ffdb16766ce033a4002bad6a4675693178230178 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 6 Jul 2023 13:31:25 +0200 Subject: [PATCH 213/421] improvements --- .../queue/discovery/ZkDiscoveryService.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index 17d046a4cb..24a7863b24 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -299,16 +299,16 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi case CHILD_ADDED: ScheduledFuture task = delayedTasks.remove(instance.getServiceId()); if (task != null) { - if (!task.cancel(false)) { - log.debug("[{}] Going to recalculate partitions due to adding new node [{}]", + if (task.cancel(false)) { + log.debug("[{}] Recalculate partitions ignored. Service was restarted in time [{}].", instance.getServiceId(), instance.getServiceTypesList()); - recalculatePartitions(); } else { - log.debug("[{}] Recalculate partitions ignored. Service restarted in time [{}]", + log.debug("[{}] Going to recalculate partitions. Service was not restarted in time [{}]!", instance.getServiceId(), instance.getServiceTypesList()); + recalculatePartitions(); } } else { - log.debug("[{}] Going to recalculate partitions due to adding new node [{}]", + log.debug("[{}] Going to recalculate partitions due to adding new node [{}].", instance.getServiceId(), instance.getServiceTypesList()); recalculatePartitions(); } @@ -317,8 +317,10 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi ScheduledFuture future = zkExecutorService.schedule(() -> { log.debug("[{}] Going to recalculate partitions due to removed node [{}]", instance.getServiceId(), instance.getServiceTypesList()); - delayedTasks.remove(instance.getServiceId()); - recalculatePartitions(); + ScheduledFuture removedTask = delayedTasks.remove(instance.getServiceId()); + if (removedTask != null) { + recalculatePartitions(); + } }, recalculateDelay, TimeUnit.MILLISECONDS); delayedTasks.put(instance.getServiceId(), future); break; @@ -332,6 +334,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi * Synchronized to ensure that other servers info is up to date * */ synchronized void recalculatePartitions() { + delayedTasks.clear(); partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), getOtherServers()); } From 14216a48827b9f59d836b7362a8d296899c1b0a2 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 6 Jul 2023 15:03:32 +0300 Subject: [PATCH 214/421] fixed security transport cases --- .../src/main/resources/thingsboard.yml | 12 ++ .../server/dao/device/DeviceService.java | 1 + .../dao/device/DeviceConnectivityInfo.java | 5 +- .../server/dao/device/DeviceServiceImpl.java | 126 ++++++++++++------ 4 files changed, 97 insertions(+), 47 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 2f58590bf6..3615e25825 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -981,16 +981,28 @@ transport: # Device connectivity properties to publish telemetry device: connectivity: + http: + enabled: "${DEVICE_CONNECTIVITY_HTTP_ENABLED:true}" + host: "${DEVICE_CONNECTIVITY_HTTP_HOST:localhost}" + port: "${DEVICE_CONNECTIVITY_HTTP_PORT:8080}" + https: + enabled: "${DEVICE_CONNECTIVITY_HTTPS_ENABLED:false}" + host: "${DEVICE_CONNECTIVITY_HTTPS_HOST:localhost}" + port: "${DEVICE_CONNECTIVITY_HTTPS_PORT:443}" mqtt: + enabled: "${DEVICE_CONNECTIVITY_MQTT_ENABLED:true}" host: "${DEVICE_CONNECTIVITY_MQTT_HOST:localhost}" port: "${DEVICE_CONNECTIVITY_MQTT_PORT:1883}" mqtts: + enabled: "${DEVICE_CONNECTIVITY_MQTT_ENABLED:false}" host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:localhost}" port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" coap: + enabled: "${DEVICE_CONNECTIVITY_MQTT_ENABLED:true}" host: "${DEVICE_CONNECTIVITY_COAP_HOST:localhost}" port: "${DEVICE_CONNECTIVITY_COAP_PORT:5683}" coaps: + enabled: "${DEVICE_CONNECTIVITY_MQTT_ENABLED:false}" host: "${DEVICE_CONNECTIVITY_COAPS_HOST:localhost}" port: "${DEVICE_CONNECTIVITY_COAPS_PORT:5684}" diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index 72c6a8852c..a029f27309 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.device; +import com.fasterxml.jackson.databind.JsonNode; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceIdInfo; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java index 7b477bfc42..f570919290 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java @@ -16,11 +16,10 @@ package org.thingsboard.server.dao.device; import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; - @Data public class DeviceConnectivityInfo { + private Boolean enabled; private String host; - private Integer port; + private String port; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index fe5ac33e73..1a881d82bd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -80,6 +80,8 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; @@ -104,8 +106,15 @@ public class DeviceServiceImpl extends AbstractCachedEntityService findDevicePublishTelemetryCommands(String baseUrl, Device device) { + public Map findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException { DeviceId deviceId = device.getId(); log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId); validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); + String defaultHostname = new URI(baseUrl).getHost(); DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); - DeviceCredentialsType credentialsType = creds.getCredentialsType(); - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); DeviceTransportType transportType = deviceProfile.getTransportType(); Map commands = new HashMap<>(); - switch (transportType) { case DEFAULT: - Optional.ofNullable(getHttpPublishCommand(baseUrl, creds)).ifPresent(v -> commands.put("http", v)); - Optional.ofNullable(getMqttPublishCommand(creds)).ifPresent(v -> commands.put("mqtt", v)); - Optional.ofNullable(getMqttsPublishCommand(creds)).ifPresent(v -> commands.put("mqtts", v)); - Optional.ofNullable(getCoapPublishCommand(creds)).ifPresent(v -> commands.put("coap", v)); - Optional.ofNullable(getCoapsPublishCommand(creds)).ifPresent(v -> commands.put("coaps", v)); + Optional.ofNullable(getHttpPublishCommand(defaultHostname, creds)).ifPresent(v -> commands.put(HTTP_PROTOCOL, v)); + Optional.ofNullable(getHttpsPublishCommand(defaultHostname, creds)).ifPresent(v -> commands.put(HTTPS_PROTOCOL, v)); + Optional.ofNullable(getMqttPublishCommand(defaultHostname, creds)).ifPresent(v -> commands.put(MQTT_PROTOCOL, v)); + Optional.ofNullable(getMqttsPublishCommand(defaultHostname, creds)).ifPresent(v -> commands.put(MQTTS_PROTOCOL, v)); + Optional.ofNullable(getCoapPublishCommand(defaultHostname, creds)).ifPresent(v -> commands.put(COAP_PROTOCOL, v)); + Optional.ofNullable(getCoapsPublishCommand(defaultHostname, creds)).ifPresent(v -> commands.put(COAPS_PROTOCOL, v)); break; case MQTT: MqttDeviceProfileTransportConfiguration transportConfiguration = @@ -164,19 +172,12 @@ public class DeviceServiceImpl extends AbstractCachedEntityService commands.put("mqtt", v)); - Optional.ofNullable(getMqttsPublishCommand(topicName, creds, payload)).ifPresent(v -> commands.put("mqtts", v)); + Optional.ofNullable(getMqttPublishCommand(defaultHostname, topicName, creds, payload)).ifPresent(v -> commands.put(MQTT_PROTOCOL, v)); + Optional.ofNullable(getMqttsPublishCommand(defaultHostname, topicName, creds, payload)).ifPresent(v -> commands.put(MQTTS_PROTOCOL, v)); break; case COAP: - CoapDeviceProfileTransportConfiguration coapTransportConfiguration = - (CoapDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); - CoapDeviceTypeConfiguration coapConfiguration = coapTransportConfiguration.getCoapDeviceTypeConfiguration(); - if (coapConfiguration instanceof DefaultCoapDeviceTypeConfiguration) { - Optional.ofNullable(getCoapPublishCommand(creds)).ifPresent(v -> commands.put("coap", v)); - Optional.ofNullable(getCoapsPublishCommand(creds)).ifPresent(v -> commands.put("coaps", v)); - } else if (coapConfiguration instanceof EfentoCoapDeviceTypeConfiguration) { - commands.put("coap for efento", "Not supported"); - } + Optional.ofNullable(getCoapPublishCommand(defaultHostname, creds)).ifPresent(v -> commands.put(COAP_PROTOCOL, v)); + Optional.ofNullable(getCoapsPublishCommand(defaultHostname, creds)).ifPresent(v -> commands.put(COAPS_PROTOCOL, v)); break; default: commands.put(transportType.name(), NOT_SUPPORTED); @@ -743,24 +744,45 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Thu, 6 Jul 2023 15:06:07 +0300 Subject: [PATCH 215/421] minor refactoring --- .../server/dao/device/DeviceServiceImpl.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 1a881d82bd..a0a8b9dbcd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -48,10 +48,6 @@ import org.thingsboard.server.common.data.device.data.DeviceData; import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration; import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration; import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; -import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; -import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration; -import org.thingsboard.server.common.data.device.profile.EfentoCoapDeviceTypeConfiguration; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; @@ -745,7 +741,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Thu, 6 Jul 2023 15:18:16 +0300 Subject: [PATCH 216/421] fixed descriptions for enrichment rule nodes --- .../rule/engine/filter/TbOriginatorTypeSwitchNode.java | 2 +- .../thingsboard/rule/engine/metadata/CalculateDeltaNode.java | 3 ++- .../rule/engine/metadata/TbFetchDeviceCredentialsNode.java | 4 +++- .../thingsboard/rule/engine/metadata/TbGetAttributesNode.java | 3 ++- .../rule/engine/metadata/TbGetCustomerAttributeNode.java | 3 ++- .../rule/engine/metadata/TbGetCustomerDetailsNode.java | 3 ++- .../thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java | 4 +++- .../rule/engine/metadata/TbGetOriginatorFieldsNode.java | 3 ++- .../rule/engine/metadata/TbGetRelatedAttributeNode.java | 3 ++- .../thingsboard/rule/engine/metadata/TbGetTelemetryNode.java | 3 ++- .../rule/engine/metadata/TbGetTenantAttributeNode.java | 3 ++- .../rule/engine/metadata/TbGetTenantDetailsNode.java | 3 ++- 12 files changed, 25 insertions(+), 12 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java index 9e14c6a7ab..17b7d575f5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java @@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; relationTypes = {}, // should always be empty. We add the relation types for this node in AnnotationComponentDiscoveryService. nodeDescription = "Route incoming messages by Message Originator Type", nodeDetails = "Routes messages to chain according to the entity type ('Device', 'Asset', etc.).

" + - "Output connections: Message originator type or Failure", + "Output connections: Message originator type or Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") public class TbOriginatorTypeSwitchNode extends TbAbstractTypeSwitchNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java index 25b9205602..3e4e6eb93f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java @@ -50,7 +50,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback; configClazz = CalculateDeltaNodeConfiguration.class, nodeDescription = "Calculates delta and amount of time passed between previous timeseries key reading " + "and current value for this key from the incoming message", - nodeDetails = "Useful for metering use cases, when you need to calculate consumption based on pulse counter reading.", + nodeDetails = "Useful for metering use cases, when you need to calculate consumption based on pulse counter reading.

" + + "Output connections: Success, Other or Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeCalculateDeltaConfig") public class CalculateDeltaNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java index e23da1e364..d8934535af 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java @@ -41,7 +41,9 @@ import java.util.concurrent.ExecutionException; nodeDescription = "Adds device credentials to the message or message metadata", nodeDetails = "if message originator type is Device and device credentials was successfully fetched, " + "rule node enriches message or message metadata with credentialsType and credentials properties. " + - "Useful when you need to fetch device credentials and use them for further message processing. For example, use device credentials to interact with external systems.", + "Useful when you need to fetch device credentials and use them for further message processing. " + + "For example, use device credentials to interact with external systems.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeFetchDeviceCredentialsConfig") public class TbFetchDeviceCredentialsNode extends TbAbstractNodeWithFetchTo { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java index 975da84510..edc7bdc44e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java @@ -40,7 +40,8 @@ import org.thingsboard.server.common.msg.TbMsg; nodeDescription = "Adds attributes and/or latest timeseries data for the message originator to the message or message metadata", nodeDetails = "Useful when you need to retrieve some attributes or the latest telemetry readings from the message originator " + "that are not included in the incoming message to use them for further message processing. " + - "For example to filter messages based on the threshold value stored in the attributes.", + "For example to filter messages based on the threshold value stored in the attributes.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeOriginatorAttributesConfig") public class TbGetAttributesNode extends TbAbstractGetAttributesNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index f5b50f259c..088aa596fc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -39,7 +39,8 @@ import org.thingsboard.server.common.data.util.TbPair; nodeDescription = "Adds message originator customer attributes or latest telemetry into message or message metadata", nodeDetails = "Useful in multi-customer solutions where each customer has a different configuration or threshold set " + "that is stored as customer attributes or telemetry data and used for dynamic message filtering, transformation, " + - "or actions such as alarm creation if the threshold is exceeded.", + "or actions such as alarm creation if the threshold is exceeded.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeCustomerAttributesConfig") public class TbGetCustomerAttributeNode extends TbAbstractGetEntityDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java index 3be5ac15c3..377e9eb0da 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java @@ -47,7 +47,8 @@ import java.util.NoSuchElementException; version = 1, nodeDescription = "Adds message originator customer details into message or message metadata", nodeDetails = "Useful in multi-customer solutions where we need dynamically use customer contact information " + - "such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.", + "such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java index 67e544fcfa..eb82d26007 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java @@ -38,7 +38,9 @@ import org.thingsboard.server.common.msg.TbMsg; nodeDescription = "Add originators related device attributes and/or latest telemetry values into message or message metadata", nodeDetails = "Related device lookup based on the configured relation query. " + "If multiple related devices are found, only first device is used for message enrichment, other entities are discarded. " + - "Useful when you need to retrieve attributes and/or latest telemetry values from device that has a relation to the message originator and use them for further message processing.", + "Useful when you need to retrieve attributes and/or latest telemetry values from device that has a relation " + + "to the message originator and use them for further message processing.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeDeviceAttributesConfig") public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java index 34153360a3..30c3e10cde 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java @@ -40,7 +40,8 @@ import java.util.concurrent.ExecutionException; version = 1, nodeDescription = "Adds message originator fields values into message or message metadata", nodeDetails = "Fetches fields values specified in the mapping. If specified field is not part of originator fields it will be ignored. " + - "Useful when you need to retrieve originator fields and use them for further message processing.", + "Useful when you need to retrieve originator fields and use them for further message processing.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeOriginatorFieldsConfig") public class TbGetOriginatorFieldsNode extends TbAbstractGetMappedDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index 249caa87ac..50e75c8cc0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -40,7 +40,8 @@ import java.util.Arrays; nodeDescription = "Adds originators related entity attributes or latest telemetry or fields into message or message metadata", nodeDetails = "Related entity lookup based on the configured relation query. " + "If multiple related entities are found, only first entity is used for message enrichment, other entities are discarded. " + - "Useful when you need to retrieve data from an entity that has a relation to the message originator and use them for further message processing.", + "Useful when you need to retrieve data from an entity that has a relation to the message originator and use them for further message processing.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeRelatedAttributesConfig") public class TbGetRelatedAttributeNode extends TbAbstractGetEntityDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java index a7ddf2a76b..08fa2a6246 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java @@ -54,7 +54,8 @@ import java.util.stream.Collectors; nodeDescription = "Adds message originator telemetry for selected time range into message metadata", nodeDetails = "Useful when you need to get telemetry data set from the message originator for a specific time range " + "instead of fetching just the latest telemetry or if you need to get the closest telemetry to the fetch interval start or end. " + - "Also, this node can be used for telemetry aggregation within configured fetch interval.", + "Also, this node can be used for telemetry aggregation within configured fetch interval.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase") public class TbGetTelemetryNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index cbbf00ce92..bcd54cd829 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -37,7 +37,8 @@ import org.thingsboard.server.common.data.util.TbPair; version = 1, nodeDescription = "Adds message originator tenant attributes or latest telemetry into message or message metadata", nodeDetails = "Useful when you need to retrieve some common configuration or threshold set " + - "that is stored as tenant attributes or telemetry data and use it for further message processing.", + "that is stored as tenant attributes or telemetry data and use it for further message processing.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeTenantAttributesConfig") public class TbGetTenantAttributeNode extends TbAbstractGetEntityDataNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index 8e293aea37..2a5039f849 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -36,7 +36,8 @@ import org.thingsboard.server.common.msg.TbMsg; version = 1, nodeDescription = "Adds message originator tenant details into message or message metadata", nodeDetails = "Useful when we need to retrieve contact information from your tenant " + - "such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.", + "such as email, phone, address, etc., for notifications via email, SMS, and other notification providers.

" + + "Output connections: Success, Failure.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbEnrichmentNodeEntityDetailsConfig") public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode { From bb71ae39c3ed381241e2606202f9e27dd92d9de1 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 6 Jul 2023 17:24:13 +0300 Subject: [PATCH 217/421] added tests --- .../controller/DeviceControllerTest.java | 175 +++++++++++++++--- 1 file changed, 150 insertions(+), 25 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java index 96aa5638db..477500508f 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java @@ -34,6 +34,7 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.Customer; @@ -51,14 +52,16 @@ import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; -import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceCredentialsId; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -91,12 +94,19 @@ import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; +@TestPropertySource(properties = { + "device.connectivity.https.enabled=true", + "device.connectivity.mqtts.enabled=true", + "device.connectivity.coaps.enabled=true", +}) @ContextConfiguration(classes = {DeviceControllerTest.Config.class}) @DaoSqlTest public class DeviceControllerTest extends AbstractControllerTest { static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() { }; + private static final String DEVICE_TELEMETRY_TOPIC = "v1/devices/customTopic"; + ListeningExecutorService executor; List> futures; @@ -104,6 +114,8 @@ public class DeviceControllerTest extends AbstractControllerTest { private Tenant savedTenant; private User tenantAdmin; + private DeviceProfileId mqttDeviceProfileId; + private DeviceProfileId coapDeviceProfileId; @SpyBean private GatewayNotificationsService gatewayNotificationsService; @@ -138,6 +150,34 @@ public class DeviceControllerTest extends AbstractControllerTest { tenantAdmin.setLastName("Downs"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + + DeviceProfile mqttProfile = new DeviceProfile(); + mqttProfile.setName("Mqtt device profile"); + mqttProfile.setType(DeviceProfileType.DEFAULT); + mqttProfile.setTransportType(DeviceTransportType.MQTT); + DeviceProfileData deviceProfileData = new DeviceProfileData(); + deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration()); + MqttDeviceProfileTransportConfiguration transportConfiguration = new MqttDeviceProfileTransportConfiguration(); + transportConfiguration.setDeviceTelemetryTopic(DEVICE_TELEMETRY_TOPIC); + deviceProfileData.setTransportConfiguration(transportConfiguration); + mqttProfile.setProfileData(deviceProfileData); + mqttProfile.setDefault(false); + mqttProfile.setDefaultRuleChainId(null); + + mqttDeviceProfileId = doPost("/api/deviceProfile", mqttProfile, DeviceProfile.class).getId(); + + DeviceProfile coapProfile = new DeviceProfile(); + coapProfile.setName("Coap device profile"); + coapProfile.setType(DeviceProfileType.DEFAULT); + coapProfile.setTransportType(DeviceTransportType.COAP); + DeviceProfileData deviceProfileData2 = new DeviceProfileData(); + deviceProfileData2.setConfiguration(new DefaultDeviceProfileConfiguration()); + deviceProfileData2.setTransportConfiguration(new CoapDeviceProfileTransportConfiguration()); + coapProfile.setProfileData(deviceProfileData); + coapProfile.setDefault(false); + coapProfile.setDefaultRuleChainId(null); + + coapDeviceProfileId = doPost("/api/deviceProfile", coapProfile, DeviceProfile.class).getId(); } @After @@ -655,51 +695,136 @@ public class DeviceControllerTest extends AbstractControllerTest { device.setName("My device"); device.setType("default"); Device savedDevice = doPost("/api/device", device, Device.class); - List commands = + Map commands = doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); DeviceCredentials credentials = doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); - assertThat(commands).hasSize(3); - assertThat(commands).containsExactly(String.format("mosquitto_pub -d -q 1 -h localhost -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", - credentials.getCredentialsId()), - String.format("curl -v -X POST http://localhost:80/api/v1/%s/telemetry --header Content-Type:application/json --data \"{temperature:25}\"", - credentials.getCredentialsId()), - String.format("echo -n \"{temperature:25}\" | coap-client -m post coap://localhost:5683/api/v1/%s/telemetry -f-", - credentials.getCredentialsId())); + assertThat(commands).hasSize(6); + assertThat(commands.get("http")).isEqualTo(String.format("curl -v -X POST http://localhost:8080/api/v1/%s/telemetry --header Content-Type:application/json --data \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(commands.get("https")).isEqualTo(String.format("curl -v -X POST https://localhost:443/api/v1/%s/telemetry --header Content-Type:application/json --data \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(commands.get("mqtt")).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(commands.get("mqtts")).isEqualTo(String.format("mosquitto_pub --cafile tb-server-chain.pem -d -q 1 -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(commands.get("coap")).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(commands.get("coaps")).isEqualTo(String.format("coap-client-openssl -v 9 -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); } @Test - public void testFetchPublishTelemetryCommandsForMqttDevice() throws Exception { - DeviceProfile mqttProfile = new DeviceProfile(); - mqttProfile.setName("Mqtt device profile"); - mqttProfile.setType(DeviceProfileType.DEFAULT); - mqttProfile.setTransportType(DeviceTransportType.MQTT); + public void testFetchPublishTelemetryCommandsForMqttDeviceWithAccessToken() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(mqttDeviceProfileId); - DeviceProfileData deviceProfileData = new DeviceProfileData(); - deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration()); - deviceProfileData.setTransportConfiguration(new MqttDeviceProfileTransportConfiguration()); + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); - mqttProfile.setProfileData(deviceProfileData); - mqttProfile.setDefault(false); - mqttProfile.setDefaultRuleChainId(null); + Map commands = + doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); + assertThat(commands).hasSize(2); + assertThat(commands.get("mqtt")).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s -u %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + assertThat(commands.get("mqtts")).isEqualTo(String.format("mosquitto_pub --cafile tb-server-chain.pem -d -q 1 -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + } - mqttProfile = doPost("/api/deviceProfile", mqttProfile, DeviceProfile.class); + @Test + public void testFetchPublishTelemetryCommandsForDeviceWithMqttBasicCreds() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(mqttDeviceProfileId); + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + credentials.setCredentialsId(null); + credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC); + BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials(); + String clientId = "testClientId"; + String userName = "testUsername"; + String password = "testPassword"; + basicMqttCredentials.setClientId(clientId); + basicMqttCredentials.setUserName(userName); + basicMqttCredentials.setPassword(password); + credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials)); + doPost("/api/device/credentials", credentials) + .andExpect(status().isOk()); + + Map commands = + doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); + assertThat(commands).hasSize(2); + assertThat(commands.get("mqtt")).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + assertThat(commands.get("mqtts")).isEqualTo(String.format("mosquitto_pub --cafile tb-server-chain.pem -d -q 1 -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + } + + @Test + public void testFetchPublishTelemetryCommandsForDeviceWithX509Creds() throws Exception { Device device = new Device(); device.setName("My device"); - device.setDeviceProfileId(mqttProfile.getId()); + device.setDeviceProfileId(mqttDeviceProfileId); Device savedDevice = doPost("/api/device", device, Device.class); DeviceCredentials credentials = doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + credentials.setCredentialsId(null); + credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); + credentials.setCredentialsValue("testValue"); + doPost("/api/device/credentials", credentials) + .andExpect(status().isOk()); + + Map commands = + doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); + assertThat(commands).hasSize(1); + assertThat(commands.get("mqtts")).isEqualTo("Not supported"); + } + + @Test + public void testFetchPublishTelemetryCommandsForСoapDevice() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(coapDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + + Map commands = + doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); + assertThat(commands).hasSize(2); + assertThat(commands.get("coap")).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(commands.get("coaps")).isEqualTo(String.format("coap-client-openssl -v 9 -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); + } + + @Test + public void testFetchPublishTelemetryCommandsForСoapDeviceWithX509Creds() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(coapDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + credentials.setCredentialsId(null); + credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); + credentials.setCredentialsValue("testValue"); + doPost("/api/device/credentials", credentials) + .andExpect(status().isOk()); - List commands = + Map commands = doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); assertThat(commands).hasSize(1); - assertThat(commands.get(0)).isEqualTo("mosquitto_pub -d -q 1 -h localhost -t v1/devices/me/telemetry -u " - + credentials.getCredentialsId() + " -m \"{temperature:25}\""); + assertThat(commands.get("coaps")).isEqualTo("Not supported"); } @Test From a1bf0f6e1911c04e72c3d9ff9b6f5eb8b083930f Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 7 Jul 2023 09:28:56 +0300 Subject: [PATCH 218/421] UI: Add option show/hide table cell actions --- .../widget/lib/alarms-table-widget.component.html | 4 ++-- .../components/widget/lib/alarms-table-widget.component.ts | 5 ++++- .../widget/lib/entities-table-widget.component.html | 4 ++-- .../widget/lib/entities-table-widget.component.ts | 7 +++++-- .../alarm/alarms-table-widget-settings.component.html | 3 +++ .../alarm/alarms-table-widget-settings.component.ts | 2 ++ .../cards/entities-table-widget-settings.component.html | 3 +++ .../cards/entities-table-widget-settings.component.ts | 2 ++ .../cards/timeseries-table-widget-settings.component.html | 3 +++ .../cards/timeseries-table-widget-settings.component.ts | 2 ++ .../home/components/widget/lib/table-widget.models.ts | 1 + .../widget/lib/timeseries-table-widget.component.html | 4 ++-- .../widget/lib/timeseries-table-widget.component.ts | 2 ++ ui-ngx/src/assets/locale/locale.constant-en_US.json | 3 ++- 14 files changed, 35 insertions(+), 10 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html index 9a23e86bf8..cfb92e5b87 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html @@ -125,7 +125,7 @@ -
+
-
+
-
+
-
+
-
+
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts index 1bc43044cc..6bd7d62c12 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts @@ -47,7 +47,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent enableFilter: true, enableStickyHeader: true, enableStickyAction: true, - hideActionCellButtons: true, + collapseCellActions: true, reserveSpaceForHiddenAction: 'true', displayDetails: true, allowAcknowledgment: true, @@ -70,7 +70,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent enableFilter: [settings.enableFilter, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], - hideActionCellButtons: [settings.hideActionCellButtons, []], + collapseCellActions: [settings.collapseCellActions, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], displayDetails: [settings.displayDetails, []], allowAcknowledgment: [settings.allowAcknowledgment, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html index 2168c190b7..818b18e6ad 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html @@ -66,8 +66,8 @@ {{ 'widgets.table.enable-sticky-action' | translate }} - - {{ 'widgets.table.hide-action-cell-buttons' | translate }} + + {{ 'widgets.table.collapse-cell-actions-mobile' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts index 0a030a86a1..f73a86069e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts @@ -45,7 +45,7 @@ export class EntitiesTableWidgetSettingsComponent extends WidgetSettingsComponen enableSelectColumnDisplay: true, enableStickyHeader: true, enableStickyAction: true, - hideActionCellButtons: true, + collapseCellActions: true, reserveSpaceForHiddenAction: 'true', displayEntityName: true, entityNameColumnTitle: '', @@ -67,7 +67,7 @@ export class EntitiesTableWidgetSettingsComponent extends WidgetSettingsComponen enableSelectColumnDisplay: [settings.enableSelectColumnDisplay, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], - hideActionCellButtons: [settings.hideActionCellButtons, []], + collapseCellActions: [settings.collapseCellActions, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], displayEntityName: [settings.displayEntityName, []], entityNameColumnTitle: [settings.entityNameColumnTitle, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index 17e9630082..bb286c83a7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -39,8 +39,8 @@ {{ 'widgets.table.enable-sticky-action' | translate }} - - {{ 'widgets.table.hide-action-cell-buttons' | translate }} + + {{ 'widgets.table.collapse-cell-actions-mobile' | translate }} widgets.table.hidden-cell-button-display-mode diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts index 3365fac4bb..edec3990e5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts @@ -44,7 +44,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon enableSelectColumnDisplay: true, enableStickyHeader: true, enableStickyAction: true, - hideActionCellButtons: true, + collapseCellActions: true, reserveSpaceForHiddenAction: 'true', showTimestamp: true, showMilliseconds: false, @@ -64,7 +64,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon enableSelectColumnDisplay: [settings.enableSelectColumnDisplay, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], - hideActionCellButtons: [settings.hideActionCellButtons, []], + collapseCellActions: [settings.collapseCellActions, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], showTimestamp: [settings.showTimestamp, []], showMilliseconds: [settings.showMilliseconds, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts index 0369d1db68..9de4601e02 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts @@ -33,7 +33,7 @@ export interface TableWidgetSettings { enableSearch: boolean; enableSelectColumnDisplay: boolean; enableStickyAction: boolean; - hideActionCellButtons: boolean; + collapseCellActions: boolean; enableStickyHeader: boolean; displayPagination: boolean; defaultPageSize: number; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html index 266d857efb..633b1c7455 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html @@ -67,7 +67,7 @@ -
+
-
+
+ + + + + + + diff --git a/ui-ngx/src/app/shared/components/unit-input.component.scss b/ui-ngx/src/app/shared/components/unit-input.component.scss new file mode 100644 index 0000000000..25280e51ec --- /dev/null +++ b/ui-ngx/src/app/shared/components/unit-input.component.scss @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2023 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. + */ +.tb-autocomplete.tb-unit-input-autocomplete { + .mat-mdc-option { + border-bottom: none; + .mdc-list-item__primary-text { + flex: 1; + display: flex; + flex-direction: row; + gap: 8px; + .tb-unit-name, .tb-unit-symbol { + font-size: 14px; + font-weight: 400; + line-height: 20px; + letter-spacing: 0.2px; + } + .tb-unit-symbol { + color: rgba(0, 0, 0, 0.38); + min-width: 22px; + text-align: end; + b { + color: rgba(0, 0, 0, 0.87); + } + } + } + } +} diff --git a/ui-ngx/src/app/shared/components/unit-input.component.ts b/ui-ngx/src/app/shared/components/unit-input.component.ts new file mode 100644 index 0000000000..4b70c31cec --- /dev/null +++ b/ui-ngx/src/app/shared/components/unit-input.component.ts @@ -0,0 +1,148 @@ +/// +/// Copyright © 2016-2023 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, ElementRef, forwardRef, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, UntypedFormBuilder } from '@angular/forms'; +import { Observable, of } from 'rxjs'; +import { searchUnits, Unit, unitBySymbol, units } from '@shared/models/unit.models'; +import { map, mergeMap, startWith, tap } from 'rxjs/operators'; +import { TranslateService } from '@ngx-translate/core'; + +@Component({ + selector: 'tb-unit-input', + templateUrl: './unit-input.component.html', + styleUrls: ['./unit-input.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => UnitInputComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None +}) +export class UnitInputComponent implements ControlValueAccessor, OnInit { + + unitsFormControl: FormControl; + + modelValue: string | null; + + @Input() + disabled: boolean; + + @ViewChild('unitInput', {static: true}) unitInput: ElementRef; + + filteredUnits: Observable>; + + searchText = ''; + + private dirty = false; + + private translatedUnits: Array = units.map(u => ({symbol: u.symbol, + name: this.translate.instant(u.name), + tags: u.tags})); + + private propagateChange = (_val: any) => {}; + + constructor(private fb: UntypedFormBuilder, + private translate: TranslateService) { + } + + ngOnInit() { + this.unitsFormControl = this.fb.control('', []); + this.filteredUnits = this.unitsFormControl.valueChanges + .pipe( + tap(value => { + this.updateView(value); + }), + startWith(''), + map(value => (value as Unit)?.symbol ? (value as Unit).symbol : (value ? value as string : '')), + mergeMap(symbol => this.fetchUnits(symbol) ) + ); + } + + writeValue(symbol?: string): void { + this.searchText = ''; + this.modelValue = symbol; + let res: Unit | string = null; + if (symbol) { + const unit = unitBySymbol(symbol); + res = unit ? unit : symbol; + } + this.unitsFormControl.patchValue(res, {emitEvent: false}); + this.dirty = true; + } + + onFocus() { + if (this.dirty) { + this.unitsFormControl.updateValueAndValidity({onlySelf: true, emitEvent: true}); + this.dirty = false; + } + } + + updateView(value: Unit | string | null) { + const res: string = (value as Unit)?.symbol ? (value as Unit)?.symbol : (value as string); + if (this.modelValue !== res) { + this.modelValue = res; + this.propagateChange(this.modelValue); + } + } + + displayUnitFn(unit?: Unit | string): string | undefined { + if (unit) { + if ((unit as Unit).symbol) { + return (unit as Unit).symbol; + } else { + return unit as string; + } + } + return undefined; + } + + fetchUnits(searchText?: string): Observable> { + this.searchText = searchText; + const result = searchUnits(this.translatedUnits, searchText); + if (result.length) { + return of(result); + } else { + return of([]); + } + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.unitsFormControl.disable({emitEvent: false}); + } else { + this.unitsFormControl.enable({emitEvent: false}); + } + } + + clear() { + this.unitsFormControl.patchValue(null, {emitEvent: true}); + setTimeout(() => { + this.unitInput.nativeElement.blur(); + this.unitInput.nativeElement.focus(); + }, 0); + } +} diff --git a/ui-ngx/src/app/shared/models/unit.models.ts b/ui-ngx/src/app/shared/models/unit.models.ts new file mode 100644 index 0000000000..7ac0d4db57 --- /dev/null +++ b/ui-ngx/src/app/shared/models/unit.models.ts @@ -0,0 +1,70 @@ +/// +/// Copyright © 2016-2023 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. +/// + +export interface Unit { + name: string; + symbol: string; + tags: string[]; +} + +export const units: Array = [ + { + name: 'unit.celsius', + symbol: '°C', + tags: ['temperature'] + }, + { + name: 'unit.kelvin', + symbol: 'K', + tags: ['temperature'] + }, + { + name: 'unit.fahrenheit', + symbol: '°F', + tags: ['temperature'] + }, + { + name: 'unit.percentage', + symbol: '%', + tags: ['percentage'] + }, + { + name: 'unit.second', + symbol: 's', + tags: ['time'] + }, + { + name: 'unit.minute', + symbol: 'min', + tags: ['time'] + }, + { + name: 'unit.hour', + symbol: 'h', + tags: ['time'] + } +]; + +export const unitBySymbol = (symbol: string): Unit => units.find(u => u.symbol === symbol); + +const searchUnitTags = (unit: Unit, searchText: string): boolean => + !!unit.tags.find(t => t.toUpperCase().includes(searchText.toUpperCase())); + +export const searchUnits = (_units: Array, searchText: string): Array => _units.filter( + u => u.symbol.toUpperCase().includes(searchText.toUpperCase()) || + u.name.toUpperCase().includes(searchText.toUpperCase()) || + searchUnitTags(u, searchText) +); diff --git a/ui-ngx/src/app/shared/pipe/highlight.pipe.ts b/ui-ngx/src/app/shared/pipe/highlight.pipe.ts index 0f8595fc3b..5d712c5b93 100644 --- a/ui-ngx/src/app/shared/pipe/highlight.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/highlight.pipe.ts @@ -18,11 +18,10 @@ import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'highlight' }) export class HighlightPipe implements PipeTransform { - transform(text: string, search): string { + transform(text: string, search: string, includes = false, flags = 'i'): string { const pattern = search .replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); - const regex = new RegExp('^' + pattern, 'i'); - + const regex = new RegExp((!includes ? '^' : '') + pattern, flags); return search ? text.replace(regex, match => `${match}`) : text; } } diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index cf8b271171..f7c37e4761 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -194,6 +194,7 @@ import { ShortNumberPipe } from '@shared/pipe/short-number.pipe'; import { ToggleHeaderComponent, ToggleOption } from '@shared/components/toggle-header.component'; import { RuleChainSelectComponent } from '@shared/components/rule-chain/rule-chain-select.component'; import { ToggleSelectComponent } from '@shared/components/toggle-select.component'; +import { UnitInputComponent } from '@shared/components/unit-input.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -367,6 +368,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ToggleHeaderComponent, ToggleOption, ToggleSelectComponent, + UnitInputComponent, RuleChainSelectComponent ], imports: [ @@ -597,6 +599,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ToggleHeaderComponent, ToggleOption, ToggleSelectComponent, + UnitInputComponent, RuleChainSelectComponent ] }) 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 c5ec1fca40..82f10b7f4c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3860,6 +3860,15 @@ "just-now": "Just now", "ago": "ago" }, + "unit": { + "celsius": "Celsius", + "kelvin": "Kelvin", + "fahrenheit": "Fahrenheit", + "percentage": "Percentage", + "second": "Second", + "minute": "Minute", + "hour": "Hour" + }, "user": { "user": "User", "users": "Users", diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 0d66e09def..fbd816272b 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -177,9 +177,15 @@ opacity: 0; } } + &:not(.mat-mdc-form-field-has-icon-suffix) { + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + padding-right: 12px; + } + } + } .mat-mdc-text-field-wrapper { &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { - padding-right: 12px; padding-left: 12px; &:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(:hover) { .mdc-notched-outline__leading, .mdc-notched-outline__trailing { @@ -233,7 +239,9 @@ } &.number { .mat-mdc-text-field-wrapper { - padding-right: 4px; + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + padding-right: 4px; + } .mat-mdc-form-field-infix { input.mdc-text-field__input[type=number]::-webkit-inner-spin-button, input.mdc-text-field__input[type=number]::-webkit-outer-spin-button { From 9ddc5e5b8d79bb5a3c4bcb35ccfaac5128dc78a2 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Fri, 7 Jul 2023 17:42:44 +0300 Subject: [PATCH 226/421] added resource delete validation --- .../service/entitiy/SimpleTbEntityService.java | 3 ++- .../resource/DefaultTbResourceService.java | 15 +++++++++++++-- .../server/dao/widget/WidgetTypeService.java | 3 +++ .../server/dao/sql/widget/JpaWidgetTypeDao.java | 5 +++++ .../dao/sql/widget/WidgetTypeRepository.java | 7 +++++++ .../server/dao/widget/WidgetTypeDao.java | 8 ++++++++ .../server/dao/widget/WidgetTypeServiceImpl.java | 10 ++++++++++ 7 files changed, 48 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java index 609a61b903..270662f263 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.service.entitiy; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.exception.ThingsboardException; public interface SimpleTbEntityService { @@ -25,6 +26,6 @@ public interface SimpleTbEntityService { T save(T entity, User user) throws Exception; - void delete(T entity, User user); + void delete(T entity, User user) throws ThingsboardException; } diff --git a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java index 81a06e9344..c47adc42c1 100644 --- a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java +++ b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java @@ -27,14 +27,18 @@ import org.thingsboard.server.common.data.TbResourceInfo; import org.thingsboard.server.common.data.TbResourceInfoFilter; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.lwm2m.LwM2mObject; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.widget.BaseWidgetType; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.resource.ResourceService; +import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; @@ -55,9 +59,11 @@ import static org.thingsboard.server.utils.LwM2mObjectModelUtils.toLwm2mResource public class DefaultTbResourceService extends AbstractTbEntityService implements TbResourceService { private final ResourceService resourceService; + private final WidgetTypeService widgetTypeService; - public DefaultTbResourceService(ResourceService resourceService) { + public DefaultTbResourceService(ResourceService resourceService, WidgetTypeService widgetTypeService) { this.resourceService = resourceService; + this.widgetTypeService = widgetTypeService; } @Override @@ -145,10 +151,15 @@ public class DefaultTbResourceService extends AbstractTbEntityService implements } @Override - public void delete(TbResource tbResource, User user) { + public void delete(TbResource tbResource, User user) throws ThingsboardException { TbResourceId resourceId = tbResource.getId(); TenantId tenantId = tbResource.getTenantId(); try { + List widgets = widgetTypeService.findWidgetTypesInfosByTenantIdAndResourceId(tenantId, resourceId); + if (!widgets.isEmpty()) { + List widgetNames = widgets.stream().map(BaseWidgetType::getName).collect(Collectors.toList()); + throw new ThingsboardException(String.format("Following widget types uses current resource: %s", widgetNames), ThingsboardErrorCode.GENERAL); + } resourceService.deleteResource(tenantId, resourceId); tbClusterService.onResourceDeleted(tbResource, null); notificationEntityService.logEntityAction(tenantId, resourceId, tbResource, ActionType.DELETED, user, resourceId.toString()); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java index cb02aa1180..245e33ed14 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.widget; +import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetType; @@ -40,6 +41,8 @@ public interface WidgetTypeService extends EntityDaoService { List findWidgetTypesInfosByTenantIdAndBundleAlias(TenantId tenantId, String bundleAlias); + List findWidgetTypesInfosByTenantIdAndResourceId(TenantId tenantId, TbResourceId tbResourceId); + WidgetType findWidgetTypeByTenantIdBundleAliasAndAlias(TenantId tenantId, String bundleAlias, String alias); void deleteWidgetTypesByTenantIdAndBundleAlias(TenantId tenantId, String bundleAlias); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java index b54dd371fe..689bcb0b03 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java @@ -77,6 +77,11 @@ public class JpaWidgetTypeDao extends JpaAbstractDao findWidgetTypesInfosByTenantIdAndResourceId(UUID tenantId, UUID tbResourceId) { + return DaoUtil.convertDataList(widgetTypeRepository.findWidgetTypesInfosByTenantIdAndResourceId(tenantId, tbResourceId)); + } + @Override public EntityType getEntityType() { return EntityType.WIDGET_TYPE; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java index a3cba644b5..55e05fe2b4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java @@ -46,4 +46,11 @@ public interface WidgetTypeRepository extends JpaRepository> 'resources' LIKE LOWER(CONCAT('%', :resourceId, '%'))", + nativeQuery = true) + List findWidgetTypesInfosByTenantIdAndResourceId(@Param("tenantId") UUID tenantId, + @Param("resourceId") UUID resourceId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java index c0fb8dd3f4..a54aa45b37 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java @@ -83,4 +83,12 @@ public interface WidgetTypeDao extends Dao { */ WidgetType findByTenantIdBundleAliasAndAlias(UUID tenantId, String bundleAlias, String alias); + /** + * Find widget types infos by tenantId and resourceId in descriptor. + * + * @param tenantId the tenantId + * @param tbResourceId the resourceId + * @return the list of widget types infos objects + */ + List findWidgetTypesInfosByTenantIdAndResourceId(UUID tenantId, UUID tbResourceId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index 0337c190a4..1ac099b075 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -21,6 +21,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.HasId; +import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetType; @@ -37,6 +38,7 @@ import java.util.Optional; public class WidgetTypeServiceImpl implements WidgetTypeService { public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; + public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId "; public static final String INCORRECT_BUNDLE_ALIAS = "Incorrect bundleAlias "; @Autowired private WidgetTypeDao widgetTypeDao; @@ -96,6 +98,14 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { return widgetTypeDao.findWidgetTypesInfosByTenantIdAndBundleAlias(tenantId.getId(), bundleAlias); } + @Override + public List findWidgetTypesInfosByTenantIdAndResourceId(TenantId tenantId, TbResourceId tbResourceId) { + log.trace("Executing findWidgetTypesInfosByTenantIdAndResourceId, tenantId [{}], tbResourceId [{}]", tenantId, tbResourceId); + Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + Validator.validateId(tbResourceId, INCORRECT_RESOURCE_ID + tbResourceId); + return widgetTypeDao.findWidgetTypesInfosByTenantIdAndResourceId(tenantId.getId(), tbResourceId.getId()); + } + @Override public WidgetType findWidgetTypeByTenantIdBundleAliasAndAlias(TenantId tenantId, String bundleAlias, String alias) { log.trace("Executing findWidgetTypeByTenantIdBundleAliasAndAlias, tenantId [{}], bundleAlias [{}], alias [{}]", tenantId, bundleAlias, alias); From db95bc8aa81f6d2beded755563be4c925cbd7811 Mon Sep 17 00:00:00 2001 From: kalytka Date: Mon, 10 Jul 2023 10:46:37 +0300 Subject: [PATCH 227/421] Added ng-content to js-func conponent --- ui-ngx/src/app/shared/components/js-func.component.html | 1 + 1 file changed, 1 insertion(+) 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 23ebd76918..8827d9e57f 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.html +++ b/ui-ngx/src/app/shared/components/js-func.component.html @@ -27,6 +27,7 @@ +
Date: Mon, 10 Jul 2023 12:14:55 +0300 Subject: [PATCH 228/421] added swagger response body example --- .../server/controller/DeviceController.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 260c1c91e0..e080574d36 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -21,8 +21,11 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -175,6 +178,15 @@ public class DeviceController extends BaseController { "If the user has the authority of 'Tenant Administrator', the server checks that the device is owned by the same tenant. " + "If the user has the authority of 'Customer User', the server checks that the device is assigned to the same customer. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK", + examples = @io.swagger.annotations.Example( + value = { + @io.swagger.annotations.ExampleProperty( + mediaType="application/json", + value="{\"http\":\"curl -v -X POST http://localhost:8080/api/v1/0ySs4FTOn5WU15XLmal8/telemetry --header Content-Type:application/json --data {temperature:25}\"," + + "\"mqtt\":\"mosquitto_pub -d -q 1 -h localhost -t v1/devices/me/telemetry -i myClient1 -u myUsername1 -P myPassword -m {temperature:25}\"," + + "\"coap\":\"coap-client -m POST coap://localhost:5683/api/v1/0ySs4FTOn5WU15XLmal8/telemetry -t json -e {temperature:25}\"}")}))}) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/device/{deviceId}/commands", method = RequestMethod.GET) @ResponseBody From 66ac23a78017a88eafe5442526de5bb37eccf111 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 10 Jul 2023 12:59:54 +0300 Subject: [PATCH 229/421] UI: Refactoring notification settings --- .../notification-setting-form.component.html | 20 ++++++++---------- .../notification-settings.component.html | 21 ++++++++++--------- .../notification-settings.component.scss | 18 ++++++++++++---- 3 files changed, 34 insertions(+), 25 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html index a4e7e062b5..752ffa367a 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html @@ -18,19 +18,17 @@
- - - {{notificationTemplateTypeTranslateMap.get(notificationSettingsFormGroup.get('name').value)?.name | translate}} - + + + {{notificationTemplateTypeTranslateMap.get(notificationSettingsFormGroup.get('name').value)?.name | translate}} + +
-
+
- - + +
@@ -48,7 +48,7 @@
-
+
-
- -
+
+ +
diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss index 12263158d1..fe8111afa0 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss @@ -17,6 +17,11 @@ :host { .mat-mdc-card.settings-card { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; margin: 8px; @media #{$mat-gt-sm} { width: 60%; @@ -24,13 +29,18 @@ .mat-headline-5 { margin: 0; } - .notification-section { + .notification-form { + height: calc(100% - 48px); + min-height: min-content; + max-height: min-content; margin-bottom: 16px; + } + .notification-section { + height: 100%; border: 1px solid rgba(0, 0, 0, 0.12); - overflow-y: hidden; - overflow-x: scroll; + overflow: scroll; &-block { - min-width: 700px; + min-width: 470px; } } } From cce56b9547f9c7cf89b8284b469aa5d5fded9ea7 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 10 Jul 2023 13:28:38 +0300 Subject: [PATCH 230/421] added test --- .../entitiy/SimpleTbEntityService.java | 2 +- .../resource/DefaultTbResourceService.java | 7 +--- .../controller/TbResourceControllerTest.java | 32 +++++++++++++++++++ .../dao/resource/BaseResourceService.java | 1 + .../server/dao/service/DataValidator.java | 4 +++ .../validator/ResourceDataValidator.java | 21 ++++++++++++ 6 files changed, 60 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java index 270662f263..daf0f346c8 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java @@ -26,6 +26,6 @@ public interface SimpleTbEntityService { T save(T entity, User user) throws Exception; - void delete(T entity, User user) throws ThingsboardException; + void delete(T entity, User user); } diff --git a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java index c47adc42c1..064511abd9 100644 --- a/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java +++ b/application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java @@ -151,15 +151,10 @@ public class DefaultTbResourceService extends AbstractTbEntityService implements } @Override - public void delete(TbResource tbResource, User user) throws ThingsboardException { + public void delete(TbResource tbResource, User user) { TbResourceId resourceId = tbResource.getId(); TenantId tenantId = tbResource.getTenantId(); try { - List widgets = widgetTypeService.findWidgetTypesInfosByTenantIdAndResourceId(tenantId, resourceId); - if (!widgets.isEmpty()) { - List widgetNames = widgets.stream().map(BaseWidgetType::getName).collect(Collectors.toList()); - throw new ThingsboardException(String.format("Following widget types uses current resource: %s", widgetNames), ThingsboardErrorCode.GENERAL); - } resourceService.deleteResource(tenantId, resourceId); tbClusterService.onResourceDeleted(tbResource, null); notificationEntityService.logEntityAction(tenantId, resourceId, tbResource, ActionType.DELETED, user, resourceId.toString()); diff --git a/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java index b4735519a5..bb542e6cf1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TbResourceControllerTest.java @@ -38,6 +38,8 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; +import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DaoSqlTest; @@ -216,6 +218,36 @@ public class TbResourceControllerTest extends AbstractControllerTest { .andExpect(statusReason(containsString(msgErrorNoFound("Resource", resourceIdStr)))); } + @Test + public void testShoudNotDeleteTbResourceIfAssignedToWidgetType() throws Exception { + TbResource resource = new TbResource(); + resource.setResourceType(ResourceType.JKS); + resource.setTitle("My first resource"); + resource.setFileName(DEFAULT_FILE_NAME); + resource.setData(TEST_DATA); + + TbResource savedResource = save(resource); + + Mockito.reset(tbClusterService, auditLogService); + String resourceIdStr = savedResource.getId().getId().toString(); + + //create widget type + WidgetsBundle widgetsBundle = new WidgetsBundle(); + widgetsBundle.setTitle("My widgets bundle"); + WidgetsBundle savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class); + + WidgetTypeDetails widgetType = new WidgetTypeDetails(); + widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); + widgetType.setName("Widget Type"); + widgetType.setDescriptor(JacksonUtil.fromString(String.format("{ \"resources\": [{\"url\":{\"entityType\":\"TB_RESOURCE\",\"id\":\"%s\"},\"isModule\":true}]}", savedResource.getId()), JsonNode.class)); + doPost("/api/widgetType", widgetType, WidgetTypeDetails.class); + + doDelete("/api/resource/" + resourceIdStr) + .andExpect(status().isBadRequest()) + .andExpect(statusReason(containsString("Following widget types uses current resource: [" + + widgetType .getName()+ "]"))); + } + @Test public void testFindTenantTbResources() throws Exception { diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index bc4f47040b..7697217b6b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -109,6 +109,7 @@ public class BaseResourceService extends AbstractCachedEntityService> { return null; } + public void validateDelete(TenantId tenantId, EntityId entityId) { + } + protected boolean isSameData(D existentData, D actualData) { return actualData.getId() != null && existentData.getId().equals(actualData.getId()); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java index c547f3c416..9939d887fa 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java @@ -20,14 +20,21 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TbResource; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; +import org.thingsboard.server.common.data.widget.BaseWidgetType; +import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.resource.TbResourceDao; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; +import org.thingsboard.server.dao.widget.WidgetTypeDao; + +import java.util.List; +import java.util.stream.Collectors; import static org.thingsboard.server.common.data.EntityType.TB_RESOURCE; @@ -37,6 +44,9 @@ public class ResourceDataValidator extends DataValidator { @Autowired private TbResourceDao resourceDao; + @Autowired + private WidgetTypeDao widgetTypeDao; + @Autowired private TenantService tenantService; @@ -77,4 +87,15 @@ public class ResourceDataValidator extends DataValidator { } } } + + @Override + public void validateDelete(TenantId tenantId, EntityId resourceId) { + List widgets = widgetTypeDao.findWidgetTypesInfosByTenantIdAndResourceId(tenantId.getId(), + resourceId.getId()); + if (!widgets.isEmpty()) { + List widgetNames = widgets.stream().map(BaseWidgetType::getName).collect(Collectors.toList()); + throw new DataValidationException(String.format("Following widget types uses current resource: %s", widgetNames)); + } + } + } From 80dfb3c5294dd7a403c5412870994e80727620ee Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 10 Jul 2023 13:31:00 +0300 Subject: [PATCH 231/421] deleted redundant imports --- .../server/service/entitiy/SimpleTbEntityService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java index daf0f346c8..609a61b903 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/SimpleTbEntityService.java @@ -16,7 +16,6 @@ package org.thingsboard.server.service.entitiy; import org.thingsboard.server.common.data.User; -import org.thingsboard.server.common.data.exception.ThingsboardException; public interface SimpleTbEntityService { From 0da9affe18e40a67d473c5243b902a252dde7c99 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 10 Jul 2023 16:48:13 +0300 Subject: [PATCH 232/421] fixed user phone display in entities table --- .../server/dao/sql/query/DefaultEntityQueryRepository.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index 2135e98eed..4cf6db0fc1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -69,7 +69,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { private static final Map entityTableMap = new HashMap<>(); private static final Map entityNameColumns = new HashMap<>(); private static final String SELECT_PHONE = " CASE WHEN entity.entity_type = 'TENANT' THEN (select phone from tenant where id = entity_id)" + - " WHEN entity.entity_type = 'CUSTOMER' THEN (select phone from customer where id = entity_id) END as phone"; + " WHEN entity.entity_type = 'CUSTOMER' THEN (select phone from customer where id = entity_id)" + + " WHEN entity.entity_type = 'USER' THEN (select phone from tb_user where id = entity_id) END as phone"; private static final String SELECT_ZIP = " CASE WHEN entity.entity_type = 'TENANT' THEN (select zip from tenant where id = entity_id)" + " WHEN entity.entity_type = 'CUSTOMER' THEN (select zip from customer where id = entity_id) END as zip"; private static final String SELECT_ADDRESS_2 = " CASE WHEN entity.entity_type = 'TENANT'" + From 4685139820d5b2e59cf0c2cf00591e32ae37e659 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 10 Jul 2023 17:38:22 +0300 Subject: [PATCH 233/421] UI: Add new unit models --- ui-ngx/src/app/shared/models/unit.models.ts | 2003 ++++++++++++++++- .../assets/locale/locale.constant-en_US.json | 413 +++- 2 files changed, 2405 insertions(+), 11 deletions(-) diff --git a/ui-ngx/src/app/shared/models/unit.models.ts b/ui-ngx/src/app/shared/models/unit.models.ts index 7ac0d4db57..e5ca8aa0b3 100644 --- a/ui-ngx/src/app/shared/models/unit.models.ts +++ b/ui-ngx/src/app/shared/models/unit.models.ts @@ -21,20 +21,1458 @@ export interface Unit { } export const units: Array = [ + { + name: 'unit.millimeter', + symbol: 'mm', + tags: ['level','height','distance','length','width','gap','depth','millimeter','millimeters','rainfall','precipitation', + 'displacement','position','movement','transition','mm'] + }, + { + name: 'unit.centimeter', + symbol: 'cm', + tags: ['level','height','distance','length','width','gap','depth','centimeter','centimeters','rainfall','precipitation', + 'displacement','position','movement','transition','cm'] + }, + { + name: 'unit.angstrom', + symbol: 'Å', + tags: ['level','height','distance','length','width','gap','depth','atomic scale','atomic distance','nanoscale', + 'angstrom','angstroms','Å'] + }, + { + name: 'unit.nanometer', + symbol: 'nm', + tags: ['level','height','distance','length','width','gap','depth','nanoscale','atomic scale','molecular scale', + 'nanometer','nanometers','nm'] + }, + { + name: 'unit.micrometer', + symbol: 'µm', + tags: ['level','height','distance','length','width','gap','depth','microns','micrometer','micrometers','µm'] + }, + { + name: 'unit.meter', + symbol: 'm', + tags: ['level','height','distance','length','width','gap','depth','meter','meters','m'] + }, + { + name: 'unit.kilometer', + symbol: 'km', + tags: ['distance','height','length','width','gap','depth','kilometer','kilometers','km'] + }, + { + name: 'unit.inch', + symbol: 'in', + tags: ['level','height','distance','length','width','gap','depth','inch','inches','in'] + }, + { + name: 'unit.foot', + symbol: 'ft', + tags: ['level','height','distance','length','width','gap','depth','foot','feet','ft'] + }, + { + name: 'unit.yard', + symbol: 'yd', + tags: ['level','height','distance','length','width','gap','depth','yard','yards','yd'] + }, + { + name: 'unit.mile', + symbol: 'mi', + tags: ['level','height','distance','length','width','gap','depth','mile','miles','mi'] + }, + { + name: 'unit.nautical-mile', + symbol: 'nm', + tags: ['level','height','distance','length','width','gap','depth','nautical mile','nm'] + }, + { + name: 'unit.astronomical-unit', + symbol: 'AU', + tags: ['distance','celestial bodies','solar system','AU'] + }, + { + name: 'unit.reciprocal-metre', + symbol: 'm⁻¹', + tags: ['wavenumber','wave density','wave frequency','m⁻¹'] + }, + { + name: 'unit.meter-per-meter', + symbol: 'm/m', + tags: ['ratio of length to length','meter per meter','m/m'] + }, + { + name: 'unit.steradian', + symbol: 'sr', + tags: ['solid angle','spatial extent','steradian','sr'] + }, + { + name: 'unit.thou', + symbol: 'thou', + tags: ['length','measurement','thou'] + }, + { + name: 'unit.barleycorn', + symbol: 'barleycorn', + tags: ['length','shoe size','barleycorn'] + }, + { + name: 'unit.hand', + symbol: 'hand', + tags: ['length','horse measurement','hand'] + }, + { + name: 'unit.chain', + symbol: 'ch', + tags: ['length','land surveying','ch'] + }, + { + name: 'unit.furlong', + symbol: 'fur', + tags: ['length','land surveying','fur'] + }, + { + name: 'unit.league', + symbol: 'league', + tags: ['length','historical measurement','league'] + }, + { + name: 'unit.fathom', + symbol: 'fathom', + tags: ['depth','nautical measurement','fathom'] + }, + { + name: 'unit.cable', + symbol: 'cable', + tags: ['distance','nautical measurement','cable'] + }, + { + name: 'unit.link', + symbol: 'link', + tags: ['length','land surveying','link'] + }, + { + name: 'unit.rod', + symbol: 'rod', + tags: ['length','land surveying','rod'] + }, + { + name: 'unit.nanogram', + symbol: 'ng', + tags: ['mass','weight','heaviness','load','nanogram','nanograms','ng'] + }, + { + name: 'unit.microgram', + symbol: 'μg', + tags: ['mass','weight','heaviness','load','μg','microgram'] + }, + { + name: 'unit.milligram', + symbol: 'mg', + tags: ['mass','weight','heaviness','load','milligram','miligrams','mg'] + }, + { + name: 'unit.gram', + symbol: 'g', + tags: ['mass','weight','heaviness','load','gram','grams','g'] + }, + { + name: 'unit.kilogram', + symbol: 'kg', + tags: ['mass','weight','heaviness','load','kilogram','kilograms','kg'] + }, + { + name: 'unit.tonne', + symbol: 't', + tags: ['mass','weight','heaviness','load','tonne','tons','t'] + }, + { + name: 'unit.ounce', + symbol: 'oz', + tags: ['mass','weight','heaviness','load','ounce','ounces','oz'] + }, + { + name: 'unit.pound', + symbol: 'lb', + tags: ['mass','weight','heaviness','load','pound','pounds','lb'] + }, + { + name: 'unit.stone', + symbol: 'st', + tags: ['mass','weight','heaviness','load','stone','stones','st'] + }, + { + name: 'unit.hundredweight-count', + symbol: 'cwt', + tags: ['mass','weight','heaviness','load','hundredweight count','cwt'] + }, + { + name: 'unit.short-tons', + symbol: 'short tons', + tags: ['mass','weight','heaviness','load','short ton','short tons'] + }, + { + name: 'unit.dalton', + symbol: 'Da', + tags: ['atomic mass unit','AMU','unified atomic mass unit','dalton','Da'] + }, + { + name: 'unit.grain', + symbol: 'gr', + tags: ['mass','measurement','grain','gr'] + }, + { + name: 'unit.drachm', + symbol: 'dr', + tags: ['mass','measurement','drachm','dr'] + }, + { + name: 'unit.quarter', + symbol: 'qr', + tags: ['mass','measurement','quarter','qr'] + }, + { + name: 'unit.slug', + symbol: 'slug', + tags: ['mass','measurement','slug'] + }, + { + name: 'unit.carat', + symbol: 'ct', + tags: ['gemstone','pearl','jewelry','carat','ct'] + }, + { + name: 'unit.cubic-millimeter', + symbol: 'mm³', + tags: ['volume','capacity','extent','cubic millimeter','mm³'] + }, + { + name: 'unit.cubic-centimeter', + symbol: 'cm³', + tags: ['volume','capacity','extent','cubic centimeter','cubic centimeters','cm³'] + }, + { + name: 'unit.cubic-meter', + symbol: 'm³', + tags: ['volume','capacity','extent','cubic meter','cubic meters','m³'] + }, + { + name: 'unit.cubic-kilometer', + symbol: 'km³', + tags: ['volume','capacity','extent','cubic kilometer','cubic kilometers','km³'] + }, + { + name: 'unit.microliter', + symbol: 'µL', + tags: ['volume','liquid measurement','microliter','µL'] + }, + { + name: 'unit.milliliter', + symbol: 'mL', + tags: ['volume','capacity','extent','milliliter','milliliters','mL'] + }, + { + name: 'unit.liter', + symbol: 'l', + tags: ['volume','capacity','extent','liter','liters','l'] + }, + { + name: 'unit.hectoliter', + symbol: 'hl', + tags: ['volume','capacity','extent','hectoliter','hectoliters','hl'] + }, + { + name: 'unit.cubic-inch', + symbol: 'in³', + tags: ['volume','capacity','extent','cubic inch','cubic inches','in³'] + }, + { + name: 'unit.cubic-foot', + symbol: 'ft³', + tags: ['volume','capacity','extent','cubic foot','cubic feet','ft³'] + }, + { + name: 'unit.cubic-yard', + symbol: 'yd³', + tags: ['volume','capacity','extent','cubic yard','cubic yards','yd³'] + }, + { + name: 'unit.fluid-ounce', + symbol: 'fl-oz', + tags: ['volume','capacity','extent','fluid ounce','fluid ounces','fl-oz'] + }, + { + name: 'unit.pint', + symbol: 'pt', + tags: ['volume','capacity','extent','pint','pints','pt'] + }, + { + name: 'unit.quart', + symbol: 'qt', + tags: ['volume','capacity','extent','quart','quarts','qt'] + }, + { + name: 'unit.gallon', + symbol: 'gal', + tags: ['volume','capacity','extent','gallon','gallons','gal'] + }, + { + name: 'unit.oil-barrels', + symbol: 'bbl', + tags: ['volume','capacity','extent','oil barrel','oil barrels','bbl'] + }, + { + name: 'unit.cubic-meter-per-kilogram', + symbol: 'm³/kg', + tags: ['specific volume','volume per unit mass','cubic meter per kilogram','m³/kg'] + }, + { + name: 'unit.gill', + symbol: 'gi', + tags: ['volume','liquid measurement','gi'] + }, + { + name: 'unit.hogshead', + symbol: 'hhd', + tags: ['volume','liquid measurement','hhd'] + }, + { + name: 'unit.teaspoon', + symbol: 'tsp', + tags: ['volume','cooking measurement','tsp'] + }, + { + name: 'unit.tablespoon', + symbol: 'tbsp', + tags: ['volume','cooking measurement','tbsp'] + }, + { + name: 'unit.cup', + symbol: 'cup', + tags: ['volume','cooking measurement','cup'] + }, { name: 'unit.celsius', symbol: '°C', - tags: ['temperature'] + tags: ['temperature','heat','cold','warmth','degrees','celsius','shipment condition','°C'] + }, + { + name: 'unit.kelvin', + symbol: 'K', + tags: ['temperature','heat','cold','warmth','degrees','kelvin','K','color quality','white balance','color temperature'] + }, + { + name: 'unit.rankine', + symbol: '°R', + tags: ['temperature','heat','cold','warmth','Rankine','°R'] + }, + { + name: 'unit.fahrenheit', + symbol: '°F', + tags: ['temperature','heat','cold','warmth','degrees','fahrenheit','°F'] + }, + { + name: 'unit.meter-per-second', + symbol: 'm/s', + tags: ['speed','velocity','pace','meter per second','m/s','peak','peak to peak','root mean square (RMS)', + 'vibration','wind speed','weather'] + }, + { + name: 'unit.kilometer-per-hour', + symbol: 'km/h', + tags: ['speed','velocity','pace','kilometer per hour','km/h'] + }, + { + name: 'unit.foot-per-second', + symbol: 'ft/s', + tags: ['speed','velocity','pace','foot per second','ft/s'] + }, + { + name: 'unit.mile-per-hour', + symbol: 'mph', + tags: ['speed','velocity','pace','mile per hour','mph'] + }, + { + name: 'unit.knot', + symbol: 'kt', + tags: ['speed','velocity','pace','knot','knots','kt'] + }, + { + name: 'unit.millimeters-per-minute', + symbol: 'mm/min', + tags: ['feed rate','cutting feed rate','millimeters per minute','mm/min'] + }, + { + name: 'unit.kilometer-per-hour-squared', + symbol: 'km/h²', + tags: ['acceleration','rate of change of velocity','kilometer per hour squared','km/h²'] + }, + { + name: 'unit.foot-per-second-squared', + symbol: 'ft/s²', + tags: ['acceleration','rate of change of velocity','foot per second squared','ft/s²'] + }, + { + name: 'unit.pascal', + symbol: 'Pa', + tags: ['pressure','force','compression','tension','pascal','pascals','Pa','atmospheric pressure','air pressure', + 'weather','altitude','flight'] + }, + { + name: 'unit.kilopascal', + symbol: 'kPa', + tags: ['pressure','force','compression','tension','kilopascal','kilopascals','kPa'] + }, + { + name: 'unit.megapascal', + symbol: 'MPa', + tags: ['pressure','force','compression','tension','megapascal','megapascals','MPa'] + }, + { + name: 'unit.gigapascal', + symbol: 'GPa', + tags: ['pressure','force','compression','tension','gigapascal','gigapascals','GPa'] + }, + { + name: 'unit.millibar', + symbol: 'mbar', + tags: ['pressure','force','compression','tension','millibar','millibars','mbar'] + }, + { + name: 'unit.bar', + symbol: 'bar', + tags: ['pressure','force','compression','tension','bar','bars'] + }, + { + name: 'unit.kilobar', + symbol: 'kbar', + tags: ['pressure','force','compression','tension','kilobar','kilobars','kbar'] + }, + { + name: 'unit.newton', + symbol: 'N', + tags: ['force','pressure','newton','newtons','N','push','pull','weight','gravity','N'] + }, + { + name: 'unit.newton-meter', + symbol: 'Nm', + tags: ['torque','rotational force','newton meter','Nm'] + }, + { + name: 'unit.foot-pounds', + symbol: 'ft·lbf', + tags: ['torque','rotational force','foot-pound','foot-pounds','ft·lbf'] + }, + { + name: 'unit.inch-pounds', + symbol: 'in·lbf', + tags: ['torque','rotational force','inch-pounds','inch-pound','in·lbf'] + }, + { + name: 'unit.newton-per-meter', + symbol: 'N/m', + tags: ['linear density','force per unit length','newton per meter','N/m'] + }, + { + name: 'unit.atmospheres', + symbol: 'atm', + tags: ['pressure','force','compression','tension','atmosphere','atmospheres','atmospheric pressure','atm'] + }, + { + name: 'unit.pounds-per-square-inch', + symbol: 'psi', + tags: ['pressure','force','compression','tension','pounds per square inch','psi'] + }, + { + name: 'unit.torr', + symbol: 'Torr', + tags: ['pressure','force','compression','tension','vacuum pressure','torr'] + }, + { + name: 'unit.inches-of-mercury', + symbol: 'inHg', + tags: ['pressure','force','compression','tension','vacuum pressure','inHg','atmospheric pressure','barometric pressure'] + }, + { + name: 'unit.pascal-per-square-meter', + symbol: 'Pa/m²', + tags: ['pressure','stress','mechanical strength','pascal per square meter','Pa/m²'] + }, + { + name: 'unit.pound-per-square-inch', + symbol: 'psi/in²', + tags: ['pressure','stress','mechanical strength','pound per square inch','psi/in²'] + }, + { + name: 'unit.newton-per-square-meter', + symbol: 'N/m²', + tags: ['pressure','stress','mechanical strength','newton per square meter','N/m²'] + }, + { + name: 'unit.kilogram-force-per-square-meter', + symbol: 'kgf/m²', + tags: ['pressure','stress','mechanical strength','kilogram-force per square meter','kgf/m²'] + }, + { + name: 'unit.pascal-per-square-centimeter', + symbol: 'Pa/cm²', + tags: ['pressure','stress','mechanical strength','pascal per square centimeter','Pa/cm²'] + }, + { + name: 'unit.ton-force-per-square-inch', + symbol: 'tonf/in²', + tags: ['pressure','stress','mechanical strength','ton-force per square inch','tonf/in²'] + }, + { + name: 'unit.kilonewton-per-square-meter', + symbol: 'kN/m²', + tags: ['stress','pressure','mechanical strength','kilonewton per square meter','kN/m²'] + }, + { + name: 'unit.newton-per-square-millimeter', + symbol: 'N/mm²', + tags: ['stress','pressure','mechanical strength','newton per square millimeter','N/mm²'] + }, + { + name: 'unit.microjoule', + symbol: 'μJ', + tags: ['energy','microjoule','microjoules','μJ'] + }, + { + name: 'unit.millijoule', + symbol: 'mJ', + tags: ['energy','millijoule','millijoules','mJ'] + }, + { + name: 'unit.joule', + symbol: 'J', + tags: ['joule','joules','energy','work done','heat','electricity','mechanical work'] + }, + { + name: 'unit.kilojoule', + symbol: 'kJ', + tags: ['energy','kilojoule','kilojoules','kJ'] + }, + { + name: 'unit.megajoule', + symbol: 'MJ', + tags: ['energy','megajoule','megajoules','MJ'] + }, + { + name: 'unit.gigajoule', + symbol: 'GJ', + tags: ['energy','gigajoule','gigajoules','GJ'] + }, + { + name: 'unit.watt-hour', + symbol: 'Wh', + tags: ['energy','watt-hour','watt-hours','energy usage','power consumption','energy consumption','electricity usage'] + }, + { + name: 'unit.kilowatt-hour', + symbol: 'kWh', + tags: ['energy','kilowatt-hour','kilowatt-hours','energy usage','power consumption','energy consumption','electricity usage'] + }, + { + name: 'unit.electron-volts', + symbol: 'eV', + tags: ['energy','subatomic particles','radiation'] + }, + { + name: 'unit.joules-per-coulomb', + symbol: 'J/C', + tags: ['electrical potential energy','voltage','joules per coulomb','J/C'] + }, + { + name: 'unit.british-thermal-unit', + symbol: 'BTU', + tags: ['energy','heat','work done','british thermal unit','british thermal units','BTU'] + }, + { + name: 'unit.foot-pound', + symbol: 'ft·lb', + tags: ['energy','foot-pound','foot-pounds','ft·lb','ft⋅lbf'] + }, + { + name: 'unit.calorie', + symbol: 'Cal', + tags: ['energy','food energy','Calorie','Calories','Cal'] + }, + { + name: 'unit.small-calorie', + symbol: 'cal', + tags: ['energy','small calorie','calories','cal'] + }, + { + name: 'unit.kilocalorie', + symbol: 'kcal', + tags: ['energy','small calorie','kilocalories','kcal'] + }, + { + name: 'unit.joule-per-kelvin', + symbol: 'J/K', + tags: ['specific heat capacity','heat capacity per unit temperature','joule per kelvin','J/K'] + }, + { + name: 'unit.joule-per-kilogram-kelvin', + symbol: 'J/(kg·K)', + tags: ['specific heat capacity','heat capacity per unit mass and temperature','joule per kilogram-kelvin','J/(kg·K)'] + }, + { + name: 'unit.joule-per-kilogram', + symbol: 'J/kg', + tags: ['specific energy','specific energy capacity','joule per kilogram','J/kg'] + }, + { + name: 'unit.watt-per-meter-kelvin', + symbol: 'W/(m·K)', + tags: ['thermal conductivity','watt per meter-kelvin','W/(m·K)'] + }, + { + name: 'unit.joule-per-cubic-meter', + symbol: 'J/m³', + tags: ['energy density','joule per cubic meter','J/m³'] + }, + { + name: 'unit.therm', + symbol: 'thm', + tags: ['energy','natural gas consumption','BTU','therm','thm'] + }, + { + name: 'unit.electric-dipole-moment', + symbol: 'C·m', + tags: ['electric dipole','dipole moment','coulomb meter','C·m'] + }, + { + name: 'unit.magnetic-dipole-moment', + symbol: 'A·m²', + tags: ['magnetic dipole','dipole moment','ampere square meter','A·m²'] + }, + { + name: 'unit.debye', + symbol: 'D', + tags: ['polarization','electric dipole moment','debye','D'] + }, + { + name: 'unit.coulomb-per-square-meter-per-volt', + symbol: 'C·m²/V', + tags: ['polarization','electric field','coulomb per square meter per volt','C·m²/V'] + }, + { + name: 'unit.milliwatt', + symbol: 'mW', + tags: ['power','horsepower','performance','milliwatt','milliwatts','electricity','mW'] + }, + { + name: 'unit.microwatt', + symbol: 'μW', + tags: ['power','horsepower','performance','microwatt','microwatts','electricity','μW'] + }, + { + name: 'unit.watt', + symbol: 'W', + tags: ['power','horsepower','performance','watt','watts','electricity','W'] + }, + { + name: 'unit.kilowatt', + symbol: 'kW', + tags: ['power','horsepower','performance','kilowatt','kilowatts','electricity','kW'] + }, + { + name: 'unit.megawatt', + symbol: 'MW', + tags: ['power','horsepower','performance','megawatt','megawatts','electricity','MW'] + }, + { + name: 'unit.gigawatt', + symbol: 'GW', + tags: ['power','horsepower','performance','gigawatt','gigawatts','electricity','GW'] + }, + { + name: 'unit.metric-horsepower', + symbol: 'PS', + tags: ['power','performance','metric horsepower','PS'] + }, + { + name: 'unit.milliwatt-per-square-centimeter', + symbol: 'mW/cm²', + tags: ['power density','radiation intensity','sunlight intensity','signal power','intensity', + 'milliwatts per square centimeter','UV Intensity','mW/cm²'] + }, + { + name: 'unit.watt-per-square-centimeter', + symbol: 'W/cm²', + tags: ['power density','intensity of power','watts per square centimeter','W/cm²'] + }, + { + name: 'unit.kilowatt-per-square-centimeter', + symbol: 'kW/cm²', + tags: ['power density','intensity of power','kilowatts per square centimeter','kW/cm²'] + }, + { + name: 'unit.milliwatt-per-square-meter', + symbol: 'mW/m²', + tags: ['power density','intensity of power','milliwatts per square meter','mW/m²'] + }, + { + name: 'unit.watt-per-square-meter', + symbol: 'W/m²', + tags: ['power density','intensity of power','watts per square meter','W/m²'] + }, + { + name: 'unit.kilowatt-per-square-meter', + symbol: 'kW/m²', + tags: ['power density','intensity of power','kilowatts per square meter','kW/m²'] + }, + { + name: 'unit.watt-per-square-inch', + symbol: 'W/in²', + tags: ['power density','intensity of power','watts per square inch','W/in²'] + }, + { + name: 'unit.kilowatt-per-square-inch', + symbol: 'kW/in²', + tags: ['power density','intensity of power','kilowatts per square inch','kW/in²'] + }, + { + name: 'unit.horsepower', + symbol: 'hp', + tags: ['power','horsepower','performance','electricity','horsepowers','hp'] + }, + { + name: 'unit.btu-per-hour', + symbol: 'BTU/h', + tags: ['power','heat transfer','thermal energy','HVAC','BTU/h'] + }, + { + name: 'unit.coulomb', + symbol: 'C', + tags: ['charge','electricity','electrostatics','Coulomb','C'] + }, + { + name: 'unit.millicoulomb', + symbol: 'mC', + tags: ['charge','electricity','electrostatics','millicoulombs','mC'] + }, + { + name: 'unit.microcoulomb', + symbol: 'µC', + tags: ['charge','electricity','electrostatics','microcoulomb','µC'] + }, + { + name: 'unit.picocoulomb', + symbol: 'pC', + tags: ['charge','electricity','electrostatics','picocoulomb','pC'] + }, + { + name: 'unit.coulomb-per-meter', + symbol: 'C/m', + tags: ['electric displacement field per length','coulomb per meter','C/m'] + }, + { + name: 'unit.coulomb-per-cubic-meter', + symbol: 'C/m³', + tags: ['electric charge density','coulomb per cubic meter','C/m³'] + }, + { + name: 'unit.coulomb-per-square-meter', + symbol: 'C/m²', + tags: ['electric surface charge density','coulomb per square meter','C/m²'] + }, + { + name: 'unit.square-millimeter', + symbol: 'mm²', + tags: ['area','lot','zone','space','region','square millimeter','square millimeters','mm²','sq-mm'] + }, + { + name: 'unit.square-centimeter', + symbol: 'cm²', + tags: ['area','lot','zone','space','region','square centimeter','square centimeters','cm²','sq-cm'] + }, + { + name: 'unit.square-meter', + symbol: 'm²', + tags: ['area','lot','zone','space','region','square meter','square meters','m²','sq-m'] + }, + { + name: 'unit.hectare', + symbol: 'ha', + tags: ['area','lot','zone','space','region','hectare','hectares','ha'] + }, + { + name: 'unit.square-kilometer', + symbol: 'km²', + tags: ['area','lot','zone','space','region','square kilometer','square kilometers','km²','sq-km'] + }, + { + name: 'unit.square-inch', + symbol: 'in²', + tags: ['area','lot','zone','space','region','square inch','square inches','in²','sq-in'] + }, + { + name: 'unit.square-foot', + symbol: 'ft²', + tags: ['area','lot','zone','space','region','square foot','square feet','ft²','sq-ft'] + }, + { + name: 'unit.square-yard', + symbol: 'yd²', + tags: ['area','lot','zone','space','region','square yard','square yards','yd²','sq-yd'] + }, + { + name: 'unit.acre', + symbol: 'a', + tags: ['area','lot','zone','space','region','acre','acres','a'] + }, + { + name: 'unit.square-mile', + symbol: 'ml²', + tags: ['area','lot','zone','space','region','square mile','square miles','ml²','sq-mi'] + }, + { + name: 'unit.are', + symbol: 'are', + tags: ['area','land measurement','are'] + }, + { + name: 'unit.barn', + symbol: 'barn', + tags: ['cross-sectional area','particle physics','nuclear physics','barn'] + }, + { + name: 'unit.circular-inch', + symbol: 'circin', + tags: ['area','circular measurement','circular inch','circin'] + }, + { + name: 'unit.milliampere-hour', + symbol: 'mAh', + tags: ['electric current','current flow','electric charge','current capacity','flow of electricity', + 'electrical flow','milliampere-hour','milliampere-hours','mAh'] + }, + { + name: 'unit.ampere-hours', + symbol: 'Ah', + tags: ['electric current','current flow','electric charge','current capacity','flow of electricity', + 'electrical flow','ampere','ampere-hours','Ah'] + }, + { + name: 'unit.kiloampere-hours', + symbol: 'kAh', + tags: ['electric current','current flow','electric charge','current capacity','flow of electricity','electrical flow', + 'kiloampere-hours','kiloampere-hour','kAh'] + }, + { + name: 'unit.nanoampere', + symbol: 'nA', + tags: ['current','amperes','nanoampere','nA'] + }, + { + name: 'unit.picoampere', + symbol: 'pA', + tags: ['current','amperes','picoampere','pA'] + }, + { + name: 'unit.microampere', + symbol: 'μA', + tags: ['electric current','microampere','microamperes','μA'] + }, + { + name: 'unit.milliampere', + symbol: 'mA', + tags: ['electric current','milliampere','milliamperes','mA'] + }, + { + name: 'unit.ampere', + symbol: 'A', + tags: ['electric current','current flow','flow of electricity','electrical flow','ampere','amperes','amperage','A'] + }, + { + name: 'unit.kiloamperes', + symbol: 'kA', + tags: ['electric current','current flow','kiloamperes','kA'] + }, + { + name: 'unit.microampere-per-square-centimeter', + symbol: 'µA/cm²', + tags: ['Current density','microampere per square centimeter','µA/cm²'] + }, + { + name: 'unit.ampere-per-square-meter', + symbol: 'A/m²', + tags: ['current density','current per unit area','ampere per square meter','A/m²'] + }, + { + name: 'unit.ampere-per-meter', + symbol: 'A/m', + tags: ['magnetic field strength','magnetic field intensity','ampere per meter','A/m'] + }, + { + name: 'unit.oersted', + symbol: 'Oe', + tags: ['magnetic field','oersted','Oe'] + }, + { + name: 'unit.bohr-magneton', + symbol: 'μB', + tags: ['atomic physics','magnetic moment','bohr magneton','μB'] + }, + { + name: 'unit.ampere-meter-squared', + symbol: 'A·m²', + tags: ['magnetic moment','dipole moment','ampere-meter squared','A·m²'] + }, + { + name: 'unit.ampere-meter', + symbol: 'A·m', + tags: ['magnetic field','current loop','ampere-meter','A·m'] + }, + { + name: 'unit.nanovolt', + symbol: 'nV', + tags: ['voltage','volts','nanovolt','nV'] + }, + { + name: 'unit.picovolt', + symbol: 'pV', + tags: ['voltage','volts','picovolt','pV'] + }, + { + name: 'unit.millivolts', + symbol: 'mV', + tags: ['electric potential','electric tension','voltage','millivolt','millivolts','mV'] + }, + { + name: 'unit.microvolts', + symbol: 'μV', + tags: ['electric potential','electric tension','voltage','microvolt','microvolts','μV'] + }, + { + name: 'unit.volt', + symbol: 'V', + tags: ['electric potential','electric tension','voltage','volt','volts','V','power source','battery','battery level'] + }, + { + name: 'unit.kilovolts', + symbol: 'kV', + tags: ['electric potential','electric tension','voltage','kilovolt','kilovolts','kV'] + }, + { + name: 'unit.dbmV', + symbol: 'dBmV', + tags: ['decibels millivolt','voltage level','signal','dBmV'] + }, + { + name: 'unit.volt-meter', + symbol: 'V·m', + tags: ['electric flux','volt-meter','V·m'] + }, + { + name: 'unit.kilovolt-meter', + symbol: 'kV·m', + tags: ['electric flux','kilovolt-meter','kV·m'] + }, + { + name: 'unit.megavolt-meter', + symbol: 'MV·m', + tags: ['electric flux','megavolt-meter','MV·m'] + }, + { + name: 'unit.microvolt-meter', + symbol: 'µV·m', + tags: ['electric flux','microvolt-meter','µV·m'] + }, + { + name: 'unit.millivolt-meter', + symbol: 'mV·m', + tags: ['electric flux','millivolt-meter','mV·m'] + }, + { + name: 'unit.nanovolt-meter', + symbol: 'nV·m', + tags: ['electric flux','nanovolt-meter','nV·m'] + }, + { + name: 'unit.ohm', + symbol: 'Ω', + tags: ['electrical resistance','resistance','impedance','ohm'] + }, + { + name: 'unit.microohm', + symbol: 'μΩ', + tags: ['electrical resistance','resistance','microohm','μΩ'] + }, + { + name: 'unit.milliohm', + symbol: 'mΩ', + tags: ['electrical resistance','resistance','milliohm','mΩ'] + }, + { + name: 'unit.kilohm', + symbol: 'kΩ', + tags: ['electrical resistance','resistance','kilohm','kΩ'] + }, + { + name: 'unit.megohm', + symbol: 'MΩ', + tags: ['electrical resistance','resistance','megohm','MΩ'] + }, + { + name: 'unit.gigohm', + symbol: 'GΩ', + tags: ['electrical resistance','resistance','gigohm','GΩ'] + }, + { + name: 'unit.hertz', + symbol: 'Hz', + tags: ['frequency','cycles per second','hertz','Hz'] + }, + { + name: 'unit.kilohertz', + symbol: 'kHz', + tags: ['frequency','cycles per second','kilohertz','kHz'] + }, + { + name: 'unit.megahertz', + symbol: 'MHz', + tags: ['frequency','cycles per second','megahertz','MHz'] + }, + { + name: 'unit.gigahertz', + symbol: 'GHz', + tags: ['frequency','cycles per second','gigahertz','GHz'] + }, + { + name: 'unit.rpm', + symbol: 'RPM', + tags: ['speed','velocity','cycle','engine','Revolutions Per Minute','RPM','angular velocity','rotation speed'] + }, + { + name: 'unit.candela-per-square-meter', + symbol: 'cd/m²', + tags: ['brightness','light level','Luminance','Candela per square meter','cd/m²'] + }, + { + name: 'unit.candela', + symbol: 'cd', + tags: ['light intensity','candle power','luminous intensity','Candela','cd'] + }, + { + name: 'unit.lumen', + symbol: 'lm', + tags: ['total light output','light power','luminous flux','Lumen','lm'] + }, + { + name: 'unit.lux', + symbol: 'lx', + tags: ['illumination','light level on a surface','illuminance','Lux','lx'] + }, + { + name: 'unit.foot-candle', + symbol: 'fc', + tags: ['illuminance','light level','foot-candle','fc'] + }, + { + name: 'unit.lumen-per-square-meter', + symbol: 'lm/m²', + tags: ['illuminance','light level','lumen per square meter','lm/m²'] + }, + { + name: 'unit.lux-second', + symbol: 'lx·s', + tags: ['light exposure','illumination time','light dosage','Lux second','lx·s'] + }, + { + name: 'unit.lumen-second', + symbol: 'lm·s', + tags: ['total light energy','luminous energy','Lumen second','lm·s'] + }, + { + name: 'unit.lumens-per-watt', + symbol: 'lm/W', + tags: ['lighting efficiency','light output per energy','luminous efficacy','Lumens per watt','lm/W'] + }, + { + name: 'unit.absorbance', + symbol: 'AU', + tags: ['optical density','light absorption','absorbance','AU'] + }, + { + name: 'unit.mole', + symbol: 'mol', + tags: ['amount of substance','substance quantity','mole','moles','mol'] + }, + { + name: 'unit.nanomole', + symbol: 'nmol', + tags: ['amount of substance','substance quantity','concentration','nanomole','nmol'] + }, + { + name: 'unit.micromole', + symbol: 'μmol', + tags: ['amount of substance','substance quantity','micromole','μmol'] + }, + { + name: 'unit.millimole', + symbol: 'mmol', + tags: ['amount of substance','substance quantity','millimole','mmol'] + }, + { + name: 'unit.kilomole', + symbol: 'kmol', + tags: ['amount of substance','substance quantity','kilomole','kmol'] + }, + { + name: 'unit.mole-per-cubic-meter', + symbol: 'mol/m³', + tags: ['concentration','amount of substance','mole per cubic meter','mol/m³'] + }, + { + name: 'unit.battery', + symbol: '%', + tags: ['power source','state of charge (SoC)','battery','battery level','level','humidity','moisture', + 'relative humidity','water content','soil moisture','irrigation','water in soil','soil water content','VWC', + 'Volumetric Water Content','Total Harmonic Distortion','THD','power quality','UV Transmittance','%'] + }, + { + name: 'unit.rssi', + symbol: 'rssi', + tags: ['signal strength','signal level','received signal strength indicator','rssi','dBm'] + }, + { + name: 'unit.ppm', + symbol: 'ppm', + tags: ['carbon dioxide','co²','carbon monoxide','co','aqi','air quality','total volatile organic compounds','tvoc','ppm'] + }, + { + name: 'unit.ppb', + symbol: 'ppb', + tags: ['ozone','o³','nitrogen dioxide','no²','sulfur dioxide','so²','aqi','air quality','tvoc','ppb'] + }, + { + name: 'unit.micrograms-per-cubic-meter', + symbol: 'µg/m³', + tags: ['coarse particulate matter','pm10','fine particulate matter','pm2.5','aqi','air quality', + 'total volatile organic compounds','tvoc','micrograms per cubic meter','µg/m³'] + }, + { + name: 'unit.aqi', + symbol: 'aqi', + tags: ['AQI','air quality index'] + }, + { + name: 'unit.gram-per-cubic-meter', + symbol: 'g/m³', + tags: ['humidity','moisture','absolute humidity','g/m³'] + }, + { + name: 'unit.gram-per-kilogram', + symbol: 'g/kg', + tags: ['humidity','moisture','specific humidity','g/kg'] + }, + { + name: 'unit.millimeters-per-second', + symbol: 'mm/s', + tags: ['velocity','speed','rate of motion','peak','peak to peak','root mean square (RMS)','vibration','mm/s'] + }, + { + name: 'unit.neper', + symbol: 'Np', + tags: ['logarithmic unit','ratio','gain','loss','attenuation','neper','Np'] + }, + { + name: 'unit.bel', + symbol: 'B', + tags: ['logarithmic unit','power ratio','intensity ratio','bel','B'] + }, + { + name: 'unit.decibel', + symbol: 'dB', + tags: ['noise level','sound level','volume','acoustics','decibel','dB'] + }, + { + name: 'unit.meters-per-second-squared', + symbol: 'm/s²', + tags: ['peak','peak to peak','root mean square (RMS)','vibration','meters per second squared','m/s²'] + }, + { + name: 'unit.becquerel', + symbol: 'Bq', + tags: ['radioactivity','radiation','becquerel','Bq'] + }, + { + name: 'unit.curie', + symbol: 'Ci', + tags: ['radioactivity','radiation','curie','Ci'] + }, + { + name: 'unit.gray', + symbol: 'Gy', + tags: ['radiation dose','gray','Gy'] + }, + { + name: 'unit.sievert', + symbol: 'Sv', + tags: ['radiation dose','sievert','radiation dose equivalent2','Sv'] + }, + { + name: 'unit.roentgen', + symbol: 'R', + tags: ['radiation exposure','roentgen','R'] + }, + { + name: 'unit.cps', + symbol: 'cps', + tags: ['radiation detection','counts per second','cps'] + }, + { + name: 'unit.rad', + symbol: 'Rad', + tags: ['radiation dose','rad'] + }, + { + name: 'unit.rem', + symbol: 'Rem', + tags: ['radiation dose equivalent','rem'] + }, + { + name: 'unit.dps', + symbol: 'dps', + tags: ['radioactive decay','radioactivity','disintegrations per second','dps'] + }, + { + name: 'unit.rutherford', + symbol: 'Rd', + tags: ['radioactive decay','radioactivity','rutherford','Rd'] + }, + { + name: 'unit.coulombs-per-kilogram', + symbol: 'C/kg', + tags: ['radiation exposure','dose','coulombs per kilogram','electric charge-to-mass ratio','C/kg'] + }, + { + name: 'unit.becquerels-per-cubic-meter', + symbol: 'Bq/m³', + tags: ['radioactivity','radiation','becquerels per cubic meter','Bq/m³'] + }, + { + name: 'unit.curies-per-liter', + symbol: 'Ci/L', + tags: ['radioactivity','radiation','curies per liter','Ci/L'] + }, + { + name: 'unit.becquerels-per-second', + symbol: 'Bq/s', + tags: ['radioactive decay rate','becquerels per second','Bq/s'] + }, + { + name: 'unit.curies-per-second', + symbol: 'Ci/s', + tags: ['radioactive decay rate','curies per second','Ci/s'] + }, + { + name: 'unit.gy-per-second', + symbol: 'Gy/s', + tags: ['absorbed dose rate','radiation dose rate','gray per second','Gy/s'] + }, + { + name: 'unit.watt-per-steradian', + symbol: 'W/sr', + tags: ['radiant intensity','power per unit solid angle','watt per steradian','W/sr'] + }, + { + name: 'unit.watt-per-square-metre-steradian', + symbol: 'W/(m²·sr)', + tags: ['radiance','radiant flux density','watt per square metre-steradian','W/(m²·sr)'] + }, + { + name: 'unit.ph-level', + symbol: 'pH', + tags: ['acidity','alkalinity','neutral','acid','base','pH','soil pH','water quality','water pH'] + }, + { + name: 'unit.turbidity', + symbol: 'NTU', + tags: ['water turbidity','water clarity','Nephelometric Turbidity Units','NTU'] + }, + { + name: 'unit.mg-per-liter', + symbol: 'mg/L', + tags: ['dissolved oxygen','water quality','mg/L'] + }, + { + name: 'unit.microsiemens-per-centimeter', + symbol: 'µS/cm', + tags: ['Electrical conductivity','water quality','soil quality','microsiemens per centimeter','µS/cm'] + }, + { + name: 'unit.millisiemens-per-meter', + symbol: 'mS/m', + tags: ['Electrical conductivity','water quality','soil quality','millisiemens per meter','mS/m'] + }, + { + name: 'unit.siemens-per-meter', + symbol: 'S/m', + tags: ['Electrical conductivity','water quality','soil quality','siemens per meter','S/m'] + }, + { + name: 'unit.kilogram-per-cubic-meter', + symbol: 'kg/m³', + tags: ['density','mass per unit volume','kg/m³'] + }, + { + name: 'unit.gram-per-cubic-centimeter', + symbol: 'g/cm³', + tags: ['density','mass per unit volume','g/cm³'] + }, + { + name: 'unit.kilogram-per-square-meter', + symbol: 'kg/m²', + tags: ['density','surface density','areal density','mass per unit area','kg/m²'] + }, + { + name: 'unit.milligram-per-milliliter', + symbol: 'mg/mL', + tags: ['concentration','mass per volume','mg/mL'] + }, + { + name: 'unit.pound-per-cubic-foot', + symbol: 'lb/ft³', + tags: ['Density','mass per unit volume','lb/ft³'] + }, + { + name: 'unit.ounces-per-cubic-inch', + symbol: 'oz/in³', + tags: ['density','mass per unit volume','oz/in³'] + }, + { + name: 'unit.tons-per-cubic-yard', + symbol: 'ton/yd³', + tags: ['density','mass per unit volume','ton/yd³'] + }, + { + name: 'unit.particle-density', + symbol: 'particles/mL', + tags: ['particle concentration','count','particles/mL'] + }, + { + name: 'unit.kilometers-per-liter', + symbol: 'km/L', + tags: ['fuel efficiency','km/L'] + }, + { + name: 'unit.miles-per-gallon', + symbol: 'mpg', + tags: ['fuel efficiency','mpg'] + }, + { + name: 'unit.liters-per-100-km', + symbol: 'L/100km', + tags: ['fuel efficiency','L/100km'] + }, + { + name: 'unit.gallons-per-mile', + symbol: 'gal/mi', + tags: ['fuel efficiency','gal/mi'] + }, + { + name: 'unit.liters-per-hour', + symbol: 'L/hr', + tags: ['fuel consumption','L/hr'] }, { - name: 'unit.kelvin', - symbol: 'K', - tags: ['temperature'] + name: 'unit.gallons-per-hour', + symbol: 'gal/hr', + tags: ['fuel consumption','gal/hr'] }, { - name: 'unit.fahrenheit', - symbol: '°F', - tags: ['temperature'] + name: 'unit.beats-per-minute', + symbol: 'bpm', + tags: ['heart rate','pulse','bpm'] + }, + { + name: 'unit.millimeters-of-mercury', + symbol: 'mmHg', + tags: ['blood pressure','systolic','diastolic','mmHg'] + }, + { + name: 'unit.milligrams-per-deciliter', + symbol: 'mg/dL', + tags: ['glucose','blood sugar','glucose level','mg/dL'] + }, + { + name: 'unit.g-force', + symbol: 'G', + tags: ['acceleration','gravity','force','g-load','G'] + }, + { + name: 'unit.kilonewton', + symbol: 'kN', + tags: ['force','kN'] + }, + { + name: 'unit.kilogram-force', + symbol: 'kgf', + tags: ['force','kgf'] + }, + { + name: 'unit.pound-force', + symbol: 'lbf', + tags: ['force','lbf'] + }, + { + name: 'unit.kilopound-force', + symbol: 'klbf', + tags: ['force','klbf'] + }, + { + name: 'unit.dyne', + symbol: 'dyn', + tags: ['force','dyn'] + }, + { + name: 'unit.poundal', + symbol: 'pdl', + tags: ['force','pdl'] + }, + { + name: 'unit.kip', + symbol: 'kip', + tags: ['force','kip'] + }, + { + name: 'unit.gal', + symbol: 'Gal', + tags: ['acceleration','gravity','g-force','Gal'] + }, + { + name: 'unit.gravity', + symbol: 'gravity', + tags: ['acceleration','gravity','g-force'] + }, + { + name: 'unit.hectopascal', + symbol: 'hPa', + tags: ['atmospheric pressure','air pressure','weather','altitude','flight','hPa'] + }, + { + name: 'unit.atmosphere', + symbol: 'atm', + tags: ['atmospheric pressure','air pressure','weather','altitude','flight','atm'] + }, + { + name: 'unit.millibars', + symbol: 'mb', + tags: ['atmospheric pressure','air pressure','weather','altitude','flight','mb'] + }, + { + name: 'unit.inch-of-mercury', + symbol: 'inHg', + tags: ['atmospheric pressure','air pressure','weather','altitude','flight','inHg','richter'] + }, + { + name: 'unit.richter-scale', + symbol: 'richter', + tags: ['earthquake','seismic activity','richter'] }, { name: 'unit.percentage', @@ -44,17 +1482,562 @@ export const units: Array = [ { name: 'unit.second', symbol: 's', - tags: ['time'] + tags: ['time','duration','interval','angle','second','arcsecond','sec'] }, { name: 'unit.minute', symbol: 'min', - tags: ['time'] + tags: ['time','duration','interval','angle','minute','arcminute','min'] }, { name: 'unit.hour', symbol: 'h', - tags: ['time'] + tags: ['time','duration','interval','h'] + }, + { + name: 'unit.day', + symbol: 'd', + tags: ['time','duration','interval','d'] + }, + { + name: 'unit.week', + symbol: 'wk', + tags: ['time','duration','interval','wk'] + }, + { + name: 'unit.month', + symbol: 'mo', + tags: ['time','duration','interval','mo'] + }, + { + name: 'unit.year', + symbol: 'yr', + tags: ['time','duration','interval','yr'] + }, + { + name: 'unit.cubic-foot-per-minute', + symbol: 'ft³/min', + tags: ['airflow','ventilation','HVAC','gas flow rate','CFM','flow rate','fluid flow','cubic foot per minute','ft³/min'] + }, + { + name: 'unit.cubic-meters-per-hour', + symbol: 'm³/hr', + tags: ['airflow','ventilation','HVAC','gas flow rate','cubic meters per hour','m³/hr'] + }, + { + name: 'unit.cubic-meters-per-second', + symbol: 'm³/s', + tags: ['airflow','ventilation','HVAC','gas flow rate','cubic meters per second','m³/s'] + }, + { + name: 'unit.liter-per-second', + symbol: 'L/s', + tags: ['airflow','ventilation','HVAC','gas flow rate','liter per second','L/s'] + }, + { + name: 'unit.liter-per-minute', + symbol: 'L/min', + tags: ['airflow','ventilation','HVAC','gas flow rate','liter per minute','L/min'] + }, + { + name: 'unit.gallons-per-minute', + symbol: 'GPM', + tags: ['airflow','ventilation','HVAC','gas flow rate','gallons per minute','GPM'] + }, + { + name: 'unit.cubic-foot-per-second', + symbol: 'ft³/s', + tags: ['flow rate','fluid flow','cubic foot per second','cubic feet per second','ft³/s'] + }, + { + name: 'unit.milliliters-per-minute', + symbol: 'mL/min', + tags: ['Flow rate','fluid dynamics','milliliters per minute','mL/min'] + }, + { + name: 'unit.bit', + symbol: 'bit', + tags: ['data','binary digit','information','bit'] + }, + { + name: 'unit.byte', + symbol: 'B', + tags: ['data','byte','information','storage','memory','B'] + }, + { + name: 'unit.kilobyte', + symbol: 'KB', + tags: ['data','kilobyte','KB'] + }, + { + name: 'unit.megabyte', + symbol: 'MB', + tags: ['data','megabyte','MB'] + }, + { + name: 'unit.gigabyte', + symbol: 'GB', + tags: ['data','gigabyte','GB'] + }, + { + name: 'unit.terabyte', + symbol: 'TB', + tags: ['data','terabyte','TB'] + }, + { + name: 'unit.petabyte', + symbol: 'PB', + tags: ['data','petabyte','PB'] + }, + { + name: 'unit.exabyte', + symbol: 'EB', + tags: ['data','exabyte','EB'] + }, + { + name: 'unit.zettabyte', + symbol: 'ZB', + tags: ['data','zettabyte','ZB'] + }, + { + name: 'unit.yottabyte', + symbol: 'YB', + tags: ['data','yottabyte','YB'] + }, + { + name: 'unit.bit-per-second', + symbol: 'bps', + tags: ['data transfer rate','bps'] + }, + { + name: 'unit.kilobit-per-second', + symbol: 'kbps', + tags: ['data transfer rate','kbps'] + }, + { + name: 'unit.megabit-per-second', + symbol: 'Mbps', + tags: ['data transfer rate','Mbps'] + }, + { + name: 'unit.gigabit-per-second', + symbol: 'Gbps', + tags: ['data transfer rate','Gbps'] + }, + { + name: 'unit.terabit-per-second', + symbol: 'Tbps', + tags: ['data transfer rate','Tbps'] + }, + { + name: 'unit.byte-per-second', + symbol: 'B/s', + tags: ['data transfer rate','B/s'] + }, + { + name: 'unit.kilobyte-per-second', + symbol: 'KB/s', + tags: ['data transfer rate','KB/s'] + }, + { + name: 'unit.megabyte-per-second', + symbol: 'MB/s', + tags: ['data transfer rate','MB/s'] + }, + { + name: 'unit.gigabyte-per-second', + symbol: 'GB/s', + tags: ['data transfer rate','GB/s'] + }, + { + name: 'unit.degree', + symbol: 'deg', + tags: ['angle','degree','degrees','deg'] + }, + { + name: 'unit.radian', + symbol: 'rad', + tags: ['angle','radian','radians','rad'] + }, + { + name: 'unit.gradian', + symbol: 'grad', + tags: ['angle','gradian','grades','grad'] + }, + { + name: 'unit.mil', + symbol: 'mil', + tags: ['angle','military angle','angular mil','mil'] + }, + { + name: 'unit.revolution', + symbol: 'rev', + tags: ['angle','revolution','full circle','complete turn','rev'] + }, + { + name: 'unit.siemens', + symbol: 'S', + tags: ['electrical conductance','conductance','siemens','S'] + }, + { + name: 'unit.millisiemens', + symbol: 'mS', + tags: ['electrical conductance','conductance','millisiemens','mS'] + }, + { + name: 'unit.microsiemens', + symbol: 'μS', + tags: ['electrical conductance','conductance','microsiemens','μS'] + }, + { + name: 'unit.kilosiemens', + symbol: 'kS', + tags: ['electrical conductance','conductance','kilosiemens','kS'] + }, + { + name: 'unit.megasiemens', + symbol: 'MS', + tags: ['electrical conductance','conductance','megasiemens','MS'] + }, + { + name: 'unit.gigasiemens', + symbol: 'GS', + tags: ['electrical conductance','conductance','gigasiemens','GS'] + }, + { + name: 'unit.farad', + symbol: 'F', + tags: ['electric capacitance','capacitance','farad','F'] + }, + { + name: 'unit.millifarad', + symbol: 'mF', + tags: ['electric capacitance','capacitance','millifarad','mF'] + }, + { + name: 'unit.microfarad', + symbol: 'μF', + tags: ['electric capacitance','capacitance','microfarad','μF'] + }, + { + name: 'unit.nanofarad', + symbol: 'nF', + tags: ['electric capacitance','capacitance','nanofarad','nF'] + }, + { + name: 'unit.picofarad', + symbol: 'pF', + tags: ['electric capacitance','capacitance','picofarad','pF'] + }, + { + name: 'unit.kilofarad', + symbol: 'kF', + tags: ['electric capacitance','capacitance','kilofarad','kF'] + }, + { + name: 'unit.megafarad', + symbol: 'MF', + tags: ['electric capacitance','capacitance','megafarad','MF'] + }, + { + name: 'unit.gigafarad', + symbol: 'GF', + tags: ['electric capacitance','capacitance','gigafarad','GF'] + }, + { + name: 'unit.terfarad', + symbol: 'TF', + tags: ['electric capacitance','capacitance','terafarad','TF'] + }, + { + name: 'unit.farad-per-meter', + symbol: 'F/m', + tags: ['electric permittivity','farad per meter','F/m'] + }, + { + name: 'unit.tesla', + symbol: 'T', + tags: ['magnetic field','magnetic field strength','tesla','T','magnetic flux density'] + }, + { + name: 'unit.gauss', + symbol: 'G', + tags: ['magnetic field','magnetic field strength','gauss','G','magnetic flux density'] + }, + { + name: 'unit.kilogauss', + symbol: 'kG', + tags: ['magnetic field','magnetic field strength','kilogauss','kG','magnetic flux density'] + }, + { + name: 'unit.millitesla', + symbol: 'mT', + tags: ['magnetic field','magnetic field strength','millitesla','mT'] + }, + { + name: 'unit.microtesla', + symbol: 'μT', + tags: ['magnetic field','magnetic field strength','microtesla','μT'] + }, + { + name: 'unit.nanotesla', + symbol: 'nT', + tags: ['magnetic field','magnetic field strength','nanotesla','nT'] + }, + { + name: 'unit.kilotesla', + symbol: 'kT', + tags: ['magnetic field','magnetic field strength','kilotesla','kT'] + }, + { + name: 'unit.megatesla', + symbol: 'MT', + tags: ['magnetic field','magnetic field strength','megatesla','MT'] + }, + { + name: 'unit.millitesla-square-meters', + symbol: 'millitesla square meters', + tags: ['magnetic field','millitesla square meters'] + }, + { + name: 'unit.gamma', + symbol: 'γ', + tags: ['magnetic flux density','gamma','γ'] + }, + { + name: 'unit.lambda', + symbol: 'λ', + tags: ['wavelength','lambda','λ'] + }, + { + name: 'unit.square-meter-per-second', + symbol: 'm²/s', + tags: ['kinematic viscosity','m²/s'] + }, + { + name: 'unit.square-centimeter-per-second', + symbol: 'cm²/s', + tags: ['kinematic viscosity','cm²/s'] + }, + { + name: 'unit.stoke', + symbol: 'St', + tags: ['kinematic viscosity','stokes','St'] + }, + { + name: 'unit.centistokes', + symbol: 'cSt', + tags: ['kinematic viscosity','centistokes','cSt'] + }, + { + name: 'unit.square-foot-per-second', + symbol: 'ft²/s', + tags: ['kinematic viscosity','ft²/s'] + }, + { + name: 'unit.square-inch-per-second', + symbol: 'in²/s', + tags: ['kinematic viscosity','in²/s'] + }, + { + name: 'unit.pascal-second', + symbol: 'Pa·s', + tags: ['dynamic viscosity','viscosity','fluid mechanics','pascal-second','Pa·s'] + }, + { + name: 'unit.centipoise', + symbol: 'cP', + tags: ['viscosity','dynamic viscosity','fluid viscosity','centipoise','cP'] + }, + { + name: 'unit.poise', + symbol: 'P', + tags: ['viscosity','dynamic viscosity','fluid viscosity','poise','P'] + }, + { + name: 'unit.reynolds', + symbol: 'Re', + tags: ['fluid flow regime','fluid mechanics','reynolds','Re'] + }, + { + name: 'unit.pound-per-foot-hour', + symbol: 'lb/(ft·h)', + tags: ['pound per foot-hour','lb/(ft·h)'] + }, + { + name: 'unit.newton-second-per-square-meter', + symbol: 'N·s/m²', + tags: ['newton second per square meter','N·s/m²'] + }, + { + name: 'unit.dyne-second-per-square-centimeter', + symbol: 'dyn·s/cm²', + tags: ['dyne second per square centimeter','dyn·s/cm²'] + }, + { + name: 'unit.kilogram-per-meter-second', + symbol: 'kg/(m·s)', + tags: ['kilogram per meter-second','kg/(m·s)'] + }, + { + name: 'unit.tesla-square-meters', + symbol: 'T/m²', + tags: ['magnetic flux density','tesla square meters','T/m²'] + }, + { + name: 'unit.maxwell', + symbol: 'Mx', + tags: ['magnetic flux','magnetic field','maxwell','Mx'] + }, + { + name: 'unit.tesla-per-meter', + symbol: 'T/m', + tags: ['magnetic field','tesla per meter','T/m'] + }, + { + name: 'unit.gauss-per-centimeter', + symbol: 'G/cm', + tags: ['magnetic field','gauss per centimeter','G/cm'] + }, + { + name: 'unit.weber', + symbol: 'Wb', + tags: ['magnetic flux','weber','Wb'] + }, + { + name: 'unit.microweber', + symbol: 'µWb', + tags: ['magnetic flux','microweber','µWb'] + }, + { + name: 'unit.milliweber', + symbol: 'mWb', + tags: ['magnetic flux','milliweber','mWb'] + }, + { + name: 'unit.gauss-square-centimeter', + symbol: 'G·cm²', + tags: ['magnetic flux','gauss-square centimeter','G·cm²'] + }, + { + name: 'unit.kilogauss-square-centimeter', + symbol: 'kG·cm²', + tags: ['magnetic flux','kilogauss-square centimeter','kG·cm²'] + }, + { + name: 'unit.henry', + symbol: 'H', + tags: ['inductance','magnetic induction','H'] + }, + { + name: 'unit.millihenry', + symbol: 'mH', + tags: ['inductance','millihenry','mH'] + }, + { + name: 'unit.microhenry', + symbol: 'µH', + tags: ['inductance','microhenry','µH'] + }, + { + name: 'unit.nanohenry', + symbol: 'nH', + tags: ['inductance','nanohenry','nH'] + }, + { + name: 'unit.henry-per-meter', + symbol: 'H/m', + tags: ['magnetic permeability','henry per meter','H/m'] + }, + { + name: 'unit.tesla-meter-per-ampere', + symbol: 'T·m/A', + tags: ['magnetic field','Tesla Meter per Ampere','T·m/A','magnetic flux'] + }, + { + name: 'unit.gauss-per-oersted', + symbol: 'G/Oe', + tags: ['magnetic field','Gauss per Oersted','G/Oe'] + }, + { + name: 'unit.kilogram-per-mole', + symbol: 'kg/mol', + tags: ['molar mass','kilogram per mole','kg/mol'] + }, + { + name: 'unit.gram-per-mole', + symbol: 'g/mol', + tags: ['molar mass','gram per mole','g/mol'] + }, + { + name: 'unit.milligram-per-mole', + symbol: 'mg/mol', + tags: ['molar mass','milligram per mole','mg/mol'] + }, + { + name: 'unit.joule-per-mole', + symbol: 'J/mol', + tags: ['molar energy','joule per mole','J/mol'] + }, + { + name: 'unit.joule-per-mole-kelvin', + symbol: 'J/(mol·K)', + tags: ['molar heat capacity','joule per mole-kelvin','J/(mol·K)'] + }, + { + name: 'unit.millivolts-per-meter', + symbol: 'mV/m', + tags: ['electric field strength','millivolts per meter','mV/m'] + }, + { + name: 'unit.volts-per-meter', + symbol: 'V/m', + tags: ['electric field strength','volts per meter','V/m'] + }, + { + name: 'unit.kilovolts-per-meter', + symbol: 'kV/m', + tags: ['electric field strength','kilovolts per meter','kV/m'] + }, + { + name: 'unit.radian-per-second', + symbol: 'rad/s', + tags: ['angular velocity','rotation speed','rad/s'] + }, + { + name: 'unit.radian-per-second-squared', + symbol: 'rad/s²', + tags: ['angular acceleration','rotation rate of change','rad/s²'] + }, + { + name: 'unit.revolutions-per-minute-per-second', + symbol: 'rpm/s', + tags: ['angular acceleration','rotation rate of change','rpm/s'] + }, + { + name: 'unit.revolutions-per-minute-per-second-squared', + symbol: 'rpm/s²', + tags: ['angular acceleration','rotation rate of change','rpm/s²'] + }, + { + name: 'unit.deg-per-second', + symbol: 'deg/s', + tags: ['angular velocity','degrees per second','deg/s'] + }, + { + name: 'unit.degrees-brix', + symbol: '°Bx', + tags: ['sugar content','fruit ripeness','Bx'] + }, + { + name: 'unit.katal', + symbol: 'kat', + tags: ['catalytic activity','enzyme activity','kat'] + }, + { + name: 'unit.katal-per-cubic-metre', + symbol: 'kat/m³', + tags: ['catalytic activity concentration','enzyme concentration','kat/m³'] } ]; 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 82f10b7f4c..ffcea42d95 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3861,13 +3861,424 @@ "ago": "ago" }, "unit": { + "millimeter": "Millimeter", + "centimeter": "Centimeter", + "angstrom": "Angstrom", + "nanometer": "Nanometer", + "micrometer": "Micrometer", + "meter": "Meter", + "kilometer": "Kilometer", + "inch": "Inch", + "foot": "Foot", + "yard": "Yard", + "mile": "Mile", + "nautical-mile": "Nautical Mile", + "astronomical-unit": "Astronomical Unit", + "reciprocal-metre": "Reciprocal Metre", + "meter-per-meter": "Meter per meter", + "steradian": "Steradian", + "thou": "Thou", + "barleycorn": "Barleycorn", + "hand": "Hand", + "chain": "Chain", + "furlong": "Furlong", + "league": "League", + "fathom": "Fathom", + "cable": "Cable", + "link": "Link", + "rod": "Rod", + "nanogram": "Nanogram", + "microgram": "Microgram", + "milligram": "Milligram", + "gram": "Gram", + "kilogram": "Kilogram", + "tonne": "Tonne", + "ounce": "Ounce", + "pound": "Pound", + "stone": "Stone", + "hundredweight-count": "Hundredweight count", + "short-tons": "Short tons", + "dalton": "Dalton", + "grain": "Grain", + "drachm": "Drachm", + "quarter": "Quarter", + "slug": "Slug", + "carat": "Carat", + "cubic-millimeter": "Cubic Millimeter", + "cubic-centimeter": "Cubic Centimeter", + "cubic-meter": "Cubic Meter/s", + "cubic-kilometer": "Cubic Kilometers", + "microliter": "Microliter", + "milliliter": "Milliliter", + "liter": "Liter", + "hectoliter": "Hectolitre", + "cubic-inch": "Cubic Inch", + "cubic-foot": "Cubic Foot", + "cubic-yard": "Cubic Yards", + "fluid-ounce": "Fluid Ounce", + "pint": "Pint", + "quart": "Quart", + "gallon": "Gallon", + "oil-barrels": "Oil Barrels", + "cubic-meter-per-kilogram": "Cubic Meter per Kilogram", + "gill": "Gill", + "hogshead": "Hogshead", + "teaspoon": "Teaspoon", + "tablespoon": "Tablespoon", + "cup": "Cup", "celsius": "Celsius", "kelvin": "Kelvin", + "rankine": "Rankine", "fahrenheit": "Fahrenheit", "percentage": "Percentage", + "meter-per-second": "Meter per Second", + "kilometer-per-hour": "Kilometer per Hour", + "foot-per-second": "Foot per Second", + "mile-per-hour": "Mile per Hour", + "knot": "Knot", + "millimeters-per-minute": "Millimeters per minute", + "kilometer-per-hour-squared": "Kilometer per hour squared", + "foot-per-second-squared": "Foot per second squared", + "pascal": "Pascal", + "kilopascal": "Kilopascal", + "megapascal": "Megapascal", + "gigapascal": "Gigapascal", + "millibar": "Millibar", + "bar": "Bar", + "kilobar": "Kilobar", + "newton": "Newton", + "newton-meter": "Newton meter", + "foot-pounds": "Foot-pounds", + "inch-pounds": "Inch-pounds", + "newton-per-meter": "Newton per meter", + "atmospheres": "Atmospheres", + "pounds-per-square-inch": "Pounds per Square Inch", + "torr": "Torr", + "inches-of-mercury": "Inches of Mercury", + "pascal-per-square-meter": "Pascal per Square Meter", + "pound-per-square-inch": "Pound per Square Inch", + "newton-per-square-meter": "Newton per Square Meter", + "kilogram-force-per-square-meter": "Kilogram-force per Square Meter", + "pascal-per-square-centimeter": "Pascal per Square Centimeter", + "ton-force-per-square-inch": "Ton-force per Square Inch", + "kilonewton-per-square-meter": "Kilonewton per Square Meter", + "newton-per-square-millimeter": "Newton per Square Millimeter", + + "microjoule": "Microjoule", + "millijoule": "Millijoule", + "joule": "Joule", + "kilojoule": "Kilojoule", + "megajoule": "Megajoule", + "gigajoule": "Gigajoule", + "watt-hour": "Watt-hour", + "kilowatt-hour": "Kilowatt-hour", + "electron-volts": "Electron volts", + "joules-per-coulomb": "Joules per Coulomb", + "british-thermal-unit": "British Thermal Units", + "foot-pound": "Foot-pound", + "calorie": "Calorie", + "small-calorie": "Small Calorie", + "kilocalorie": "Kilocalorie", + "joule-per-kelvin": "Joule per Kelvin", + "joule-per-kilogram-kelvin": "Joule per Kilogram-Kelvin", + "joule-per-kilogram": "Joule per Kilogram", + "watt-per-meter-kelvin": "Watt per Meter-Kelvin", + "joule-per-cubic-meter": "Joule per Cubic Meter", + "therm": "Therm", + "electric-dipole-moment": "Electric Dipole Moment", + "magnetic-dipole-moment": "Magnetic Dipole Moment", + "debye": "Debye", + "coulomb-per-square-meter-per-volt": "Coulomb per Square Meter per Volt", + "milliwatt": "Milliwatt", + "microwatt": "Microwatt", + "watt": "Watt", + "kilowatt": "Kilowatt", + "megawatt": "Megawatt", + "gigawatt": "Gigawatt", + "metric-horsepower": "Metric Horsepower", + "milliwatt-per-square-centimeter": "Milliwatts per square centimeter", + "watt-per-square-centimeter": "Watts per square centimeter", + "kilowatt-per-square-centimeter": "Kilowatts per square centimeter", + "milliwatt-per-square-meter": "Milliwatts per square meter", + "watt-per-square-meter": "Watts per square meter", + "kilowatt-per-square-meter": "Kilowatts per square meter", + "watt-per-square-inch": "Watts per square inch", + "kilowatt-per-square-inch": "Kilowatts per square inch", + "horsepower": "Horsepower", + "btu-per-hour": "British thermal units/hour", + "coulomb": "Coulomb", + "millicoulomb": "Millicoulombs", + "microcoulomb": "Microcoulomb", + "picocoulomb": "Picocoulomb", + "coulomb-per-meter": "Coulomb per meter", + "coulomb-per-cubic-meter": "Coulomb per Cubic Meter", + "coulomb-per-square-meter": "Coulomb per Square Meter", + "square-millimeter": "Square Millimeter", + "square-centimeter": "Square Centimeter", + "square-meter": "Square Meter", + "hectare": "Hectare", + "square-kilometer": "Square Kilometer", + "square-inch": "Square Inch", + "square-foot": "Square Foot", + "square-yard": "Square Yard", + "acre": "Acre", + "square-mile": "Square Mile", + "are": "Are", + "barn": "Barn", + "circular-inch": "Circular Inch", + "milliampere-hour": "Milliampere-hour", + "milliampere-hour-tags": "electric current, current flow, electric charge, current capacity, flow of electricity, electrical flow, milliampere-hour, milliampere-hours, mAh", + "ampere-hours": "Ampere-hours", + "ampere-hours-tags": "electric current, current flow, electric charge, current capacity, flow of electricity, electrical flow, ampere, ampere-hours, Ah", + "kiloampere-hours": "Kiloampere-hours", + "kiloampere-hours-tags": "electric current, current flow, electric charge, current capacity, flow of electricity, electrical flow, kiloampere-hours, kiloampere-hour, kAh", + "nanoampere": "Nanoampere", + "nanoampere-tags": "current, amperes, nanoampere, nA", + "picoampere": "Picoampere", + "picoampere-tags": "current, amperes, picoampere, pA", + "microampere": "Microampere", + "microampere-tags": "electric current, microampere, microamperes, μA", + "milliampere": "Milliampere", + "milliampere-tags": "electric current, milliampere, milliamperes, mA", + "ampere": "Ampere", + "ampere-tags": "electric current, current flow, flow of electricity, electrical flow, ampere, amperes, amperage, A", + "kiloamperes": "Kiloamperes", + "kiloamperes-tags": "electric current, current flow, kiloamperes, kA", + "microampere-per-square-centimeter": "Microampere per square centimeter", + "microampere-per-square-centimeter-tags": "Current density, microampere per square centimeter, µA/cm²", + "ampere-per-square-meter": "Ampere per Square Meter", + "ampere-per-square-meter-tags": "current density, current per unit area, ampere per square meter, A/m²", + "ampere-per-meter": "Ampere per Meter", + "ampere-per-meter-tags": "magnetic field strength, magnetic field intensity, ampere per meter, A/m", + "oersted": "Oersted", + "oersted-tags": "magnetic field, oersted, Oe", + "bohr-magneton": "Bohr Magneton", + "bohr-magneton-tags": "atomic physics, magnetic moment, bohr magneton, μB", + "ampere-meter-squared": "Ampere-Meter Squared", + "ampere-meter-squared-tags": "magnetic moment, dipole moment, ampere-meter squared, A·m²", + "ampere-meter": "Ampere-Meter", + "ampere-meter-tags": "magnetic field, current loop, ampere-meter, A·m", + "nanovolt": "Nanovolt", + "picovolt": "Picovolt", + "millivolts": "Millivolts", + "microvolts": "Microvolts", + "volt": "Volt", + "kilovolts": "Kilovolts", + "dbmV": "dBmV", + "volt-meter": "Volt-Meter", + "kilovolt-meter": "Kilovolt-Meter", + "megavolt-meter": "Megavolt-Meter", + "microvolt-meter": "Microvolt-Meter", + "millivolt-meter": "Millivolt-Meter", + "nanovolt-meter": "Nanovolt-Meter", + "ohm": "Ohm", + "microohm": "Microohm", + "milliohm": "Milliohm", + "kilohm": "Kilohm", + "megohm": "Megohm", + "gigohm": "Gigohm", + "hertz": "Hertz", + "kilohertz": "Kilohertz", + "megahertz": "Megahertz", + "gigahertz": "Gigahertz", + "rpm": "Revolutions Per Minute", + "candela-per-square-meter": "Candela per square meter", + "candela": "Candela", + "lumen": "Lumen", + "lux": "Lux", + "foot-candle": "Foot-candle", + "lumen-per-square-meter": "Lumen per square meter", + "lux-second": "Lux second", + "lumen-second": "Lumen second", + "lumens-per-watt": "Lumens per watt", + "absorbance": "Absorbance", + "mole": "Mole", + "nanomole": "Nanomole", + "micromole": "MicroMole", + "millimole": "Millimole", + "kilomole": "Kilomole", + "mole-per-cubic-meter": "Mole per Cubic Meter", + "battery": "Battery", + "rssi": "RSSI", + "ppm": "Parts Per Million", + "ppb": "Parts Per Billion", + "micrograms-per-cubic-meter": "Micrograms per Cubic Meter", + "aqi": "AQI", + "gram-per-cubic-meter": "Gram per cubic meter", + "gram-per-kilogram": "Specific Humidity", + "millimeters-per-second": "Millimeters per second", + "neper": "Neper", + "bel": "Bel", + "decibel": "Decibel", + "meters-per-second-squared": "Meters per second squared", + "becquerel": "Becquerel", + "curie": "Curie", + "gray": "Gray", + "sievert": "Sievert", + "roentgen": "Roentgen", + "cps": "Counts per Second", + "rad": "Rad", + "rem": "Rem", + "dps": "Disintegrations per second", + "rutherford": "Rutherford", + "coulombs-per-kilogram": "Coulombs per kilogram", + "becquerels-per-cubic-meter": "Becquerels per cubic meter", + "curies-per-liter": "Curies per liter", + "becquerels-per-second": "Becquerels per second", + "curies-per-second": "Curies per second", + "gy-per-second": "Gray per Second", + "watt-per-steradian": "Watt per Steradian", + "watt-per-square-metre-steradian": "Watt per Square Metre-Steradian", + "ph-level": "pH Level", + "turbidity": "Turbidity", + "mg-per-liter": "Milligrams per liter", + "microsiemens-per-centimeter": "Microsiemens per centimeter", + "millisiemens-per-meter": "Millisiemens per meter", + "siemens-per-meter": "Siemens per meter", + "kilogram-per-cubic-meter": "Kilogram per cubic meter", + "gram-per-cubic-centimeter": "Gram per cubic centimeter", + "kilogram-per-square-meter": "Kilogram per square metre", + "milligram-per-milliliter": "Milligram per milliliter", + "pound-per-cubic-foot": "Pound per cubic foot", + "ounces-per-cubic-inch": "Ounces per cubic inch", + "tons-per-cubic-yard": "Tons per cubic yard", + "particle-density": "Particle density", + "kilometers-per-liter": "Kilometers per liter", + "miles-per-gallon": "Miles per gallon", + "liters-per-100-km": "Liters per 100 km", + "gallons-per-mile": "Gallons per mile", + "liters-per-hour": "Liters per hour", + "gallons-per-hour": "Gallons per hour", + "beats-per-minute": "Beats per minute", + "millimeters-of-mercury": "Millimeters of mercury", + "milligrams-per-deciliter": "Milligrams per deciliter", + "g-force": "G-force", + "kilonewton": "Kilonewton", + "kilogram-force": "Kilogram-Force", + "pound-force": "Pound-Force", + "kilopound-force": "Kilopound-Force", + "dyne": "Dyne", + "poundal": "Poundal", + "kip": "Kip", + "gal": "Gal", + "gravity": "Gravity", + "hectopascal": "Hectopascal", + "atmosphere": "Atmosphere", + "millibars": "Millibars", + "inch-of-mercury": "One inch of mercury", + "richter-scale": "Richter Scale", "second": "Second", "minute": "Minute", - "hour": "Hour" + "hour": "Hour", + "day": "Day", + "week": "Week", + "month": "Month", + "year": "Year", + "cubic-foot-per-minute": "Cubic Foot Per Minute", + "cubic-meters-per-hour": "Cubic Meters Per Hour", + "cubic-meters-per-second": "Cubic Meters Per Second", + "liter-per-second": "Liter Per Second", + "liter-per-minute": "Liter Per Minute", + "gallons-per-minute": "Gallons Per Minute", + "cubic-foot-per-second": "Cubic foot per second", + "milliliters-per-minute": "Milliliters per minute", + "bit": "Bit", + "byte": "Byte", + "kilobyte": "Kilobyte", + "megabyte": "Megabyte", + "gigabyte": "Gigabyte", + "terabyte": "Terabyte", + "petabyte": "Petabyte", + "exabyte": "Exabyte", + "zettabyte": "Zettabyte", + "yottabyte": "Yottabyte", + "bit-per-second": "Bit per second", + "kilobit-per-second": "Kilobit per second", + "megabit-per-second": "Megabit per second", + "gigabit-per-second": "Gigabit per second", + "terabit-per-second": "Terabit per second", + "byte-per-second": "Byte per second", + "kilobyte-per-second": "Kilobyte per second", + "megabyte-per-second": "Megabyte per second", + "gigabyte-per-second": "Gigabyte per second", + "degree": "Degree", + "radian": "Radian", + "gradian": "Gradian", + "mil": "Mil", + "revolution": "Revolution", + "siemens": "Siemens", + "millisiemens": "Millisiemens", + "microsiemens": "Microsiemens", + "kilosiemens": "Kilosiemens", + "megasiemens": "Megasiemens", + "gigasiemens": "Gigasiemens", + "farad": "Farad", + "millifarad": "Millifarad", + "microfarad": "Microfarad", + "nanofarad": "Nanofarad", + "picofarad": "Picofarad", + "kilofarad": "Kilofarad", + "megafarad": "Megafarad", + "gigafarad": "Gigafarad", + "terfarad": "Terfarad", + "farad-per-meter": "Farad per Meter", + "tesla": "Tesla", + "gauss": "Gauss", + "kilogauss": "Kilogauss", + "millitesla": "Millitesla", + "microtesla": "Microtesla", + "nanotesla": "Nanotesla", + "kilotesla": "Kilotesla", + "megatesla": "Megatesla", + "millitesla-square-meters": "millitesla square meters", + "gamma": "Gamma", + "lambda": "Lambda", + "square-meter-per-second": "Square meter per second", + "square-centimeter-per-second": "Square centimeter per second", + "stoke": "Stoke", + "centistokes": "Centistokes", + "square-foot-per-second": "Square foot per second", + "square-inch-per-second": "Square inch per second", + "pascal-second": "Pascal-second", + "centipoise": "Centipoise", + "poise": "Poise", + "reynolds": "Reynolds", + "pound-per-foot-hour": "Pound per foot-hour", + "newton-second-per-square-meter": "Newton second per square meter", + "dyne-second-per-square-centimeter": "Dyne second per square centimeter", + "kilogram-per-meter-second": "Kilogram per meter-second", + "tesla-square-meters": "Tesla square meters", + "maxwell": "Maxwell", + "tesla-per-meter": "Tesla per Meter", + "gauss-per-centimeter": "Gauss per Centimeter", + "weber": "Weber", + "microweber": "Microweber", + "milliweber": "Milliweber", + "gauss-square-centimeter": "Gauss-Square Centimeter", + "kilogauss-square-centimeter": "Kilogauss-Square Centimeter", + "henry": "Henry", + "millihenry": "Millihenry", + "microhenry": "Microhenry", + "nanohenry": "Nanohenry", + "henry-per-meter": "Henry per Meter", + "tesla-meter-per-ampere": "Tesla Meter per Ampere", + "gauss-per-oersted": "Gauss per Oersted", + "kilogram-per-mole": "Kilogram per mole", + "gram-per-mole": "Gram per mole", + "milligram-per-mole": "Milligram per mole", + "joule-per-mole": "Joule per Mole", + "joule-per-mole-kelvin": "Joule per Mole-Kelvin", + "millivolts-per-meter": "Millivolts per meter", + "volts-per-meter": "Volts per meter", + "kilovolts-per-meter": "Kilovolts per meter", + "radian-per-second": "Radian per second", + "radian-per-second-squared": "Radian per second squared", + "revolutions-per-minute-per-second": "Angular acceleration", + "revolutions-per-minute-per-second-squared": "Angular Acceleration", + "deg-per-second": "deg/s", + "degrees-brix": "Degrees Brix", + "katal": "Katal", + "katal-per-cubic-metre": "Katal per Cubic Metre" }, "user": { "user": "User", From f7b60e1c0e1b7ef27a42bcd80b54d942c566b33b Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 11 Jul 2023 10:40:04 +0300 Subject: [PATCH 234/421] UI: Redesign user menu: move profile and security menu item to account item --- ui-ngx/src/app/core/auth/auth.service.ts | 2 +- ui-ngx/src/app/core/services/menu.service.ts | 84 +++++++++++++++++++ ui-ngx/src/app/modules/home/home.component.ts | 9 +- .../modules/home/menu/side-menu.component.ts | 12 ++- .../pages/account/account-routing.module.ts | 54 ++++++++++++ .../home/pages/account/account.module.ts | 28 +++++++ .../modules/home/pages/home-pages.module.ts | 4 +- .../pages/profile/profile-routing.module.ts | 9 +- .../pages/security/security-routing.module.ts | 9 +- .../components/user-menu.component.html | 8 +- .../shared/components/user-menu.component.ts | 8 +- .../assets/locale/locale.constant-en_US.json | 4 + 12 files changed, 210 insertions(+), 21 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts create mode 100644 ui-ngx/src/app/modules/home/pages/account/account.module.ts diff --git a/ui-ngx/src/app/core/auth/auth.service.ts b/ui-ngx/src/app/core/auth/auth.service.ts index 87c6561315..f1af3b745a 100644 --- a/ui-ngx/src/app/core/auth/auth.service.ts +++ b/ui-ngx/src/app/core/auth/auth.service.ts @@ -244,7 +244,7 @@ export class AuthService { if (authState && authState.authUser) { if (authState.authUser.authority === Authority.TENANT_ADMIN || authState.authUser.authority === Authority.CUSTOMER_USER) { if ((this.userHasDefaultDashboard(authState) && authState.forceFullscreen) || authState.authUser.isPublic) { - if (path === 'profile' || path === 'security') { + if (path.startsWith('account')) { if (this.userHasProfile(authState.authUser)) { return false; } else { diff --git a/ui-ngx/src/app/core/services/menu.service.ts b/ui-ngx/src/app/core/services/menu.service.ts index b33c552eb1..507ed01984 100644 --- a/ui-ngx/src/app/core/services/menu.service.ts +++ b/ui-ngx/src/app/core/services/menu.service.ts @@ -262,6 +262,34 @@ export class MenuService { isMdiIcon: true } ] + }, + { + id: 'account', + name: 'profile.profile', + type: 'link', + path: '/account', + disabled: true, + icon: 'mdi:message-badge', + isMdiIcon: true, + pages: [ + { + id: 'personal_info', + name: 'account.personal-info', + fullName: 'account.personal-info', + type: 'link', + path: '/account/profile', + icon: 'mdi:badge-account-horizontal', + isMdiIcon: true + }, + { + id: 'security', + name: 'security.security', + fullName: 'security.security', + type: 'link', + path: '/account/security', + icon: 'lock' + } + ] } ); return sections; @@ -634,6 +662,34 @@ export class MenuService { icon: 'track_changes' } ] + }, + { + id: 'account', + name: 'profile.profile', + type: 'link', + path: '/account', + disabled: true, + icon: 'mdi:message-badge', + isMdiIcon: true, + pages: [ + { + id: 'personal_info', + name: 'account.personal-info', + fullName: 'account.personal-info', + type: 'link', + path: '/account/profile', + icon: 'mdi:badge-account-horizontal', + isMdiIcon: true + }, + { + id: 'security', + name: 'security.security', + fullName: 'security.security', + type: 'link', + path: '/account/security', + icon: 'lock' + } + ] } ); return sections; @@ -885,6 +941,34 @@ export class MenuService { icon: 'inbox' } ] + }, + { + id: 'account', + name: 'profile.profile', + type: 'link', + path: '/account', + disabled: true, + icon: 'mdi:message-badge', + isMdiIcon: true, + pages: [ + { + id: 'personal_info', + name: 'account.personal-info', + fullName: 'account.personal-info', + type: 'link', + path: '/account/profile', + icon: 'mdi:badge-account-horizontal', + isMdiIcon: true + }, + { + id: 'security', + name: 'security.security', + fullName: 'security.security', + type: 'link', + path: '/account/security', + icon: 'lock' + } + ] } ); return sections; diff --git a/ui-ngx/src/app/modules/home/home.component.ts b/ui-ngx/src/app/modules/home/home.component.ts index 6e045b9786..1ab9cea1dc 100644 --- a/ui-ngx/src/app/modules/home/home.component.ts +++ b/ui-ngx/src/app/modules/home/home.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { AfterViewInit, Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { fromEvent } from 'rxjs'; import { Store } from '@ngrx/store'; import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; @@ -27,10 +27,10 @@ import { MediaBreakpoints } from '@shared/models/constants'; import screenfull from 'screenfull'; import { MatSidenav } from '@angular/material/sidenav'; import { AuthState } from '@core/auth/auth.models'; -import { WINDOW } from '@core/services/window.service'; import { instanceOfSearchableComponent, ISearchableComponent } from '@home/models/searchable-component.models'; import { ActiveComponentService } from '@core/services/active-component.service'; import { RouterTabsComponent } from '@home/components/router-tabs.component'; +import { Router } from '@angular/router'; @Component({ selector: 'tb-home', @@ -65,8 +65,8 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni hideLoadingBar = false; constructor(protected store: Store, - @Inject(WINDOW) private window: Window, private activeComponentService: ActiveComponentService, + private router: Router, public breakpointObserver: BreakpointObserver) { super(store); } @@ -120,7 +120,8 @@ export class HomeComponent extends PageComponent implements AfterViewInit, OnIni } goBack() { - this.window.history.back(); + const dashboardId = this.authState.userDetails.additionalInfo.defaultDashboardId; + this.router.navigate(['dashboard', dashboardId]).then(() => {}); } activeComponentChanged(activeComponent: any) { diff --git a/ui-ngx/src/app/modules/home/menu/side-menu.component.ts b/ui-ngx/src/app/modules/home/menu/side-menu.component.ts index f6e1f30624..cf3e5ca4db 100644 --- a/ui-ngx/src/app/modules/home/menu/side-menu.component.ts +++ b/ui-ngx/src/app/modules/home/menu/side-menu.component.ts @@ -17,6 +17,8 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { MenuService } from '@core/services/menu.service'; import { MenuSection } from '@core/services/menu.models'; +import { Observable, of } from 'rxjs'; +import { mergeMap, share } from 'rxjs/operators'; @Component({ selector: 'tb-side-menu', @@ -26,15 +28,23 @@ import { MenuSection } from '@core/services/menu.models'; }) export class SideMenuComponent implements OnInit { - menuSections$ = this.menuService.menuSections(); + menuSections$: Observable>; constructor(private menuService: MenuService) { + this.menuSections$ = this.menuService.menuSections().pipe( + mergeMap((sections) => this.filterSections(sections)), + share() + ); } trackByMenuSection(index: number, section: MenuSection){ return section.id; } + private filterSections(sections: Array): Observable> { + return of(sections.filter(section => !section.disabled)); + } + ngOnInit() { } diff --git a/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts b/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts new file mode 100644 index 0000000000..bb63b361b6 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts @@ -0,0 +1,54 @@ +/// +/// Copyright © 2016-2023 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { RouterTabsComponent } from '@home/components/router-tabs.component'; +import { Authority } from '@shared/models/authority.enum'; +import { securityRoutes } from '@home/pages/security/security-routing.module'; +import { profileRoutes } from '@home/pages/profile/profile-routing.module'; + +const routes: Routes = [ + { + path: 'account', + component: RouterTabsComponent, + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN, Authority.CUSTOMER_USER], + breadcrumb: { + label: 'account.account', + icon: 'account_circle' + } + }, + children: [ + { + path: '', + children: [], + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN, Authority.CUSTOMER_USER], + redirectTo: '/account/profile', + } + }, + ...profileRoutes, + ...securityRoutes + ] + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AccountRoutingModule { } diff --git a/ui-ngx/src/app/modules/home/pages/account/account.module.ts b/ui-ngx/src/app/modules/home/pages/account/account.module.ts new file mode 100644 index 0000000000..df178607ce --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/account/account.module.ts @@ -0,0 +1,28 @@ +/// +/// Copyright © 2016-2023 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 { NgModule } from '@angular/core'; +import { AccountRoutingModule } from '@home/pages/account/account-routing.module'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + declarations: [ ], + imports: [ + CommonModule, + AccountRoutingModule + ] +}) +export class AccountModule { } diff --git a/ui-ngx/src/app/modules/home/pages/home-pages.module.ts b/ui-ngx/src/app/modules/home/pages/home-pages.module.ts index b1f4715c33..005c47f787 100644 --- a/ui-ngx/src/app/modules/home/pages/home-pages.module.ts +++ b/ui-ngx/src/app/modules/home/pages/home-pages.module.ts @@ -42,6 +42,7 @@ import { AlarmModule } from '@home/pages/alarm/alarm.module'; import { EntitiesModule } from '@home/pages/entities/entities.module'; import { FeaturesModule } from '@home/pages/features/features.module'; import { NotificationModule } from '@home/pages/notification/notification.module'; +import { AccountModule } from '@home/pages/account/account.module'; @NgModule({ exports: [ @@ -70,7 +71,8 @@ import { NotificationModule } from '@home/pages/notification/notification.module ApiUsageModule, OtaUpdateModule, UserModule, - VcModule + VcModule, + AccountModule ] }) export class HomePagesModule { } diff --git a/ui-ngx/src/app/modules/home/pages/profile/profile-routing.module.ts b/ui-ngx/src/app/modules/home/pages/profile/profile-routing.module.ts index c14e450745..334174194c 100644 --- a/ui-ngx/src/app/modules/home/pages/profile/profile-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/profile/profile-routing.module.ts @@ -40,7 +40,7 @@ export class UserProfileResolver implements Resolve { } } -const routes: Routes = [ +export const profileRoutes: Routes = [ { path: 'profile', component: ProfileComponent, @@ -59,6 +59,13 @@ const routes: Routes = [ } ]; +const routes: Routes = [ + { + path: 'profile', + redirectTo: 'account/profile' + } +]; + @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule], diff --git a/ui-ngx/src/app/modules/home/pages/security/security-routing.module.ts b/ui-ngx/src/app/modules/home/pages/security/security-routing.module.ts index d2820e0184..f6da1dabd2 100644 --- a/ui-ngx/src/app/modules/home/pages/security/security-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/security/security-routing.module.ts @@ -53,7 +53,7 @@ export class UserTwoFAProvidersResolver implements Resolve
- - - - - -
-
- -
-
-
-
- - - - - - -
-
-
-
- - -
- +
+ + + +
diff --git a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.scss b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.scss index 849b646234..afd8d1cfcb 100644 --- a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.scss +++ b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.scss @@ -14,36 +14,9 @@ * limitations under the License. */ :host { - .tb-material-icons-dialog { - position: relative; - } - .tb-icons-load { - top: 64px; - z-index: 3; - background: rgba(255, 255, 255, .75); - } -} - -:host ::ng-deep { - .tb-material-icons-dialog { - button.mat-mdc-button-base.tb-select-icon-button { - width: 56px; - min-width: 56px; - height: 56px; - padding: 16px; - margin: 10px; - border: solid 1px #ffa500; - border-radius: 0; - line-height: 0; - display: inline-block; - vertical-align: baseline; - .mat-icon { - width: 24px; - margin: 0; - height: 24px; - vertical-align: initial; - font-size: 24px; - } - } + .tb-close-button { + position: absolute; + top: 6px; + right: 6px; } } diff --git a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts index e63b6a0c9c..b6321c966d 100644 --- a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts @@ -14,18 +14,12 @@ /// limitations under the License. /// -import { AfterViewInit, Component, Inject, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Router } from '@angular/router'; import { DialogComponent } from '@shared/components/dialog.component'; -import { UtilsService } from '@core/services/utils.service'; -import { UntypedFormControl } from '@angular/forms'; -import { merge, Observable } from 'rxjs'; -import { delay, map, mapTo, mergeMap, share, startWith, tap } from 'rxjs/operators'; -import { ResourcesService } from '@core/services/resources.service'; -import { getMaterialIcons } from '@shared/models/icon.models'; export interface MaterialIconsDialogData { icon: string; @@ -37,63 +31,16 @@ export interface MaterialIconsDialogData { providers: [], styleUrls: ['./material-icons-dialog.component.scss'] }) -export class MaterialIconsDialogComponent extends DialogComponent - implements OnInit, AfterViewInit { - - @ViewChildren('iconButtons') iconButtons: QueryList; +export class MaterialIconsDialogComponent extends DialogComponent { selectedIcon: string; - icons$: Observable>; - loadingIcons$: Observable; - - showAllControl: UntypedFormControl; constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: MaterialIconsDialogData, - private utils: UtilsService, - private resourcesService: ResourcesService, public dialogRef: MatDialogRef) { super(store, router, dialogRef); this.selectedIcon = data.icon; - this.showAllControl = new UntypedFormControl(false); - } - - ngOnInit(): void { - this.icons$ = this.showAllControl.valueChanges.pipe( - map((showAll) => ({firstTime: false, showAll})), - startWith<{firstTime: boolean; showAll: boolean}>({firstTime: true, showAll: false}), - mergeMap((data) => { - const res = getMaterialIcons(this.resourcesService, data.showAll, ''); - if (data.showAll) { - return res.pipe(delay(100)); - } else { - return data.firstTime ? res : res.pipe(delay(50)); - } - }), - share() - ); - } - - ngAfterViewInit(): void { - this.loadingIcons$ = merge( - this.showAllControl.valueChanges.pipe( - mapTo(true), - ), - this.iconButtons.changes.pipe( - delay(100), - mapTo( false), - ) - ).pipe( - tap((loadingIcons) => { - if (loadingIcons) { - this.showAllControl.disable({emitEvent: false}); - } else { - this.showAllControl.enable({emitEvent: false}); - } - }), - share() - ); } selectIcon(icon: string) { diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.html b/ui-ngx/src/app/shared/components/material-icon-select.component.html index 5cf7cb6de7..8bae8c3435 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.html +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.html @@ -29,7 +29,13 @@
- {{materialIconFormGroup.get('icon').value}} + diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.scss b/ui-ngx/src/app/shared/components/material-icon-select.component.scss index 6bfd308ae5..b008fc6838 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.scss +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.scss @@ -22,20 +22,23 @@ border: solid 1px rgba(0, 0, 0, .27); box-sizing: initial; } - &.icon-box { - border: 1px solid rgba(0, 0, 0, 0.12); - border-radius: 4px; - cursor: pointer; - box-sizing: border-box; - padding: 8px; - height: 40px; - width: 40px; - font-size: 22px; - vertical-align: middle; - &.disabled { - cursor: initial; - color: rgba(0, 0, 0, 0.38); - } + } +} + +:host ::ng-deep { + button.mat-mdc-button-base.icon-box { + width: 40px; + min-width: 40px; + height: 40px; + padding: 7px; + &:not(:disabled) { + color: rgba(0, 0, 0, 0.87); + } + > .mat-icon { + width: 24px; + height: 24px; + font-size: 24px; + margin: 0; } } } diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.ts b/ui-ngx/src/app/shared/components/material-icon-select.component.ts index b8bb7ed25b..740bb4545a 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.ts +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.ts @@ -14,15 +14,18 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, forwardRef, Input, OnInit, 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, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { DialogService } from '@core/services/dialog.service'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { TranslateService } from '@ngx-translate/core'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { MaterialIconsComponent } from '@shared/components/material-icons.component'; +import { MatButton } from '@angular/material/button'; @Component({ selector: 'tb-material-icon-select', @@ -81,6 +84,9 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit constructor(protected store: Store, private dialogs: DialogService, private translate: TranslateService, + private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef, private fb: UntypedFormBuilder, private cd: ChangeDetectorRef) { super(store); @@ -142,6 +148,32 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit } } + openIconPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const materialIconsPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, MaterialIconsComponent, 'left', true, null, + { + selectedIcon: this.materialIconFormGroup.get('icon').value + }, + {}, + {}, {}, true); + materialIconsPopover.tbComponentRef.instance.popover = materialIconsPopover; + materialIconsPopover.tbComponentRef.instance.iconSelected.subscribe((icon) => { + materialIconsPopover.hide(); + this.materialIconFormGroup.patchValue( + {icon}, {emitEvent: true} + ); + this.cd.markForCheck(); + }); + } + } + clear() { this.materialIconFormGroup.get('icon').patchValue(null, {emitEvent: true}); this.cd.markForCheck(); diff --git a/ui-ngx/src/app/shared/components/material-icons.component.html b/ui-ngx/src/app/shared/components/material-icons.component.html new file mode 100644 index 0000000000..39404a9998 --- /dev/null +++ b/ui-ngx/src/app/shared/components/material-icons.component.html @@ -0,0 +1,65 @@ + +
+
icon.icons
+ + search + + + + +
+ + + + +
+
+ + +
+
+
{{ 'icon.no-icons-found' | translate:{iconSearch: searchIconControl.value} }}
+
+
+
diff --git a/ui-ngx/src/app/shared/components/material-icons.component.scss b/ui-ngx/src/app/shared/components/material-icons.component.scss new file mode 100644 index 0000000000..23b959d118 --- /dev/null +++ b/ui-ngx/src/app/shared/components/material-icons.component.scss @@ -0,0 +1,61 @@ +/** + * Copyright © 2016-2023 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. + */ +.tb-material-icons-panel { + width: 100%; + display: flex; + flex-direction: column; + gap: 16px; + align-items: center; + .tb-material-icons-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-material-icons-title, .tb-material-icons-search, .tb-material-icons-show-more { + width: 100%; + } + .tb-material-icons-viewport { + min-height: 144px; + } + .tb-material-icons-row { + display: flex; + flex-direction: row; + gap: 12px; + } + .tb-material-icons-row + .tb-material-icons-row { + margin-top: 12px; + } + .tb-no-data-available { + min-height: 144px; + } + button.mat-mdc-button-base.tb-select-icon-button { + width: 36px; + min-width: 36px; + height: 36px; + padding: 6px; + &:not(.mat-primary) { + color: rgba(0, 0, 0, 0.54); + } + > .mat-icon { + width: 24px; + height: 24px; + font-size: 24px; + margin: 0; + } + } +} diff --git a/ui-ngx/src/app/shared/components/material-icons.component.ts b/ui-ngx/src/app/shared/components/material-icons.component.ts index 5588540018..9347243af2 100644 --- a/ui-ngx/src/app/shared/components/material-icons.component.ts +++ b/ui-ngx/src/app/shared/components/material-icons.component.ts @@ -1,24 +1,135 @@ +/// +/// Copyright © 2016-2023 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 { PageComponent } from '@shared/components/page.component'; -import { OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, + ViewEncapsulation +} from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { UntypedFormControl } from '@angular/forms'; -import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs'; +import { BehaviorSubject, combineLatest, debounce, Observable, of, timer } from 'rxjs'; +import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; +import { getMaterialIcons, MaterialIcon } from '@shared/models/icon.models'; +import { distinctUntilChanged, map, mergeMap, share, startWith, tap } from 'rxjs/operators'; +import { ResourcesService } from '@core/services/resources.service'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { BreakpointObserver } from '@angular/cdk/layout'; +import { MediaBreakpoints } from '@shared/models/constants'; +@Component({ + selector: 'tb-material-icons', + templateUrl: './material-icons.component.html', + providers: [], + styleUrls: ['./material-icons.component.scss'], + encapsulation: ViewEncapsulation.None +}) export class MaterialIconsComponent extends PageComponent implements OnInit { - searchIconsControl: UntypedFormControl; + @ViewChild('iconsPanel') + iconsPanel: CdkVirtualScrollViewport; + + @Input() + selectedIcon: string; + + @Input() + popover: TbPopoverComponent; + + @Output() + iconSelected = new EventEmitter(); + + iconRows$: Observable; showAllSubject = new BehaviorSubject(false); + searchIconControl: UntypedFormControl; + + iconsRowHeight = 48; + + iconsPanelHeight: string; + iconsPanelWidth: string; - icons$: Observable>; + notFound = false; - constructor(protected store: Store) { + constructor(protected store: Store, + private resourcesService: ResourcesService, + private breakpointObserver: BreakpointObserver, + private cd: ChangeDetectorRef) { super(store); - this.searchIconsControl = new UntypedFormControl(''); + this.searchIconControl = new UntypedFormControl(''); } ngOnInit(): void { + const iconsRowSize = this.breakpointObserver.isMatched(MediaBreakpoints['lt-md']) ? 8 : 11; + this.calculatePanelSize(iconsRowSize); + const iconsRowSizeObservable = this.breakpointObserver + .observe(MediaBreakpoints['lt-md']).pipe( + map((state) => state.matches ? 8 : 11), + startWith(iconsRowSize), + ); + this.iconRows$ = combineLatest({showAll: this.showAllSubject.asObservable(), + rowSize: iconsRowSizeObservable, + searchText: this.searchIconControl.valueChanges.pipe( + startWith(''), + debounce((searchText) => searchText ? timer(150) : of({})), + )}).pipe( + map((data) => { + if (data.searchText && !data.showAll) { + data.showAll = true; + this.showAllSubject.next(true); + } + return data; + }), + distinctUntilChanged((p, c) => c.showAll === p.showAll && c.searchText === p.searchText && c.rowSize === p.rowSize), + mergeMap((data) => getMaterialIcons(this.resourcesService, data.rowSize, data.showAll, data.searchText).pipe( + map(iconRows => ({iconRows, iconsRowSize: data.rowSize})) + )), + tap((data) => { + this.notFound = !data.iconRows.length; + this.calculatePanelSize(data.iconsRowSize, data.iconRows.length); + this.cd.markForCheck(); + setTimeout(() => { + this.checkSize(); + }, 0); + }), + map((data) => data.iconRows), + share() + ); + } + + clearSearch() { + this.searchIconControl.patchValue('', {emitEvent: true}); + } + selectIcon(icon: MaterialIcon) { + this.iconSelected.emit(icon.name); } + private calculatePanelSize(iconsRowSize: number, iconRows = 4) { + this.iconsPanelHeight = Math.min(iconRows * this.iconsRowHeight, 10 * this.iconsRowHeight) + 'px'; + this.iconsPanelWidth = (iconsRowSize * 36 + (iconsRowSize - 1) * 12 + 6) + 'px'; + } + + private checkSize() { + this.iconsPanel?.checkViewportSize(); + this.popover?.updatePosition(); + } } diff --git a/ui-ngx/src/app/shared/components/popover.component.ts b/ui-ngx/src/app/shared/components/popover.component.ts index d6d092d03c..91f5a2e902 100644 --- a/ui-ngx/src/app/shared/components/popover.component.ts +++ b/ui-ngx/src/app/shared/components/popover.component.ts @@ -63,8 +63,10 @@ import { coerceBoolean } from '@shared/decorators/coercion'; export type TbPopoverTrigger = 'click' | 'focus' | 'hover' | null; @Directive({ + // eslint-disable-next-line @angular-eslint/directive-selector selector: '[tb-popover]', exportAs: 'tbPopover', + // eslint-disable-next-line @angular-eslint/no-host-metadata-property host: { '[class.tb-popover-open]': 'visible' } @@ -265,12 +267,20 @@ export class TbPopoverDirective implements OnChanges, OnDestroy, AfterViewInit { } else if (delay > 0) { this.delayTimer = setTimeout(() => { this.delayTimer = undefined; - isEnter ? this.show() : this.hide(); + if (isEnter) { + this.show(); + } else { + this.hide(); + } }, delay * 1000); } else { // `isOrigin` is used due to the tooltip will not hide immediately // (may caused by the fade-out animation). - isEnter && isOrigin ? this.show() : this.hide(); + if (isEnter && isOrigin) { + this.show(); + } else { + this.hide(); + } } } @@ -345,15 +355,15 @@ export class TbPopoverDirective implements OnChanges, OnDestroy, AfterViewInit { ` }) -export class TbPopoverComponent implements OnDestroy, OnInit { +export class TbPopoverComponent implements OnDestroy, OnInit { @ViewChild('overlay', { static: false }) overlay!: CdkConnectedOverlay; @ViewChild('popoverRoot', { static: false }) popoverRoot!: ElementRef; @ViewChild('popover', { static: false }) popover!: ElementRef; tbContent: string | TemplateRef | null = null; - tbComponentFactory: ComponentFactory | null = null; - tbComponentRef: ComponentRef | null = null; + tbComponentFactory: ComponentFactory | null = null; + tbComponentRef: ComponentRef | null = null; tbComponentContext: any; tbComponentInjector: Injector | null = null; tbComponentStyle: { [klass: string]: any } = {}; diff --git a/ui-ngx/src/app/shared/components/popover.service.ts b/ui-ngx/src/app/shared/components/popover.service.ts index f547200316..1bef922ec1 100644 --- a/ui-ngx/src/app/shared/components/popover.service.ts +++ b/ui-ngx/src/app/shared/components/popover.service.ts @@ -65,7 +65,7 @@ export class TbPopoverService { displayPopover(trigger: Element, renderer: Renderer2, hostView: ViewContainerRef, componentType: Type, preferredPlacement: PopoverPlacement = 'top', hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, popoverStyle: any = {}, style?: any, - showCloseButton = true): TbPopoverComponent { + showCloseButton = true): TbPopoverComponent { const componentRef = this.createPopoverRef(hostView); return this.displayPopoverWithComponentRef(componentRef, trigger, renderer, componentType, preferredPlacement, hideOnClickOutside, injector, context, overlayStyle, popoverStyle, style, showCloseButton); @@ -74,7 +74,7 @@ export class TbPopoverService { displayPopoverWithComponentRef(componentRef: ComponentRef, trigger: Element, renderer: Renderer2, componentType: Type, preferredPlacement: PopoverPlacement = 'top', hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, - popoverStyle: any = {}, style?: any, showCloseButton = true): TbPopoverComponent { + popoverStyle: any = {}, style?: any, showCloseButton = true): TbPopoverComponent { const component = componentRef.instance; this.popoverWithTriggers.push({ trigger, diff --git a/ui-ngx/src/app/shared/components/public-api.ts b/ui-ngx/src/app/shared/components/public-api.ts index 3ed56d0256..04508266e9 100644 --- a/ui-ngx/src/app/shared/components/public-api.ts +++ b/ui-ngx/src/app/shared/components/public-api.ts @@ -26,3 +26,4 @@ export * from './resource/resource-autocomplete.component'; export * from './toggle-header.component'; export * from './toggle-select.component'; export * from './unit-input.component'; +export * from './material-icons.component'; diff --git a/ui-ngx/src/app/shared/models/icon.models.ts b/ui-ngx/src/app/shared/models/icon.models.ts index c774b65ae5..48b643d235 100644 --- a/ui-ngx/src/app/shared/models/icon.models.ts +++ b/ui-ngx/src/app/shared/models/icon.models.ts @@ -1,11 +1,27 @@ -import { Unit, units } from '@shared/models/unit.models'; +/// +/// Copyright © 2016-2023 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 { ResourcesService } from '@core/services/resources.service'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { isEmptyStr, isNotEmptyStr } from '@core/utils'; +import { isNotEmptyStr } from '@core/utils'; export interface MaterialIcon { name: string; + displayName?: string; tags: string[]; } @@ -16,21 +32,41 @@ const searchIconTags = (icon: MaterialIcon, searchText: string): boolean => const searchIcons = (_icons: Array, searchText: string): Array => _icons.filter( i => i.name.toUpperCase().includes(searchText.toUpperCase()) || + i.displayName.toUpperCase().includes(searchText.toUpperCase()) || searchIconTags(i, searchText) ); -const getCommonMaterialIcons = (icons: Array): Array => icons.slice(0, 44); +const getCommonMaterialIcons = (icons: Array, chunkSize: number): Array => icons.slice(0, chunkSize * 4); -export const getMaterialIcons = (resourcesService: ResourcesService, all = false, searchText: string): Observable => - resourcesService.loadJsonResource>('/assets/metadata/material-icons.json').pipe( +export const getMaterialIcons = (resourcesService: ResourcesService, chunkSize = 11, + all = false, searchText: string): Observable => + resourcesService.loadJsonResource>('/assets/metadata/material-icons.json', + (icons) => { + for (const icon of icons) { + const words = icon.name.replace(/_/g, ' ').split(' '); + for (let i = 0; i < words.length; i++) { + words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1); + } + icon.displayName = words.join(' '); + } + return icons; + } + ).pipe( map((icons) => { if (isNotEmptyStr(searchText)) { return searchIcons(icons, searchText); } else if (!all) { - return getCommonMaterialIcons(icons); + return getCommonMaterialIcons(icons, chunkSize); } else { return icons; } }), - map((icons) => icons.map(icon => icon.name)) + map((icons) => { + const iconChunks: MaterialIcon[][] = []; + for (let i = 0; i < icons.length; i += chunkSize) { + const chunk = icons.slice(i, i + chunkSize); + iconChunks.push(chunk); + } + return iconChunks; + }) ); diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index f7c37e4761..25eee9ca08 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -195,6 +195,7 @@ import { ToggleHeaderComponent, ToggleOption } from '@shared/components/toggle-h import { RuleChainSelectComponent } from '@shared/components/rule-chain/rule-chain-select.component'; import { ToggleSelectComponent } from '@shared/components/toggle-select.component'; import { UnitInputComponent } from '@shared/components/unit-input.component'; +import { MaterialIconsComponent } from '@shared/components/material-icons.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -369,6 +370,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ToggleOption, ToggleSelectComponent, UnitInputComponent, + MaterialIconsComponent, RuleChainSelectComponent ], imports: [ @@ -600,6 +602,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ToggleOption, ToggleSelectComponent, UnitInputComponent, + MaterialIconsComponent, RuleChainSelectComponent ] }) 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 82f10b7f4c..bc3351aa83 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -68,7 +68,8 @@ "less": "Less", "skip": "Skip", "send": "Send", - "reset": "Reset" + "reset": "Reset", + "show-more": "Show more" }, "aggregation": { "aggregation": "Aggregation", @@ -5501,9 +5502,12 @@ }, "icon": { "icon": "Icon", + "icons": "Icons", "select-icon": "Select icon", "material-icons": "Material icons", - "show-all": "Show all icons" + "show-all": "Show all icons", + "search-icon": "Search icon", + "no-icons-found": "No icons found for '{{iconSearch}}'" }, "phone-input": { "phone-input-label": "Phone number", diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 1f27e59279..8197e32f6c 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@import './scss/constants'; + .tb-default, .tb-dark { .tb-form-panel { box-shadow: 0 0 10px 6px rgba(11, 17, 51, 0.04); @@ -177,6 +180,13 @@ opacity: 0; } } + &:not(.mat-mdc-form-field-has-icon-prefix) { + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { + padding-left: 12px; + } + } + } &:not(.mat-mdc-form-field-has-icon-suffix) { .mat-mdc-text-field-wrapper { &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { @@ -186,7 +196,6 @@ } .mat-mdc-text-field-wrapper { &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { - padding-left: 12px; &:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(:hover) { .mdc-notched-outline__leading, .mdc-notched-outline__trailing { border-color: rgba(0, 0, 0, 0.12); @@ -203,7 +212,7 @@ line-height: 20px; } } - .mat-mdc-form-field-icon-suffix { + .mat-mdc-form-field-icon-prefix, .mat-mdc-form-field-icon-suffix { height: 40px; font-size: 14px; line-height: 40px; @@ -336,4 +345,49 @@ } } } + + .tb-no-data-available { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + + .tb-no-data-bg { + margin: 10px; + position: relative; + flex: 1; + width: 100%; + max-height: 100px; + &:before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: #305680; + -webkit-mask-image: url(/assets/home/no_data_folder_bg.svg); + -webkit-mask-repeat: no-repeat; + -webkit-mask-size: contain; + -webkit-mask-position: center; + mask-image: url(/assets/home/no_data_folder_bg.svg); + mask-repeat: no-repeat; + mask-size: contain; + mask-position: center; + } + } + + .tb-no-data-text { + font-weight: 500; + font-size: 14px; + line-height: 20px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.54); + @media #{$mat-md-lg} { + font-size: 12px; + line-height: 16px; + } + } } From 25f0c9e15f7d04127a640a2d765b16eeb9d1621a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 13 Jul 2023 12:48:21 +0300 Subject: [PATCH 251/421] UI: Minor improvements --- ui-ngx/src/app/core/services/utils.service.ts | 26 +++++++++++- .../lib/alarms-table-widget.component.ts | 40 ++++--------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index 339c1e1742..a6065dfe62 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -41,7 +41,7 @@ import { TranslateService } from '@ngx-translate/core'; import { customTranslationsPrefix, i18nPrefix } from '@app/shared/models/constants'; import { DataKey, Datasource, DatasourceType, KeyInfo } from '@shared/models/widget.models'; import { DataKeyType } from '@app/shared/models/telemetry/telemetry.models'; -import { alarmFields } from '@shared/models/alarm.models'; +import { alarmFields, alarmSeverityTranslations, alarmStatusTranslations } from '@shared/models/alarm.models'; import { materialColors } from '@app/shared/models/material.models'; import { WidgetInfo } from '@home/models/widget-component.models'; import jsonSchemaDefaults from 'json-schema-defaults'; @@ -55,6 +55,8 @@ import { TelemetryType } from '@shared/models/telemetry/telemetry.models'; import { EntityId } from '@shared/models/id/entity-id'; +import { DatePipe } from '@angular/common'; +import { entityTypeTranslations } from '@shared/models/entity-type.models'; const i18nRegExp = new RegExp(`{${i18nPrefix}:[^{}]+}`, 'g'); @@ -115,6 +117,7 @@ export class UtilsService { constructor(@Inject(WINDOW) private window: Window, private zone: NgZone, + private datePipe: DatePipe, private translate: TranslateService) { let frame: Element = null; try { @@ -170,6 +173,27 @@ export class UtilsService { return deepClone(this.defaultAlarmDataKeys); } + public defaultAlarmFieldContent(key: DataKey | {name: string}, value: any): string { + if (isDefined(value)) { + const alarmField = alarmFields[key.name]; + if (alarmField) { + if (alarmField.time) { + return value ? this.datePipe.transform(value, 'yyyy-MM-dd HH:mm:ss') : ''; + } else if (alarmField === alarmFields.severity) { + return this.translate.instant(alarmSeverityTranslations.get(value)); + } else if (alarmField === alarmFields.status) { + return alarmStatusTranslations.get(value) ? this.translate.instant(alarmStatusTranslations.get(value)) : value; + } else if (alarmField === alarmFields.originatorType) { + return this.translate.instant(entityTypeTranslations.get(value).type); + } else if (alarmField.value === alarmFields.assignee.value) { + return ''; + } + } + return value; + } + return ''; + } + public generateObjectFromJsonSchema(schema: any): any { const obj = jsonSchemaDefaults(schema); deleteNullProperties(obj); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index a0062645ac..db2d04ea88 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -23,6 +23,7 @@ import { Injector, Input, NgZone, + OnDestroy, OnInit, StaticProvider, ViewChild, @@ -52,7 +53,6 @@ import { Direction } from '@shared/models/page/sort-order'; import { CollectionViewer, DataSource, SelectionModel } from '@angular/cdk/collections'; import { BehaviorSubject, forkJoin, fromEvent, merge, Observable, Subscription } from 'rxjs'; import { emptyPageData, PageData } from '@shared/models/page/page-data'; -import { entityTypeTranslations } from '@shared/models/entity-type.models'; import { debounceTime, distinctUntilChanged, map, take, tap } from 'rxjs/operators'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort, SortDirection } from '@angular/material/sort'; @@ -92,15 +92,7 @@ import { DisplayColumnsPanelComponent, DisplayColumnsPanelData } from '@home/components/widget/lib/display-columns-panel.component'; -import { - AlarmDataInfo, - alarmFields, - AlarmInfo, - alarmSeverityColors, - alarmSeverityTranslations, - AlarmStatus, - alarmStatusTranslations -} from '@shared/models/alarm.models'; +import { AlarmDataInfo, alarmFields, AlarmInfo, alarmSeverityColors, AlarmStatus } from '@shared/models/alarm.models'; import { DatePipe } from '@angular/common'; import { AlarmDetailsDialogComponent, @@ -139,7 +131,6 @@ import { AlarmFilterConfigData } from '@home/components/alarm/alarm-filter-config.component'; import { getCurrentAuthUser } from '@core/auth/auth.selectors'; -import { UserId } from '@shared/models/id/user-id'; interface AlarmsTableWidgetSettings extends TableWidgetSettings { alarmsTitle: string; @@ -167,7 +158,7 @@ interface AlarmWidgetActionDescriptor extends TableCellButtonActionDescriptor { templateUrl: './alarms-table-widget.component.html', styleUrls: ['./alarms-table-widget.component.scss', './table-widget.scss'] }) -export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, AfterViewInit { +export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, OnDestroy, AfterViewInit { @Input() ctx: WidgetContext; @@ -431,7 +422,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, keySettings.columnWidth = '120px'; } if (alarmField && alarmField.keyName === alarmFields.assignee.keyName) { - keySettings.columnWidth = '120px' + keySettings.columnWidth = '120px'; } } this.stylesInfo[dataKey.def] = getCellStyleInfo(keySettings, 'value, alarm, ctx'); @@ -543,14 +534,12 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, overlayRef.dispose(); }); - const columns: DisplayColumn[] = this.columns.map(column => { - return { + const columns: DisplayColumn[] = this.columns.map(column => ({ title: column.title, def: column.def, display: this.displayedColumns.indexOf(column.def) > -1, selectable: this.columnSelectionAvailability[column.def] - }; - }); + })); const providers: StaticProvider[] = [ { @@ -1010,7 +999,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, data: { alarmId: alarm.id.id } - }).afterClosed() + }).afterClosed(); } } @@ -1018,20 +1007,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, if (isDefined(value)) { const alarmField = alarmFields[key.name]; if (alarmField) { - if (alarmField.time) { - return value ? this.datePipe.transform(value, 'yyyy-MM-dd HH:mm:ss') : ''; - } else if (alarmField.value === alarmFields.severity.value) { - return this.translate.instant(alarmSeverityTranslations.get(value)); - } else if (alarmField.value === alarmFields.status.value) { - return alarmStatusTranslations.get(value) ? this.translate.instant(alarmStatusTranslations.get(value)) : value; - } else if (alarmField.value === alarmFields.originatorType.value) { - return this.translate.instant(entityTypeTranslations.get(value).type); - } else if (alarmField.value === alarmFields.assignee.value) { - return ''; - } - else { - return value; - } + return this.utils.defaultAlarmFieldContent(key, value); } const entityField = entityFields[key.name]; if (entityField) { From 2f1290e7e1be7b01c76b2f1a0da911fa03b171b6 Mon Sep 17 00:00:00 2001 From: Ruslan Vasylkiv <87172504+rusikv@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:24:45 +0300 Subject: [PATCH 252/421] Delete timeseries UI implementation (#8932) --- ui-ngx/src/app/core/http/attribute.service.ts | 14 ++- .../attribute/attribute-table.component.html | 12 +++ .../attribute/attribute-table.component.ts | 83 ++++++++++++++- .../delete-timeseries-panel.component.html | 74 +++++++++++++ .../delete-timeseries-panel.component.scss | 28 +++++ .../delete-timeseries-panel.component.ts | 100 ++++++++++++++++++ .../home/components/home-components.module.ts | 2 + .../models/telemetry/telemetry.models.ts | 18 +++- .../assets/locale/locale.constant-ca_ES.json | 2 +- .../assets/locale/locale.constant-cs_CZ.json | 2 +- .../assets/locale/locale.constant-da_DK.json | 2 +- .../assets/locale/locale.constant-de_DE.json | 2 +- .../assets/locale/locale.constant-el_GR.json | 2 +- .../assets/locale/locale.constant-en_US.json | 15 ++- .../assets/locale/locale.constant-es_ES.json | 2 +- .../assets/locale/locale.constant-fa_IR.json | 2 +- .../assets/locale/locale.constant-fr_FR.json | 2 +- .../assets/locale/locale.constant-it_IT.json | 2 +- .../assets/locale/locale.constant-ja_JP.json | 2 +- .../assets/locale/locale.constant-ka_GE.json | 2 +- .../assets/locale/locale.constant-ko_KR.json | 2 +- .../assets/locale/locale.constant-lv_LV.json | 2 +- .../assets/locale/locale.constant-pt_BR.json | 2 +- .../assets/locale/locale.constant-ro_RO.json | 2 +- .../assets/locale/locale.constant-sl_SI.json | 2 +- .../assets/locale/locale.constant-tr_TR.json | 2 +- .../assets/locale/locale.constant-uk_UA.json | 2 +- .../assets/locale/locale.constant-zh_CN.json | 2 +- .../assets/locale/locale.constant-zh_TW.json | 2 +- 29 files changed, 357 insertions(+), 29 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html create mode 100644 ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts diff --git a/ui-ngx/src/app/core/http/attribute.service.ts b/ui-ngx/src/app/core/http/attribute.service.ts index 67132d8983..b772cd63e6 100644 --- a/ui-ngx/src/app/core/http/attribute.service.ts +++ b/ui-ngx/src/app/core/http/attribute.service.ts @@ -50,10 +50,11 @@ export class AttributeService { } public deleteEntityTimeseries(entityId: EntityId, timeseries: Array, deleteAllDataForKeys = false, - startTs?: number, endTs?: number, config?: RequestConfig): Observable { + startTs?: number, endTs?: number, rewriteLatestIfDeleted = false, deleteLatest = false, + config?: RequestConfig): Observable { const keys = timeseries.map(attribute => encodeURIComponent(attribute.key)).join(','); let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/delete` + - `?keys=${keys}&deleteAllDataForKeys=${deleteAllDataForKeys}`; + `?keys=${keys}&deleteAllDataForKeys=${deleteAllDataForKeys}&rewriteLatestIfDeleted=${rewriteLatestIfDeleted}&deleteLatest=${deleteLatest}`; if (isDefinedAndNotNull(startTs)) { url += `&startTs=${startTs}`; } @@ -63,6 +64,12 @@ export class AttributeService { return this.http.delete(url, defaultHttpOptionsFromConfig(config)); } + public deleteEntityLatestTimeseries(entityId: EntityId, timeseries: Array, config?: RequestConfig): Observable { + const keys = timeseries.map(attribute => encodeURIComponent(attribute.key)).join(','); + let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/latest/delete?keys=${keys}`; + return this.http.delete(url, defaultHttpOptionsFromConfig(config)); + } + public saveEntityAttributes(entityId: EntityId, attributeScope: AttributeScope, attributes: Array, config?: RequestConfig): Observable { const attributesData: {[key: string]: any} = {}; @@ -103,7 +110,8 @@ export class AttributeService { }); let deleteEntityTimeseriesObservable: Observable; if (deleteTimeseries.length) { - deleteEntityTimeseriesObservable = this.deleteEntityTimeseries(entityId, deleteTimeseries, true, null, null, config); + deleteEntityTimeseriesObservable = this.deleteEntityTimeseries(entityId, deleteTimeseries, true, + null, null, false, false, config); } else { deleteEntityTimeseriesObservable = of(null); } diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html index 32ebb28ae9..1def300b78 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html @@ -93,6 +93,14 @@ (click)="deleteAttributes($event)"> delete +
diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts index e9d67a3fdd..13a7ef0a70 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts @@ -38,7 +38,7 @@ import { TranslateService } from '@ngx-translate/core'; import { MatDialog } from '@angular/material/dialog'; import { DialogService } from '@core/services/dialog.service'; import { Direction, SortOrder } from '@shared/models/page/sort-order'; -import { fromEvent, merge } from 'rxjs'; +import { fromEvent, merge, Observable } from 'rxjs'; import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; import { EntityId } from '@shared/models/id/entity-id'; import { @@ -48,7 +48,7 @@ import { isClientSideTelemetryType, LatestTelemetry, TelemetryType, - telemetryTypeTranslations, + telemetryTypeTranslations, TimeseriesDeleteStrategy, toTelemetryType } from '@shared/models/telemetry/telemetry.models'; import { AttributeDatasource } from '@home/models/datasource/attribute-datasource'; @@ -82,10 +82,14 @@ import { AddWidgetToDashboardDialogComponent, AddWidgetToDashboardDialogData } from '@home/components/attribute/add-widget-to-dashboard-dialog.component'; -import { deepClone } from '@core/utils'; +import { deepClone, isUndefinedOrNull } from '@core/utils'; import { Filters } from '@shared/models/query/query.models'; import { hidePageSizePixelValue } from '@shared/models/constants'; import { ResizeObserver } from '@juggle/resize-observer'; +import { + DELETE_TIMESERIES_PANEL_DATA, + DeleteTimeseriesPanelComponent, DeleteTimeseriesPanelData +} from '@home/components/attribute/delete-timeseries-panel.component'; @Component({ @@ -378,6 +382,79 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI }); } + deleteTimeseries($event: Event, attribute?: AttributeData) { + if ($event) { + $event.stopPropagation(); + } + const isMultipleDeletion = isUndefinedOrNull(attribute); + const target = $event.target || $event.srcElement || $event.currentTarget; + const config = new OverlayConfig(); + config.backdropClass = 'cdk-overlay-transparent-backdrop'; + config.hasBackdrop = true; + const connectedPosition: ConnectedPosition = { + originX: 'start', + originY: 'top', + overlayX: 'end', + overlayY: 'top' + }; + config.positionStrategy = this.overlay.position().flexibleConnectedTo(target as HTMLElement) + .withPositions([connectedPosition]); + config.maxWidth = '488px'; + config.width = '100%'; + const overlayRef = this.overlay.create(config); + overlayRef.backdropClick().subscribe(() => { + overlayRef.dispose(); + }); + + const providers: StaticProvider[] = [ + { + provide: DELETE_TIMESERIES_PANEL_DATA, + useValue: { + isMultipleDeletion: isMultipleDeletion + } as DeleteTimeseriesPanelData + }, + { + provide: OverlayRef, + useValue: overlayRef + } + ]; + const injector = Injector.create({parent: this.viewContainerRef.injector, providers}); + const componentRef = overlayRef.attach(new ComponentPortal(DeleteTimeseriesPanelComponent, + this.viewContainerRef, injector)); + componentRef.onDestroy(() => { + if (componentRef.instance.result !== null) { + const strategy = componentRef.instance.result; + const timeseries = isMultipleDeletion ? this.dataSource.selection.selected : [attribute]; + let deleteAllDataForKeys = false; + let rewriteLatestIfDeleted = false; + let startTs = null; + let endTs = null; + let deleteLatest = false; + let task: Observable; + if (strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA_INCLUDING_KEY) { + deleteAllDataForKeys = true; + deleteLatest = true; + } + if (strategy === TimeseriesDeleteStrategy.DELETE_OLD_DATA_EXCEPT_LATEST_VALUE) { + deleteAllDataForKeys = true; + } + if (strategy === TimeseriesDeleteStrategy.DELETE_LATEST_VALUE) { + task = this.attributeService.deleteEntityLatestTimeseries(this.entityIdValue, timeseries); + } + if (strategy === TimeseriesDeleteStrategy.DELETE_DATA_FOR_TIME_PERIOD) { + startTs = componentRef.instance.startDateTime.getTime(); + endTs = componentRef.instance.endDateTime.getTime(); + rewriteLatestIfDeleted = componentRef.instance.rewriteLatestIfDeleted; + } + if (!task) { + task = this.attributeService.deleteEntityTimeseries(this.entityIdValue, timeseries, deleteAllDataForKeys, + startTs, endTs, rewriteLatestIfDeleted, deleteLatest); + } + task.subscribe(() => this.reloadAttributes()); + } + }); + } + deleteAttributes($event: Event) { if ($event) { $event.stopPropagation(); diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html new file mode 100644 index 0000000000..e164cb56ed --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html @@ -0,0 +1,74 @@ + + +
+ +

{{ "attribute.delete-timeseries.delete-strategy" | translate }}

+ + +
+
+ + attribute.delete-timeseries.strategy + + + {{ strategiesTranslationsMap.get(strategy) | translate }} + + + +
+
+ + attribute.delete-timeseries.start-time + + + + + + attribute.delete-timeseries.ends-on + + + + +
+ + {{ "attribute.delete-timeseries.rewrite-latest-value-if-deleted" | translate }} + +
+
+
+ + + +
+
+ diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss new file mode 100644 index 0000000000..c0f26644d5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss @@ -0,0 +1,28 @@ +/** + * Copyright © 2016-2023 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 { + width: 100%; + background-color: #fff; + box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3), 0px 2px 6px 2px rgba(0, 0, 0, 0.15); + border-radius: 4px; +} + +:host ::ng-deep{ + div .mat-toolbar { + background: none; + } +} diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts new file mode 100644 index 0000000000..914e5246f7 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts @@ -0,0 +1,100 @@ +/// +/// Copyright © 2016-2023 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, InjectionToken, OnInit } from '@angular/core'; +import { OverlayRef } from '@angular/cdk/overlay'; +import { + TimeseriesDeleteStrategy, + timeseriesDeleteStrategyTranslations +} from '@shared/models/telemetry/telemetry.models'; +import { MINUTE } from '@shared/models/time/time.models'; + +export const DELETE_TIMESERIES_PANEL_DATA = new InjectionToken('DeleteTimeseriesPanelData'); + +export interface DeleteTimeseriesPanelData { + isMultipleDeletion: boolean; +} + +@Component({ + selector: 'tb-delete-timeseries-panel', + templateUrl: './delete-timeseries-panel.component.html', + styleUrls: ['./delete-timeseries-panel.component.scss'] +}) +export class DeleteTimeseriesPanelComponent implements OnInit { + + strategy: string = TimeseriesDeleteStrategy.DELETE_ALL_DATA_INCLUDING_KEY; + + result: string = null; + + startDateTime: Date; + + endDateTime: Date; + + rewriteLatestIfDeleted: boolean = false; + + strategiesTranslationsMap = timeseriesDeleteStrategyTranslations; + + multipleDeletionStrategies = [ + TimeseriesDeleteStrategy.DELETE_ALL_DATA_INCLUDING_KEY, + TimeseriesDeleteStrategy.DELETE_OLD_DATA_EXCEPT_LATEST_VALUE + ]; + + constructor(@Inject(DELETE_TIMESERIES_PANEL_DATA) public data: DeleteTimeseriesPanelData, + public overlayRef: OverlayRef) { } + + ngOnInit(): void { + let today = new Date(); + this.startDateTime = new Date(today.getFullYear(), today.getMonth() - 1, today.getDate()); + this.endDateTime = today; + if (this.data.isMultipleDeletion) { + this.strategiesTranslationsMap = new Map(Array.from(this.strategiesTranslationsMap.entries()) + .filter(([strategy]) => { + return this.multipleDeletionStrategies.includes(strategy); + })) + } + } + + delete(): void { + this.result = this.strategy; + this.overlayRef.dispose(); + } + + cancel(): void { + this.overlayRef.dispose(); + } + + isPeriodStrategy(): boolean { + return this.strategy === TimeseriesDeleteStrategy.DELETE_DATA_FOR_TIME_PERIOD; + } + + onStartDateTimeChange(newStartDateTime: Date) { + const endDateTimeTs = this.endDateTime.getTime(); + if (newStartDateTime.getTime() >= endDateTimeTs) { + this.startDateTime = new Date(endDateTimeTs - MINUTE); + } else { + this.startDateTime = newStartDateTime; + } + } + + onEndDateTimeChange(newEndDateTime: Date) { + const startDateTimeTs = this.startDateTime.getTime(); + if (newEndDateTime.getTime() <= startDateTimeTs) { + this.endDateTime = new Date(startDateTimeTs + MINUTE); + } else { + this.endDateTime = newEndDateTime; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index a6e2cc03dc..a18f785b35 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -177,6 +177,7 @@ import { } from '@home/components/widget/action/manage-widget-actions-dialog.component'; import { WidgetConfigComponentsModule } from '@home/components/widget/config/widget-config-components.module'; import { BasicWidgetConfigModule } from '@home/components/widget/config/basic/basic-widget-config.module'; +import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delete-timeseries-panel.component'; @NgModule({ declarations: @@ -205,6 +206,7 @@ import { BasicWidgetConfigModule } from '@home/components/widget/config/basic/ba AttributeTableComponent, AddAttributeDialogComponent, EditAttributeValuePanelComponent, + DeleteTimeseriesPanelComponent, AliasesEntitySelectPanelComponent, AliasesEntitySelectComponent, AliasesEntityAutocompleteComponent, diff --git a/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts b/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts index 50cbef2f8b..76f6b0f247 100644 --- a/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts +++ b/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts @@ -61,6 +61,13 @@ export enum TelemetryFeature { TIMESERIES = 'TIMESERIES' } +export enum TimeseriesDeleteStrategy { + DELETE_ALL_DATA_INCLUDING_KEY = 'DELETE_ALL_DATA_INCLUDING_KEY', + DELETE_OLD_DATA_EXCEPT_LATEST_VALUE = 'DELETE_OLD_DATA_EXCEPT_LATEST_VALUE', + DELETE_LATEST_VALUE = 'DELETE_LATEST_VALUE', + DELETE_DATA_FOR_TIME_PERIOD = 'DELETE_DATA_FOR_TIME_PERIOD' +} + export type TelemetryType = LatestTelemetry | AttributeScope; export const toTelemetryType = (val: string): TelemetryType => { @@ -73,7 +80,7 @@ export const toTelemetryType = (val: string): TelemetryType => { export const telemetryTypeTranslations = new Map( [ - [LatestTelemetry.LATEST_TELEMETRY, 'attribute.scope-latest-telemetry'], + [LatestTelemetry.LATEST_TELEMETRY, 'attribute.scope-telemetry'], [AttributeScope.CLIENT_SCOPE, 'attribute.scope-client'], [AttributeScope.SERVER_SCOPE, 'attribute.scope-server'], [AttributeScope.SHARED_SCOPE, 'attribute.scope-shared'] @@ -89,6 +96,15 @@ export const isClientSideTelemetryType = new Map( ] ); +export const timeseriesDeleteStrategyTranslations = new Map( + [ + [TimeseriesDeleteStrategy.DELETE_ALL_DATA_INCLUDING_KEY, 'attribute.delete-timeseries.all-data-including-key'], + [TimeseriesDeleteStrategy.DELETE_OLD_DATA_EXCEPT_LATEST_VALUE, 'attribute.delete-timeseries.old-data-except-latest'], + [TimeseriesDeleteStrategy.DELETE_LATEST_VALUE, 'attribute.delete-timeseries.latest-value'], + [TimeseriesDeleteStrategy.DELETE_DATA_FOR_TIME_PERIOD, 'attribute.delete-timeseries.data-for-time-period'] + ] +) + export interface AttributeData { lastUpdateTs?: number; key: string; 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 349d13da2c..edb406d9cb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -632,7 +632,7 @@ "attributes": "Atributs", "latest-telemetry": "Última telemetria", "attributes-scope": "Abast dels atributs del dispositiu", - "scope-latest-telemetry": "Última telemetria", + "scope-telemetry": "Telemetria", "scope-client": "Atributs del Client", "scope-server": "Atributs del Servidor", "scope-shared": "Atributs Compartits", 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 52873b4d70..5697486e37 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -445,7 +445,7 @@ "attributes": "Atributy", "latest-telemetry": "Poslední telemetrie", "attributes-scope": "Rozsah atributů entity", - "scope-latest-telemetry": "Poslední telemetrie", + "scope-telemetry": "Telemetrie", "scope-client": "Atributy klienta", "scope-server": "Atributy serveru", "scope-shared": "Sdílené atributy", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 2c1df70902..1486870a7a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -453,7 +453,7 @@ "attributes": "Attributter", "latest-telemetry": "Seneste telemetri", "attributes-scope": "Omfang af entitetsattributter", - "scope-latest-telemetry": "Seneste telemetri", + "scope-telemetry": "Telemetri", "scope-client": "Klientattributter", "scope-server": "Serverattributter", "scope-shared": "Delte attributter", 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 ed73ad25cf..c27d63f4fb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-de_DE.json +++ b/ui-ngx/src/assets/locale/locale.constant-de_DE.json @@ -324,7 +324,7 @@ "attributes": "Eigenschaften", "latest-telemetry": "Neueste Telemetrie", "attributes-scope": "Entitätseigenschaftsbereich", - "scope-latest-telemetry": "Neueste Telemetrie", + "scope-telemetry": "Telemetrie", "scope-client": "Client Eigenschaften", "scope-server": "Server Eigenschaften", "scope-shared": "Gemeinsame Eigenschaften", diff --git a/ui-ngx/src/assets/locale/locale.constant-el_GR.json b/ui-ngx/src/assets/locale/locale.constant-el_GR.json index 453b5dd83c..36e8e4e000 100644 --- a/ui-ngx/src/assets/locale/locale.constant-el_GR.json +++ b/ui-ngx/src/assets/locale/locale.constant-el_GR.json @@ -291,7 +291,7 @@ "attributes": "Χαρακτηριστικά", "latest-telemetry": "Τελευταία τηλεμετρία", "attributes-scope": "Πεδίο εφαρμογής Χαρακτηριστικών Οντότητας", - "scope-latest-telemetry": "Τελευταία τηλεμετρία", + "scope-telemetry": "Τηλεμετρία", "scope-client": "Χαρακτηριστικά Client", "scope-server": "Χαρακτηριστικά Server", "scope-shared": "Κοινόχρηστα Χαρακτηριστικά", 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 82f10b7f4c..091ee1e3bf 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -691,7 +691,7 @@ "attributes": "Attributes", "latest-telemetry": "Latest telemetry", "attributes-scope": "Entity attributes scope", - "scope-latest-telemetry": "Latest telemetry", + "scope-telemetry": "Telemetry", "scope-client": "Client attributes", "scope-server": "Server attributes", "scope-shared": "Shared attributes", @@ -717,7 +717,18 @@ "no-attributes-text": "No attributes found", "no-telemetry-text": "No telemetry found", "copy-key": "Copy key", - "copy-value": "Copy value" + "copy-value": "Copy value", + "delete-timeseries": { + "start-time": "Start time", + "ends-on": "Ends on", + "strategy": "Strategy", + "delete-strategy": "Delete strategy", + "all-data-including-key": "Delete all data including key", + "old-data-except-latest": "Delete old data except latest value", + "latest-value": "Delete latest value", + "data-for-time-period": "Delete data for time period", + "rewrite-latest-value-if-deleted": "Rewrite latest value if deleted" + } }, "api-usage": { "api-features": "API features", 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 6518e03f58..62152e998d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -667,7 +667,7 @@ "attributes": "Atributos", "latest-telemetry": "Última telemetría", "attributes-scope": "Alcance de los atributos del dispositivo", - "scope-latest-telemetry": "Última telemetría", + "scope-telemetry": "Telemetría", "scope-client": "Atributos de Cliente", "scope-server": "Atributos de Servidor", "scope-shared": "Atributos Compartidos", diff --git a/ui-ngx/src/assets/locale/locale.constant-fa_IR.json b/ui-ngx/src/assets/locale/locale.constant-fa_IR.json index 6e5026b011..da841a6e53 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fa_IR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fa_IR.json @@ -254,7 +254,7 @@ "attributes": "ويژگي ها", "latest-telemetry": "آخرين سنجش", "attributes-scope": "حوزه ويژگي هاي موجودي", - "scope-latest-telemetry": "آخرين سنجش", + "scope-telemetry": "تله متری", "scope-client": "ويژگي هاي مشتري", "scope-server": "ويژگي هاي سِروِر", "scope-shared": "ويژگي هاي مشترک", 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 19f92e5a7c..a929477d5e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -459,7 +459,7 @@ "next-widget": "Widget suivant", "prev-widget": "Widget précédent", "scope-client": "Attributs du client", - "scope-latest-telemetry": "Dernière télémétrie", + "scope-telemetry": "Télémétrie", "scope-server": "Attributs du serveur", "scope-shared": "Attributs partagés", "selected-attributes": "{count, plural, =1 {1 attribut} other {# attributs} } sélectionnés", diff --git a/ui-ngx/src/assets/locale/locale.constant-it_IT.json b/ui-ngx/src/assets/locale/locale.constant-it_IT.json index 94acd17f82..2c093e76a9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-it_IT.json +++ b/ui-ngx/src/assets/locale/locale.constant-it_IT.json @@ -276,7 +276,7 @@ "attributes": "Attributi", "latest-telemetry": "Ultima telemetria", "attributes-scope": "Visibilità attributi entità", - "scope-latest-telemetry": "Ultima telemetria", + "scope-telemetry": "Telemetria", "scope-client": "Attributi client", "scope-server": "Attributi server", "scope-shared": "Attributi condivisi", diff --git a/ui-ngx/src/assets/locale/locale.constant-ja_JP.json b/ui-ngx/src/assets/locale/locale.constant-ja_JP.json index f63a6681a2..23145c1f89 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ja_JP.json +++ b/ui-ngx/src/assets/locale/locale.constant-ja_JP.json @@ -244,7 +244,7 @@ "attributes": "属性", "latest-telemetry": "最新テレメトリ", "attributes-scope": "エンティティ属性のスコープ", - "scope-latest-telemetry": "最新テレメトリ", + "scope-telemetry": "テレメトリー", "scope-client": "クライアントの属性", "scope-server": "サーバーの属性", "scope-shared": "共有属性", diff --git a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json index a6c5a6576d..89d25703e3 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json +++ b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json @@ -290,7 +290,7 @@ "attributes": "ატრიბუტები", "latest-telemetry": "უახლესი ტელემეტრია", "attributes-scope": "ობიექტის ატრიბუტების ფარგლები", - "scope-latest-telemetry": "უახლესი ტელემეტრია", + "scope-telemetry": "ტელემეტრია", "scope-client": "კლიენტის ატრიბუტები", "scope-server": "სერვერის ატრიბუტები", "scope-shared": "ატრიბუტების გაზიარება", diff --git a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json index 758482f578..3da051ec1a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -408,7 +408,7 @@ "attributes": "속성", "latest-telemetry": "최근 데이터", "attributes-scope": "장치 속성 범위", - "scope-latest-telemetry": "최근 데이터", + "scope-telemetry": "원격 측정", "scope-client": "클라이언트 속성", "scope-server": "서버 속성", "scope-shared": "공유 속성", diff --git a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json index d584f2da96..f4f5befc14 100644 --- a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json +++ b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json @@ -256,7 +256,7 @@ "attributes": "Attribūti", "latest-telemetry": "Jaunākā telemetrija", "attributes-scope": "Vienības atribūtu darbības joma", - "scope-latest-telemetry": "Jaunākā telemetrija", + "scope-telemetry": "Telemetrija", "scope-client": "Klientu atribūti", "scope-server": "Servera atribūti", "scope-shared": "Dalītie atribūti", diff --git a/ui-ngx/src/assets/locale/locale.constant-pt_BR.json b/ui-ngx/src/assets/locale/locale.constant-pt_BR.json index 2bba0338d2..28c7082df9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-pt_BR.json +++ b/ui-ngx/src/assets/locale/locale.constant-pt_BR.json @@ -309,7 +309,7 @@ "attributes": "Atributos", "latest-telemetry": "Última telemetria", "attributes-scope": "Escopo de atributos de entidade", - "scope-latest-telemetry": "Última telemetria", + "scope-telemetry": "Telemetria", "scope-client": "Atributos do cliente", "scope-server": "Atributos do servidor", "scope-shared": "Atributos compartilhados", diff --git a/ui-ngx/src/assets/locale/locale.constant-ro_RO.json b/ui-ngx/src/assets/locale/locale.constant-ro_RO.json index fa5cee48c9..da0012e6f6 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ro_RO.json +++ b/ui-ngx/src/assets/locale/locale.constant-ro_RO.json @@ -285,7 +285,7 @@ "attributes": "Atribute", "latest-telemetry": "Ultimele Date Telemetrice", "attributes-scope": "Scop Atribute Entitate", - "scope-latest-telemetry": "Ultimele Date Telemetrice", + "scope-telemetry": "Telemetrie", "scope-client": "Atribute Client", "scope-server": "Atribute Server", "scope-shared": "Atribute Partajate", diff --git a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json index 8aced0ddc6..e53e4fc7c0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -408,7 +408,7 @@ "attributes": "Lastnosti", "latest-telemetry": "Najnovejša telemetrija", "attributes-scope": "Obseg atributov entitete", - "scope-latest-telemetry": "Najnovejša telemetrija", + "scope-telemetry": "Telemetrija", "scope-client": "Atributi odjemalca", "scope-server": "Atributi strežnika", "scope-shared": "Skupni atributi", 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 b175a2d51a..ae79f0c81c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -445,7 +445,7 @@ "attributes": "Öznitelikler", "latest-telemetry": "Son telemetri", "attributes-scope": "Varlık öznitelik kapsamı", - "scope-latest-telemetry": "Son telemetri", + "scope-telemetry": "telemetri", "scope-client": "İstemci öznitelikler", "scope-server": "Sunucu öznitelikler", "scope-shared": "Paylaşılan öznitelikler", 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 7aa541e57f..bd608cd709 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -342,7 +342,7 @@ "attributes": "Атрибути", "latest-telemetry": "Остання телеметрія", "attributes-scope": "Область видимості атрибутів", - "scope-latest-telemetry": "Остання телеметрія", + "scope-telemetry": "Телеметрія", "scope-client": "Клієнтські атрибути", "scope-server": "Серверні атрибути", "scope-shared": "Спільні атрибути", 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 b39e10e46c..4c33ac46a2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -590,7 +590,7 @@ "attributes": "属性", "latest-telemetry": "最新遥测数据", "attributes-scope": "设备属性范围", - "scope-latest-telemetry": "最新遥测数据", + "scope-telemetry": "遥测", "scope-client": "客户端属性", "scope-server": "服务端属性", "scope-shared": "共享属性", 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 f2cce81824..3a1c4edd83 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -519,7 +519,7 @@ "attributes": "屬性", "latest-telemetry": "最新遙測", "attributes-scope": "設備屬性範圍", - "scope-latest-telemetry": "最新遙測", + "scope-telemetry": "遙測", "scope-client": "客戶端屬性", "scope-server": "服務端屬性", "scope-shared": "共享屬性", From b74e52d14ad730c1d752eab3e5439567aa3dca39 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 13 Jul 2023 18:14:50 +0300 Subject: [PATCH 253/421] UI: Improve color picker --- .../src/app/core/services/dialog.service.ts | 3 +- .../alarm/alarm-assignee.component.scss | 6 -- .../alarms-table-basic-config.component.html | 27 ++++----- ...entities-table-basic-config.component.html | 27 ++++----- .../simple-card-basic-config.component.html | 22 +++----- ...meseries-table-basic-config.component.html | 27 ++++----- .../chart/flot-basic-config.component.html | 27 ++++----- .../config/data-key-config.component.html | 11 ++-- .../widget/config/data-keys.component.html | 2 +- .../widget/config/data-keys.component.ts | 32 ++++++++--- .../chart/flot-key-settings.component.html | 11 ++-- .../flot-latest-key-settings.component.html | 11 ++-- .../chart/flot-widget-settings.component.html | 54 +++++++----------- .../widget/widget-config.component.html | 27 ++++----- .../components/color-input.component.html | 13 ++++- .../components/color-input.component.scss | 9 +++ .../components/color-input.component.ts | 42 +++++++++++++- .../color-picker-panel.component.html | 30 ++++++++++ .../color-picker-panel.component.scss | 36 ++++++++++++ .../color-picker-panel.component.ts | 55 +++++++++++++++++++ .../color-picker/color-picker.component.html | 14 ++++- .../color-picker/color-picker.component.scss | 39 ++++++++----- .../color-picker/color-picker.component.ts | 27 +++++---- .../dialog/color-picker-dialog.component.html | 30 ++++------ .../dialog/color-picker-dialog.component.scss | 22 ++++++++ .../dialog/color-picker-dialog.component.ts | 24 +++----- ui-ngx/src/app/shared/shared.module.ts | 3 + .../assets/locale/locale.constant-en_US.json | 3 + ui-ngx/src/form.scss | 53 +++++++++--------- 29 files changed, 423 insertions(+), 264 deletions(-) create mode 100644 ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html create mode 100644 ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss create mode 100644 ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts create mode 100644 ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss diff --git a/ui-ngx/src/app/core/services/dialog.service.ts b/ui-ngx/src/app/core/services/dialog.service.ts index 1daf90ac82..2ca2d6d87e 100644 --- a/ui-ngx/src/app/core/services/dialog.service.ts +++ b/ui-ngx/src/app/core/services/dialog.service.ts @@ -103,7 +103,8 @@ export class DialogService { panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { color - } + }, + autoFocus: false }).afterClosed(); } 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 947eeb01d0..3aed0ccb5e 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 @@ -45,9 +45,3 @@ margin-right: 8px; } } - -.drop-down-icon { - &.inline { - margin-right: -12px; - } -} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html index 90314b9cbe..18cd34609e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html @@ -58,16 +58,15 @@
-
+
{{ 'widget-config.card-icon' | translate }} -
+
- @@ -82,23 +81,17 @@ {{ 'fullscreen.fullscreen' | translate }}
-
+
{{ 'widget-config.text-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.background-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.card-icon' | translate }} -
+
- @@ -70,23 +69,17 @@ {{ 'fullscreen.fullscreen' | translate }}
-
+
{{ 'widget-config.text-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.background-color' | translate }}
-
- - - -
+ +
{{ 'fullscreen.fullscreen' | translate }}
-
+
{{ 'widget-config.text-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.background' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.card-icon' | translate }} -
+
- @@ -70,23 +69,17 @@ {{ 'fullscreen.fullscreen' | translate }}
-
+
{{ 'widget-config.text-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.background-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.card-icon' | translate }} -
+
- @@ -68,23 +67,17 @@ {{ 'fullscreen.fullscreen' | translate }}
-
+
{{ 'widget-config.text-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.background-color' | translate }}
-
- - - -
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html index a32735e0d1..8510e19f24 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html @@ -59,14 +59,11 @@
-
+
{{ 'datakey.color' | translate }}
-
- - - -
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html index 39fffd79e7..65daa6552c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html @@ -72,7 +72,7 @@
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts index 95fe5bc444..02060db364 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts @@ -27,6 +27,7 @@ import { SimpleChanges, SkipSelf, ViewChild, + ViewContainerRef, ViewEncapsulation } from '@angular/core'; import { @@ -56,7 +57,6 @@ import { alarmFields } from '@shared/models/alarm.models'; import { UtilsService } from '@core/services/utils.service'; import { ErrorStateMatcher } from '@angular/material/core'; import { TruncatePipe } from '@shared/pipe/truncate.pipe'; -import { DialogService } from '@core/services/dialog.service'; import { MatDialog } from '@angular/material/dialog'; import { DataKeyConfigDialogComponent, @@ -69,6 +69,8 @@ import { DndDropEvent } from 'ngx-drag-drop/lib/dnd-dropzone.directive'; import { moveItemInArray } from '@angular/cdk/drag-drop'; import { coerceBoolean } from '@shared/decorators/coercion'; import { DatasourceComponent } from '@home/components/widget/config/datasource.component'; +import { ColorPickerPanelComponent } from '@shared/components/color-picker/color-picker-panel.component'; +import { TbPopoverService } from '@shared/components/popover.service'; @Component({ selector: 'tb-data-keys', @@ -208,10 +210,11 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange private datasourceComponent: DatasourceComponent, public translate: TranslateService, private utils: UtilsService, - private dialogs: DialogService, private dialog: MatDialog, private fb: UntypedFormBuilder, private cd: ChangeDetectorRef, + private popoverService: TbPopoverService, + private viewContainerRef: ViewContainerRef, private renderer: Renderer2, public truncate: TruncatePipe) { } @@ -471,15 +474,30 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange this.propagateChange(this.modelValue); } - showColorPicker(key: DataKey) { - this.dialogs.colorPicker(key.color).subscribe( - (color) => { + openColorPickerPopup(key: DataKey, $event: Event, keyColorButton: HTMLDivElement) { + if ($event) { + $event.stopPropagation(); + } + const trigger = keyColorButton; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const colorPickerPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, ColorPickerPanelComponent, 'left', true, null, + { + color: key.color + }, + {}, + {}, {}, true); + colorPickerPopover.tbComponentRef.instance.popover = colorPickerPopover; + colorPickerPopover.tbComponentRef.instance.colorSelected.subscribe((color) => { + colorPickerPopover.hide(); if (color && key.color !== color) { key.color = color; this.propagateChange(this.modelValue); } - } - ); + }); + } } editDataKey(key: DataKey, index: number) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html index f3176f9834..96ff4d8559 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html @@ -235,14 +235,11 @@
-
+
{{ 'widgets.chart.comparison-line-color' | translate }}
-
- - - -
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html index cdff37f492..286d26481b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-latest-key-settings.component.html @@ -36,14 +36,11 @@ px
-
+
{{ 'widgets.chart.threshold-color' | translate }}
-
- - - -
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html index defc26856a..5dd7eaa2dc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html @@ -61,14 +61,13 @@
-
+
{{ 'widgets.chart.default-font' | translate }}
-
+
px - @@ -132,14 +131,11 @@ -
+
{{ 'widget-config.color' | translate }}
-
- - - -
+ +
widget-config.decimals-short
@@ -187,14 +183,11 @@ -
+
{{ 'widget-config.color' | translate }}
-
- - - -
+ +
@@ -213,36 +206,29 @@ {{ 'widgets.chart.horizontal-grid-lines' | translate }}
-
+
{{ 'widgets.chart.grid-lines-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widgets.chart.border' | translate }}
-
+
px -
-
+
{{ 'widgets.chart.background-color' | translate }}
-
- - - -
+ +
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 ab226987ca..68a9ed6f3d 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 @@ -48,11 +48,11 @@
-
+
{{ 'widget-config.display-icon' | translate }} -
+
@@ -60,7 +60,6 @@ - @@ -84,23 +83,17 @@
widget-config.card-style
-
+
{{ 'widget-config.text-color' | translate }}
-
- - - -
+ +
-
+
{{ 'widget-config.background-color' | translate }}
-
- - - -
+ +
{{ 'widget-config.padding' | translate }}
diff --git a/ui-ngx/src/app/shared/components/color-input.component.html b/ui-ngx/src/app/shared/components/color-input.component.html index 2a283f7d93..c027104c6e 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.html +++ b/ui-ngx/src/app/shared/components/color-input.component.html @@ -35,7 +35,14 @@ -
-
-
+
diff --git a/ui-ngx/src/app/shared/components/color-input.component.scss b/ui-ngx/src/app/shared/components/color-input.component.scss index ca8ffedc72..b81ac0fdf8 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.scss +++ b/ui-ngx/src/app/shared/components/color-input.component.scss @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@import './../../../scss/mixins'; + :host { .mat-mdc-form-field { width: 100%; @@ -29,4 +32,10 @@ margin: 0; } } + button.mat-mdc-button-base.color-box { + width: 40px; + min-width: 40px; + height: 40px; + padding: 7px; + } } diff --git a/ui-ngx/src/app/shared/components/color-input.component.ts b/ui-ngx/src/app/shared/components/color-input.component.ts index fa6c73116e..f22b91fde2 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.ts +++ b/ui-ngx/src/app/shared/components/color-input.component.ts @@ -14,15 +14,24 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, forwardRef, Input, OnInit, 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, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { + ControlValueAccessor, + NG_VALUE_ACCESSOR, + UntypedFormBuilder, + UntypedFormGroup, + Validators +} from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { DialogService } from '@core/services/dialog.service'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { ColorPickerPanelComponent } from '@shared/components/color-picker/color-picker-panel.component'; +import { MatButton } from '@angular/material/button'; @Component({ selector: 'tb-color-input', @@ -100,6 +109,9 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro constructor(protected store: Store, private dialogs: DialogService, private translate: TranslateService, + private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef, private fb: UntypedFormBuilder, private cd: ChangeDetectorRef) { super(store); @@ -167,6 +179,32 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro ); } + openColorPickerPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const colorPickerPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, ColorPickerPanelComponent, 'left', true, null, + { + color: this.colorFormGroup.get('color').value + }, + {}, + {}, {}, true); + colorPickerPopover.tbComponentRef.instance.popover = colorPickerPopover; + colorPickerPopover.tbComponentRef.instance.colorSelected.subscribe((color) => { + colorPickerPopover.hide(); + this.colorFormGroup.patchValue( + {color}, {emitEvent: true} + ); + this.cd.markForCheck(); + }); + } + } + clear() { this.colorFormGroup.get('color').patchValue(null, {emitEvent: true}); this.cd.markForCheck(); diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html new file mode 100644 index 0000000000..56e4523b67 --- /dev/null +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.html @@ -0,0 +1,30 @@ + +
+
color.color
+ +
+ +
+
diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss new file mode 100644 index 0000000000..e7d78b4018 --- /dev/null +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.scss @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2023 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. + */ +.tb-color-picker-panel { + width: 328px; + display: flex; + flex-direction: column; + gap: 16px; + .tb-color-picker-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-color-picker-panel-buttons { + height: 60px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts new file mode 100644 index 0000000000..59199388b8 --- /dev/null +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker-panel.component.ts @@ -0,0 +1,55 @@ +/// +/// Copyright © 2016-2023 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 { PageComponent } from '@shared/components/page.component'; +import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { UntypedFormControl } from '@angular/forms'; +import { TbPopoverComponent } from '@shared/components/popover.component'; + +@Component({ + selector: 'tb-color-picker-panel', + templateUrl: './color-picker-panel.component.html', + providers: [], + styleUrls: ['./color-picker-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ColorPickerPanelComponent extends PageComponent implements OnInit { + + @Input() + color: string; + + @Input() + popover: TbPopoverComponent; + + @Output() + colorSelected = new EventEmitter(); + + colorPickerControl: UntypedFormControl; + + constructor(protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.colorPickerControl = new UntypedFormControl(this.color); + } + + selectColor() { + this.colorSelected.emit(this.colorPickerControl.value); + } +} diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html index d1432d27f5..5806037c89 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.html @@ -19,7 +19,7 @@
@@ -29,7 +29,12 @@
-
+ + HEX + RGBA + HSLA + +
-
+
+ +
+
diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss index ea2bfa94ba..dc1d3b5042 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.scss @@ -17,12 +17,10 @@ width: 100%; display: flex; flex-direction: column; - gap: 16px; + gap: 32px; .saturation-component { - height: 100%; - min-height: 200px; - max-height: 300px; + height: 238px; border-radius: 8px; } @@ -55,6 +53,12 @@ .color-input-block { display: flex; + gap: 20px; + + .presentation-select { + font-size: 14px; + width: 56px; + } .color-input { flex: 1; @@ -63,16 +67,13 @@ color: initial; } } + } - .type-btn { - height: 26px; - width: 20px; - background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAgCAMAAAAootjDAAAAM1BMVEUAAAAzMzMzMzMzMzMzMzM0NDQzMzMzMzM0NDQzMzMzMzM0NDQzMzMzMzMyMjIrKyszMzPF8UZlAAAAEHRSTlMA1fHr4ZxxSRP45sG+sCkGH2+Z6QAAAHJJREFUKM+9kkkSgCAQA0FEVLb5/2tViqgQvNrHviSzKGCt6nDGuNass8i8NsrLiX+bZbrUtDwm7VLYE0zWUtEZ+RvUZpEvN8YhH9QmQRoC8kFpEnVHVP/DJUZVeSAem5fDKxwtms/BR+PT8gN8vwk/0wE1gQzNVYryIwAAAABJRU5ErkJggg==') no-repeat center; - background-size: 6px 12px; - - &:hover { - background-color: #eee; - } + .color-presets-block { + .color-presets-component { + display: flex; + flex-direction: column; + gap: 12px; } } } @@ -105,4 +106,16 @@ } } } + + .color-presets-component { + .presets-row { + gap: 10px; + justify-content: space-between; + } + color-preset { + height: 20px; + width: 20px; + border-radius: 4px; + } + } } diff --git a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts index ce49310b03..47a745819d 100644 --- a/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts +++ b/ui-ngx/src/app/shared/components/color-picker/color-picker.component.ts @@ -17,7 +17,7 @@ import { Component, forwardRef, OnDestroy } from '@angular/core'; import { Color, ColorPickerControl } from '@iplab/ngx-color-picker'; import { Subscription } from 'rxjs'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; export enum ColorType { hex = 'hex', @@ -29,6 +29,10 @@ export enum ColorType { cmyk = 'cmyk' } +const colorPresetsHex = + ['#435B63', '#F44336', '#E89623', '#F5DD00', '#8BC34A', '#4CAF50', '#009688', '#048AD3', '#673AB7', '#9C27B0', '#E91E63', + '#A1ADB1', '#F9A19B', '#FFD190', '#FFF59D', '#C5E1A4', '#A5D7A7', '#80CBC3', '#81C4E9', '#B39CDB', '#CD93D7', '#F48FB1']; + @Component({ selector: `tb-color-picker`, templateUrl: `./color-picker.component.html`, @@ -43,10 +47,13 @@ export enum ColorType { }) export class ColorPickerComponent implements ControlValueAccessor, OnDestroy { - selectedPresentation = 0; presentations = [ColorType.hex, ColorType.rgba, ColorType.hsla]; control = new ColorPickerControl(); + presentationControl = new UntypedFormControl(0); + + colorPresets: Color[] = colorPresetsHex.map(c => Color.from(c)); + private modelValue: string; private subscriptions: Array = []; @@ -65,6 +72,11 @@ export class ColorPickerComponent implements ControlValueAccessor, OnDestroy { } }) ); + this.subscriptions.push( + this.presentationControl.valueChanges.subscribe(() => { + this.updateModel(); + }) + ); } registerOnChange(fn: any): void { @@ -86,12 +98,11 @@ export class ColorPickerComponent implements ControlValueAccessor, OnDestroy { } else if (this.control.initType === ColorType.hsl) { this.control.initType = ColorType.hsla; } - - this.selectedPresentation = this.presentations.indexOf(this.control.initType); + this.presentationControl.patchValue(this.presentations.indexOf(this.control.initType), {emitEvent: false}); } private updateModel() { - const color: string = this.getValueByType(this.control.value, this.presentations[this.selectedPresentation]); + const color: string = this.getValueByType(this.control.value, this.presentations[this.presentationControl.value]); if (this.modelValue !== color) { this.modelValue = color; this.propagateChange(color); @@ -103,12 +114,6 @@ export class ColorPickerComponent implements ControlValueAccessor, OnDestroy { this.subscriptions.length = 0; } - public changePresentation(): void { - this.selectedPresentation = - this.selectedPresentation === this.presentations.length - 1 ? 0 : this.selectedPresentation + 1; - this.updateModel(); - } - getValueByType(color: Color, type: ColorType): string { switch (type) { case ColorType.hex: diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html index eaec4c0b5e..0d916f428a 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.html @@ -15,22 +15,14 @@ limitations under the License. --> -
-
- -
-
- - - -
-
+
+ + + +
diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss new file mode 100644 index 0000000000..afd8d1cfcb --- /dev/null +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.scss @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2023 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-close-button { + position: absolute; + top: 6px; + right: 6px; + } +} diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts index 44959023f4..219ed0ec56 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts @@ -14,11 +14,10 @@ /// limitations under the License. /// -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { DialogComponent } from '@shared/components/dialog.component'; @@ -29,33 +28,26 @@ export interface ColorPickerDialogData { @Component({ selector: 'tb-color-picker-dialog', templateUrl: './color-picker-dialog.component.html', - styleUrls: [] + styleUrls: ['./color-picker-dialog.component.scss'] }) -export class ColorPickerDialogComponent extends DialogComponent - implements OnInit { +export class ColorPickerDialogComponent extends DialogComponent { - colorPickerFormGroup: FormGroup; + color: string; constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: ColorPickerDialogData, - public dialogRef: MatDialogRef, - public fb: FormBuilder) { + public dialogRef: MatDialogRef) { super(store, router, dialogRef); + this.color = data.color; } - ngOnInit(): void { - this.colorPickerFormGroup = this.fb.group({ - color: [this.data.color, [Validators.required]] - }); + selectColor(color: string) { + this.dialogRef.close(color); } cancel(): void { this.dialogRef.close(null); } - select(): void { - const color: string = this.colorPickerFormGroup.get('color').value; - this.dialogRef.close(color); - } } diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 25eee9ca08..11c4b4effb 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -196,6 +196,7 @@ import { RuleChainSelectComponent } from '@shared/components/rule-chain/rule-cha import { ToggleSelectComponent } from '@shared/components/toggle-select.component'; import { UnitInputComponent } from '@shared/components/unit-input.component'; import { MaterialIconsComponent } from '@shared/components/material-icons.component'; +import { ColorPickerPanelComponent } from '@shared/components/color-picker/color-picker-panel.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -365,6 +366,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) GtMdLgLayoutGapDirective, GtMdLgShowHideDirective, ColorPickerComponent, + ColorPickerPanelComponent, ResourceAutocompleteComponent, ToggleHeaderComponent, ToggleOption, @@ -597,6 +599,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) GtMdLgLayoutGapDirective, GtMdLgShowHideDirective, ColorPickerComponent, + ColorPickerPanelComponent, ResourceAutocompleteComponent, ToggleHeaderComponent, ToggleOption, 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 bc3351aa83..cd379fa4dc 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5500,6 +5500,9 @@ } } }, + "color": { + "color": "Color" + }, "icon": { "icon": "Icon", "icons": "Icons", diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 8197e32f6c..c9e3bc6a16 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -131,14 +131,11 @@ } .tb-form-row { height: 100%; - padding-top: 7px; - padding-bottom: 7px; display: flex; flex-direction: row; align-items: center; gap: 16px; - padding-left: 16px; - padding-right: 12px; + padding: 7px 7px 7px 16px; border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 6px; &.same-padding { @@ -314,33 +311,33 @@ .tb-prompt { height: 38px; } + } - .tb-form-table-row { - height: 38px; - display: flex; - flex-direction: row; - gap: 12px; - padding-left: 12px; + .tb-form-table-row { + height: 38px; + display: flex; + flex-direction: row; + gap: 12px; + padding-left: 12px; - &.tb-draggable { - gap: 0; - padding-left: 0; - background: #fff; - } + &.tb-draggable { + gap: 0; + padding-left: 0; + background: #fff; + } - &-cell-buttons { - display: flex; - flex-direction: row; - button.mat-mdc-icon-button.mat-mdc-button-base { - padding: 7px; - width: 38px; - height: 38px; - .mat-icon { - color: rgba(0, 0, 0, 0.38); - } - &.tb-hidden { - visibility: hidden; - } + &-cell-buttons { + display: flex; + flex-direction: row; + button.mat-mdc-icon-button.mat-mdc-button-base { + padding: 7px; + width: 38px; + height: 38px; + .mat-icon { + color: rgba(0, 0, 0, 0.38); + } + &.tb-hidden { + visibility: hidden; } } } From a9b8a6459e449beb995f0d16d15f31145331988b Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 13 Jul 2023 20:04:25 +0300 Subject: [PATCH 254/421] UI: Load home dashboards from asset resources --- .../home-links/home-links-routing.module.ts | 43 ++++++++++--------- .../dashboard/customer_user_home_page.json} | 0 .../dashboard/sys_admin_home_page.json} | 0 .../dashboard/tenant_admin_home_page.json} | 0 4 files changed, 22 insertions(+), 21 deletions(-) rename ui-ngx/src/{app/modules/home/pages/home-links/customer_user_home_page.raw => assets/dashboard/customer_user_home_page.json} (100%) rename ui-ngx/src/{app/modules/home/pages/home-links/sys_admin_home_page.raw => assets/dashboard/sys_admin_home_page.json} (100%) rename ui-ngx/src/{app/modules/home/pages/home-links/tenant_admin_home_page.raw => assets/dashboard/tenant_admin_home_page.json} (100%) diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts b/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts index 5edc9cb7fc..c1c1c9bc9e 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts @@ -25,20 +25,19 @@ import { DashboardService } from '@core/http/dashboard.service'; import { select, Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { map } from 'rxjs/operators'; -import { - getCurrentAuthUser, - selectHasRepository, - selectPersistDeviceStateToTelemetry -} from '@core/auth/auth.selectors'; -import sysAdminHomePageDashboardJson from '!raw-loader!./sys_admin_home_page.raw'; -import tenantAdminHomePageDashboardJson from '!raw-loader!./tenant_admin_home_page.raw'; -import customerUserHomePageDashboardJson from '!raw-loader!./customer_user_home_page.raw'; +import { getCurrentAuthUser, selectPersistDeviceStateToTelemetry } from '@core/auth/auth.selectors'; import { EntityKeyType } from '@shared/models/query/query.models'; +import { ResourcesService } from '@core/services/resources.service'; + +const sysAdminHomePageJson = '/assets/dashboard/sys_admin_home_page.json'; +const tenantAdminHomePageJson = '/assets/dashboard/tenant_admin_home_page.json'; +const customerUserHomePageJson = '/assets/dashboard/customer_user_home_page.json'; @Injectable() export class HomeDashboardResolver implements Resolve { constructor(private dashboardService: DashboardService, + private resourcesService: ResourcesService, private store: Store) { } @@ -50,13 +49,13 @@ export class HomeDashboardResolver implements Resolve { const authority = getCurrentAuthUser(this.store).authority; switch (authority) { case Authority.SYS_ADMIN: - dashboard$ = of(JSON.parse(sysAdminHomePageDashboardJson)); + dashboard$ = this.resourcesService.loadJsonResource(sysAdminHomePageJson); break; case Authority.TENANT_ADMIN: - dashboard$ = this.updateDeviceActivityKeyFilterIfNeeded(JSON.parse(tenantAdminHomePageDashboardJson)); + dashboard$ = this.updateDeviceActivityKeyFilterIfNeeded(this.resourcesService.loadJsonResource(tenantAdminHomePageJson)); break; case Authority.CUSTOMER_USER: - dashboard$ = this.updateDeviceActivityKeyFilterIfNeeded(JSON.parse(customerUserHomePageDashboardJson)); + dashboard$ = this.updateDeviceActivityKeyFilterIfNeeded(this.resourcesService.loadJsonResource(customerUserHomePageJson)); break; } if (dashboard$) { @@ -73,18 +72,20 @@ export class HomeDashboardResolver implements Resolve { ); } - private updateDeviceActivityKeyFilterIfNeeded(dashboard: HomeDashboard): Observable { + private updateDeviceActivityKeyFilterIfNeeded(dashboard$: Observable): Observable { return this.store.pipe(select(selectPersistDeviceStateToTelemetry)).pipe( - map((persistToTelemetry) => { - if (persistToTelemetry) { - for (const filterId of Object.keys(dashboard.configuration.filters)) { - if (['Active Devices', 'Inactive Devices'].includes(dashboard.configuration.filters[filterId].filter)) { - dashboard.configuration.filters[filterId].keyFilters[0].key.type = EntityKeyType.TIME_SERIES; + mergeMap((persistToTelemetry) => dashboard$.pipe( + map((dashboard) => { + if (persistToTelemetry) { + for (const filterId of Object.keys(dashboard.configuration.filters)) { + if (['Active Devices', 'Inactive Devices'].includes(dashboard.configuration.filters[filterId].filter)) { + dashboard.configuration.filters[filterId].keyFilters[0].key.type = EntityKeyType.TIME_SERIES; + } + } } - } - } - return dashboard; - }) + return dashboard; + }) + )) ); } } diff --git a/ui-ngx/src/app/modules/home/pages/home-links/customer_user_home_page.raw b/ui-ngx/src/assets/dashboard/customer_user_home_page.json similarity index 100% rename from ui-ngx/src/app/modules/home/pages/home-links/customer_user_home_page.raw rename to ui-ngx/src/assets/dashboard/customer_user_home_page.json diff --git a/ui-ngx/src/app/modules/home/pages/home-links/sys_admin_home_page.raw b/ui-ngx/src/assets/dashboard/sys_admin_home_page.json similarity index 100% rename from ui-ngx/src/app/modules/home/pages/home-links/sys_admin_home_page.raw rename to ui-ngx/src/assets/dashboard/sys_admin_home_page.json diff --git a/ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw b/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json similarity index 100% rename from ui-ngx/src/app/modules/home/pages/home-links/tenant_admin_home_page.raw rename to ui-ngx/src/assets/dashboard/tenant_admin_home_page.json From 5eebbf89859ee08ee6c481646c060495f51086ce Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 13 Jul 2023 22:28:59 +0200 Subject: [PATCH 255/421] web socket handler tests added. ws msg queue fixed the last msg pickup (and msg order as result) --- .../controller/plugin/TbWebSocketHandler.java | 44 +++-- .../plugin/TbWebSocketHandlerTest.java | 160 ++++++++++++++++++ 2 files changed, 186 insertions(+), 18 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java diff --git a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java index 56d88143a5..481d412d59 100644 --- a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java +++ b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java @@ -219,12 +219,12 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke .build(); } - private class SessionMetaData implements SendHandler { + class SessionMetaData implements SendHandler { private final WebSocketSession session; private final RemoteEndpoint.Async asyncRemote; private final WebSocketSessionRef sessionRef; - private final AtomicBoolean isSending = new AtomicBoolean(false); + final AtomicBoolean isSending = new AtomicBoolean(false); private final Queue> msgQueue; private volatile long lastActivityTime; @@ -254,11 +254,13 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke } } - private void closeSession(CloseStatus reason) { + void closeSession(CloseStatus reason) { try { close(this.sessionRef, reason); } catch (IOException ioe) { log.trace("[{}] Session transport error", session.getId(), ioe); + } finally { + msgQueue.clear(); } } @@ -271,20 +273,19 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke } void sendMsg(TbWebSocketMsg msg) { - if (isSending.compareAndSet(false, true)) { - sendMsgInternal(msg); - } else { - try { - msgQueue.add(msg); - } catch (RuntimeException e) { - if (log.isTraceEnabled()) { - log.trace("[{}][{}] Session closed due to queue error", sessionRef.getSecurityCtx().getTenantId(), session.getId(), e); - } else { - log.info("[{}][{}] Session closed due to queue error", sessionRef.getSecurityCtx().getTenantId(), session.getId()); - } - closeSession(CloseStatus.POLICY_VIOLATION.withReason("Max pending updates limit reached!")); + try { + msgQueue.add(msg); + } catch (RuntimeException e) { + if (log.isTraceEnabled()) { + log.trace("[{}][{}] Session closed due to queue error", sessionRef.getSecurityCtx().getTenantId(), session.getId(), e); + } else { + log.info("[{}][{}] Session closed due to queue error", sessionRef.getSecurityCtx().getTenantId(), session.getId()); } + closeSession(CloseStatus.POLICY_VIOLATION.withReason("Max pending updates limit reached!")); + return; } + + processNextMsg(); } private void sendMsgInternal(TbWebSocketMsg msg) { @@ -292,9 +293,11 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke if (TbWebSocketMsgType.TEXT.equals(msg.getType())) { TbWebSocketTextMsg textMsg = (TbWebSocketTextMsg) msg; this.asyncRemote.sendText(textMsg.getMsg(), this); + // isSending status will be reset in the onResult method by call back } else { TbWebSocketPingMsg pingMsg = (TbWebSocketPingMsg) msg; - this.asyncRemote.sendPing(pingMsg.getMsg()); + this.asyncRemote.sendPing(pingMsg.getMsg()); // blocking call + isSending.set(false); processNextMsg(); } } catch (Exception e) { @@ -308,12 +311,17 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements WebSocke if (!result.isOK()) { log.trace("[{}] Failed to send msg", session.getId(), result.getException()); closeSession(CloseStatus.SESSION_NOT_RELIABLE); - } else { - processNextMsg(); + return; } + + isSending.set(false); + processNextMsg(); } private void processNextMsg() { + if (msgQueue.isEmpty() || !isSending.compareAndSet(false, true)) { + return; + } TbWebSocketMsg msg = msgQueue.poll(); if (msg != null) { sendMsgInternal(msg); diff --git a/application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java b/application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java new file mode 100644 index 0000000000..0394e8a505 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/plugin/TbWebSocketHandlerTest.java @@ -0,0 +1,160 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller.plugin; + +import lombok.extern.slf4j.Slf4j; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.adapter.NativeWebSocketSession; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.service.ws.WebSocketSessionRef; + +import javax.websocket.RemoteEndpoint; +import javax.websocket.SendHandler; +import javax.websocket.SendResult; +import javax.websocket.Session; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.willAnswer; +import static org.mockito.BDDMockito.willDoNothing; +import static org.mockito.BDDMockito.willReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@Slf4j +class TbWebSocketHandlerTest { + + TbWebSocketHandler wsHandler; + NativeWebSocketSession session; + Session nativeSession; + RemoteEndpoint.Async asyncRemote; + WebSocketSessionRef sessionRef; + int maxMsgQueuePerSession; + TbWebSocketHandler.SessionMetaData sendHandler; + ExecutorService executor; + + @BeforeEach + void setUp() throws IOException { + maxMsgQueuePerSession = 100; + executor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName(getClass().getSimpleName())); + wsHandler = spy(new TbWebSocketHandler()); + willDoNothing().given(wsHandler).close(any(), any()); + session = mock(NativeWebSocketSession.class); + nativeSession = mock(Session.class); + willReturn(nativeSession).given(session).getNativeSession(Session.class); + asyncRemote = mock(RemoteEndpoint.Async.class); + willReturn(asyncRemote).given(nativeSession).getAsyncRemote(); + sessionRef = mock(WebSocketSessionRef.class, Mockito.RETURNS_DEEP_STUBS); //prevent NPE on logs + sendHandler = spy(wsHandler.new SessionMetaData(session, sessionRef, maxMsgQueuePerSession)); + } + + @AfterEach + void tearDown() { + if (executor != null) { + executor.shutdownNow(); + } + } + + @Test + void sendHandler_sendMsg_parallel_no_race() throws InterruptedException { + CountDownLatch finishLatch = new CountDownLatch(maxMsgQueuePerSession * 2); + AtomicInteger sendersCount = new AtomicInteger(); + willAnswer(invocation -> { + assertThat(sendersCount.incrementAndGet()).as("no race").isEqualTo(1); + String text = invocation.getArgument(0); + SendHandler onResultHandler = invocation.getArgument(1); + SendResult sendResult = new SendResult(); + executor.submit(() -> { + sendersCount.decrementAndGet(); + onResultHandler.onResult(sendResult); + finishLatch.countDown(); + }); + return null; + }).given(asyncRemote).sendText(anyString(), any()); + + assertThat(sendHandler.isSending.get()).as("sendHandler not is in sending state").isFalse(); + //first batch + IntStream.range(0, maxMsgQueuePerSession).parallel().forEach(i -> sendHandler.sendMsg("hello " + i)); + Awaitility.await("first batch processed").atMost(30, TimeUnit.SECONDS).until(() -> finishLatch.getCount() == maxMsgQueuePerSession); + assertThat(sendHandler.isSending.get()).as("sendHandler not is in sending state").isFalse(); + //second batch - to test pause between big msg batches + IntStream.range(100, 100 + maxMsgQueuePerSession).parallel().forEach(i -> sendHandler.sendMsg("hello " + i)); + assertThat(finishLatch.await(30, TimeUnit.SECONDS)).as("all callbacks fired").isTrue(); + + verify(sendHandler, never()).closeSession(any()); + verify(sendHandler, times(maxMsgQueuePerSession * 2)).onResult(any()); + assertThat(sendHandler.isSending.get()).as("sendHandler not is in sending state").isFalse(); + } + + @Test + void sendHandler_sendMsg_message_order() throws InterruptedException { + CountDownLatch finishLatch = new CountDownLatch(maxMsgQueuePerSession); + Collection outputs = new ConcurrentLinkedQueue<>(); + willAnswer(invocation -> { + String text = invocation.getArgument(0); + outputs.add(text); + SendHandler onResultHandler = invocation.getArgument(1); + SendResult sendResult = new SendResult(); + executor.submit(() -> { + onResultHandler.onResult(sendResult); + finishLatch.countDown(); + }); + return null; + }).given(asyncRemote).sendText(anyString(), any()); + + List inputs = IntStream.range(0, maxMsgQueuePerSession).mapToObj(i -> "msg " + i).collect(Collectors.toList()); + inputs.forEach(s -> sendHandler.sendMsg(s)); + + assertThat(finishLatch.await(30, TimeUnit.SECONDS)).as("all callbacks fired").isTrue(); + assertThat(outputs).as("inputs exactly the same as outputs").containsExactlyElementsOf(inputs); + + verify(sendHandler, never()).closeSession(any()); + verify(sendHandler, times(maxMsgQueuePerSession)).onResult(any()); + } + + @Test + void sendHandler_sendMsg_queue_size_exceed() { + willDoNothing().given(asyncRemote).sendText(anyString(), any()); // send text will never call back, so queue will grow each sendMsg + sendHandler.sendMsg("first message to stay in-flight all the time during this test"); + IntStream.range(0, maxMsgQueuePerSession).parallel().forEach(i -> sendHandler.sendMsg("hello " + i)); + verify(sendHandler, never()).closeSession(any()); + sendHandler.sendMsg("excessive message"); + verify(sendHandler, times(1)).closeSession(eq(new CloseStatus(1008, "Max pending updates limit reached!"))); + verify(asyncRemote, times(1)).sendText(anyString(), any()); + } + +} From 32c2d44b0cd664aa832c4471c976690208dfa2be Mon Sep 17 00:00:00 2001 From: Ruslan Vasylkiv <87172504+rusikv@users.noreply.github.com> Date: Fri, 14 Jul 2023 12:37:40 +0300 Subject: [PATCH 256/421] added rewrite param to delete latest timeseries, enabled single selection deletion (#8933) --- ui-ngx/src/app/core/http/attribute.service.ts | 10 ++++++---- .../attribute/attribute-table.component.html | 2 +- .../components/attribute/attribute-table.component.ts | 11 ++++++----- .../attribute/delete-timeseries-panel.component.html | 2 ++ .../attribute/delete-timeseries-panel.component.ts | 6 +++++- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/ui-ngx/src/app/core/http/attribute.service.ts b/ui-ngx/src/app/core/http/attribute.service.ts index b772cd63e6..cc20069e04 100644 --- a/ui-ngx/src/app/core/http/attribute.service.ts +++ b/ui-ngx/src/app/core/http/attribute.service.ts @@ -50,7 +50,7 @@ export class AttributeService { } public deleteEntityTimeseries(entityId: EntityId, timeseries: Array, deleteAllDataForKeys = false, - startTs?: number, endTs?: number, rewriteLatestIfDeleted = false, deleteLatest = false, + startTs?: number, endTs?: number, rewriteLatestIfDeleted = false, deleteLatest = true, config?: RequestConfig): Observable { const keys = timeseries.map(attribute => encodeURIComponent(attribute.key)).join(','); let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/delete` + @@ -64,9 +64,11 @@ export class AttributeService { return this.http.delete(url, defaultHttpOptionsFromConfig(config)); } - public deleteEntityLatestTimeseries(entityId: EntityId, timeseries: Array, config?: RequestConfig): Observable { + public deleteEntityLatestTimeseries(entityId: EntityId, timeseries: Array, rewrite = true, + config?: RequestConfig): Observable { const keys = timeseries.map(attribute => encodeURIComponent(attribute.key)).join(','); - let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/latest/delete?keys=${keys}`; + let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/latest/delete?keys=${keys}` + + `$rewrite=${rewrite}`; return this.http.delete(url, defaultHttpOptionsFromConfig(config)); } @@ -111,7 +113,7 @@ export class AttributeService { let deleteEntityTimeseriesObservable: Observable; if (deleteTimeseries.length) { deleteEntityTimeseriesObservable = this.deleteEntityTimeseries(entityId, deleteTimeseries, true, - null, null, false, false, config); + null, null, false, true, config); } else { deleteEntityTimeseriesObservable = of(null); } diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html index 1def300b78..95ade10645 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html @@ -93,7 +93,7 @@ (click)="deleteAttributes($event)"> delete -
+
+
{{ "attribute.delete-timeseries.rewrite-latest-value-if-deleted" | translate }} diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts index 914e5246f7..2bf6b44859 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts @@ -43,7 +43,7 @@ export class DeleteTimeseriesPanelComponent implements OnInit { endDateTime: Date; - rewriteLatestIfDeleted: boolean = false; + rewriteLatestIfDeleted: boolean = true; strategiesTranslationsMap = timeseriesDeleteStrategyTranslations; @@ -80,6 +80,10 @@ export class DeleteTimeseriesPanelComponent implements OnInit { return this.strategy === TimeseriesDeleteStrategy.DELETE_DATA_FOR_TIME_PERIOD; } + isDeleteLatestStrategy(): boolean { + return this.strategy === TimeseriesDeleteStrategy.DELETE_LATEST_VALUE; + } + onStartDateTimeChange(newStartDateTime: Date) { const endDateTimeTs = this.endDateTime.getTime(); if (newStartDateTime.getTime() >= endDateTimeTs) { From 0d55ac97604829ed73145a5d3313f397e9a4f56a Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Fri, 14 Jul 2023 13:24:02 +0300 Subject: [PATCH 257/421] make X509 certificate doc link be always available --- .../thingsboard/server/dao/device/DeviceServiceImpl.java | 6 ++++++ .../server/dao/util/DeviceConnectivityUtil.java | 8 -------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 91d591171f..0e8ea653ef 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -755,6 +755,9 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Fri, 14 Jul 2023 13:29:51 +0300 Subject: [PATCH 258/421] make X509 certificate doc link be always available --- .../org/thingsboard/server/dao/device/DeviceServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 0e8ea653ef..376133b173 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -755,7 +755,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Fri, 14 Jul 2023 13:54:43 +0300 Subject: [PATCH 259/421] UI: Move API usage dashboard to assets. Update deprecated dashboards resolvers by resolver functions. --- .../api-usage/api-usage-routing.module.ts | 18 ++- .../pages/api-usage/api-usage.component.ts | 16 +-- .../home-links/home-links-routing.module.ts | 111 ++++++++---------- .../dashboard/api_usage.json} | 0 4 files changed, 74 insertions(+), 71 deletions(-) rename ui-ngx/src/{app/modules/home/pages/api-usage/api_usage_json.raw => assets/dashboard/api_usage.json} (100%) diff --git a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts index a38fbf9958..7d4bb5fe14 100644 --- a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage-routing.module.ts @@ -14,10 +14,21 @@ /// limitations under the License. /// -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; +import { inject, NgModule } from '@angular/core'; +import { ActivatedRouteSnapshot, ResolveFn, RouterModule, RouterStateSnapshot, Routes } from '@angular/router'; import { Authority } from '@shared/models/authority.enum'; import { ApiUsageComponent } from '@home/pages/api-usage/api-usage.component'; +import { Dashboard } from '@shared/models/dashboard.models'; +import { ResourcesService } from '@core/services/resources.service'; +import { Observable } from 'rxjs'; + +const apiUsageDashboardJson = '/assets/dashboard/api_usage.json'; + +export const apiUsageDashboardResolver: ResolveFn = ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot, + resourcesService = inject(ResourcesService) +): Observable => resourcesService.loadJsonResource(apiUsageDashboardJson); const routes: Routes = [ { @@ -30,6 +41,9 @@ const routes: Routes = [ label: 'api-usage.api-usage', icon: 'insert_chart' } + }, + resolve: { + apiUsageDashboard: apiUsageDashboardResolver } } ]; diff --git a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts index 0bcae0801b..e84a23fb66 100644 --- a/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts +++ b/ui-ngx/src/app/modules/home/pages/api-usage/api-usage.component.ts @@ -14,28 +14,24 @@ /// limitations under the License. /// -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; -import apiUsageDashboardJson from '!raw-loader!./api_usage_json.raw'; import { Dashboard } from '@shared/models/dashboard.models'; +import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'tb-api-usage', templateUrl: './api-usage.component.html', styleUrls: ['./api-usage.component.scss'] }) -export class ApiUsageComponent extends PageComponent implements OnInit { +export class ApiUsageComponent extends PageComponent { - apiUsageDashboard: Dashboard; + apiUsageDashboard: Dashboard = this.route.snapshot.data.apiUsageDashboard; - constructor(protected store: Store) { + constructor(protected store: Store, + private route: ActivatedRoute) { super(store); } - - ngOnInit() { - this.apiUsageDashboard = JSON.parse(apiUsageDashboardJson); - } - } diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts b/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts index c1c1c9bc9e..a11ae14231 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links-routing.module.ts @@ -14,8 +14,8 @@ /// limitations under the License. /// -import { Injectable, NgModule } from '@angular/core'; -import { Resolve, RouterModule, Routes } from '@angular/router'; +import { inject, NgModule } from '@angular/core'; +import { ActivatedRouteSnapshot, ResolveFn, RouterModule, RouterStateSnapshot, Routes } from '@angular/router'; import { HomeLinksComponent } from './home-links.component'; import { Authority } from '@shared/models/authority.enum'; @@ -33,62 +33,58 @@ const sysAdminHomePageJson = '/assets/dashboard/sys_admin_home_page.json'; const tenantAdminHomePageJson = '/assets/dashboard/tenant_admin_home_page.json'; const customerUserHomePageJson = '/assets/dashboard/customer_user_home_page.json'; -@Injectable() -export class HomeDashboardResolver implements Resolve { - - constructor(private dashboardService: DashboardService, - private resourcesService: ResourcesService, - private store: Store) { - } - - resolve(): Observable { - return this.dashboardService.getHomeDashboard().pipe( - mergeMap((dashboard) => { - if (!dashboard) { - let dashboard$: Observable; - const authority = getCurrentAuthUser(this.store).authority; - switch (authority) { - case Authority.SYS_ADMIN: - dashboard$ = this.resourcesService.loadJsonResource(sysAdminHomePageJson); - break; - case Authority.TENANT_ADMIN: - dashboard$ = this.updateDeviceActivityKeyFilterIfNeeded(this.resourcesService.loadJsonResource(tenantAdminHomePageJson)); - break; - case Authority.CUSTOMER_USER: - dashboard$ = this.updateDeviceActivityKeyFilterIfNeeded(this.resourcesService.loadJsonResource(customerUserHomePageJson)); - break; - } - if (dashboard$) { - return dashboard$.pipe( - map((homeDashboard) => { - homeDashboard.hideDashboardToolbar = true; - return homeDashboard; - }) - ); +const updateDeviceActivityKeyFilterIfNeeded = (store: Store, + dashboard$: Observable): Observable => + store.pipe(select(selectPersistDeviceStateToTelemetry)).pipe( + mergeMap((persistToTelemetry) => dashboard$.pipe( + map((dashboard) => { + if (persistToTelemetry) { + for (const filterId of Object.keys(dashboard.configuration.filters)) { + if (['Active Devices', 'Inactive Devices'].includes(dashboard.configuration.filters[filterId].filter)) { + dashboard.configuration.filters[filterId].keyFilters[0].key.type = EntityKeyType.TIME_SERIES; + } } } - return of(dashboard); + return dashboard; }) - ); - } + )) + ); - private updateDeviceActivityKeyFilterIfNeeded(dashboard$: Observable): Observable { - return this.store.pipe(select(selectPersistDeviceStateToTelemetry)).pipe( - mergeMap((persistToTelemetry) => dashboard$.pipe( - map((dashboard) => { - if (persistToTelemetry) { - for (const filterId of Object.keys(dashboard.configuration.filters)) { - if (['Active Devices', 'Inactive Devices'].includes(dashboard.configuration.filters[filterId].filter)) { - dashboard.configuration.filters[filterId].keyFilters[0].key.type = EntityKeyType.TIME_SERIES; - } - } - } - return dashboard; - }) - )) - ); - } -} +export const homeDashboardResolver: ResolveFn = ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot, + dashboardService = inject(DashboardService), + resourcesService = inject(ResourcesService), + store: Store = inject(Store) +): Observable => + dashboardService.getHomeDashboard().pipe( + mergeMap((dashboard) => { + if (!dashboard) { + let dashboard$: Observable; + const authority = getCurrentAuthUser(store).authority; + switch (authority) { + case Authority.SYS_ADMIN: + dashboard$ = resourcesService.loadJsonResource(sysAdminHomePageJson); + break; + case Authority.TENANT_ADMIN: + dashboard$ = updateDeviceActivityKeyFilterIfNeeded(store, resourcesService.loadJsonResource(tenantAdminHomePageJson)); + break; + case Authority.CUSTOMER_USER: + dashboard$ = updateDeviceActivityKeyFilterIfNeeded(store, resourcesService.loadJsonResource(customerUserHomePageJson)); + break; + } + if (dashboard$) { + return dashboard$.pipe( + map((homeDashboard) => { + homeDashboard.hideDashboardToolbar = true; + return homeDashboard; + }) + ); + } + } + return of(dashboard); + }) + ); const routes: Routes = [ { @@ -103,16 +99,13 @@ const routes: Routes = [ } }, resolve: { - homeDashboard: HomeDashboardResolver + homeDashboard: homeDashboardResolver } } ]; @NgModule({ imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [ - HomeDashboardResolver - ] + exports: [RouterModule] }) export class HomeLinksRoutingModule { } diff --git a/ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw b/ui-ngx/src/assets/dashboard/api_usage.json similarity index 100% rename from ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw rename to ui-ngx/src/assets/dashboard/api_usage.json From f9aa9b6a92b0522517ecc7b898951e2e7599094a Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 14 Jul 2023 14:43:32 +0200 Subject: [PATCH 260/421] added ability to rewrite latest --- .../controller/TelemetryController.java | 10 +++--- .../DefaultTelemetrySubscriptionService.java | 4 +-- .../dao/timeseries/TimeseriesService.java | 2 ++ .../dao/timeseries/BaseTimeseriesService.java | 33 ++++++++++++++++--- .../api/RuleEngineTelemetryService.java | 2 +- ui-ngx/src/app/core/http/attribute.service.ts | 2 +- 6 files changed, 41 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index 8d94fb22cf..449e82fc41 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -557,12 +557,14 @@ public class TelemetryController extends BaseController { @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr, @ApiParam(value = TELEMETRY_KEYS_DESCRIPTION, required = true) - @RequestParam(name = "keys") String keysStr) throws ThingsboardException { + @RequestParam(name = "keys") String keysStr, + @ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.") + @RequestParam(name = "rewrite", defaultValue = "false") boolean rewrite) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return deleteLatestTimeseries(entityId, keysStr); + return deleteLatestTimeseries(entityId, keysStr, rewrite); } - private DeferredResult deleteLatestTimeseries(EntityId entityIdStr, String keysStr) throws ThingsboardException { + private DeferredResult deleteLatestTimeseries(EntityId entityIdStr, String keysStr, boolean rewrite) throws ThingsboardException { List keys = toKeysList(keysStr); if (keys.isEmpty()) { return getImmediateDeferredResult("Empty keys: " + keysStr, HttpStatus.BAD_REQUEST); @@ -570,7 +572,7 @@ public class TelemetryController extends BaseController { SecurityUser user = getCurrentUser(); return accessValidator.validateEntityAndCallback(user, Operation.WRITE_TELEMETRY, entityIdStr, (result, tenantId, entityId) -> - tsSubService.deleteLatestAndNotify(tenantId, entityId, keys, new FutureCallback<>() { + tsSubService.deleteLatestAndNotify(tenantId, entityId, keys, rewrite, new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { logLatestTimeseriesDeleted(user, entityId, keys, null); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 40f4e3415b..a97b7f386d 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -317,8 +317,8 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } @Override - public void deleteLatestAndNotify(TenantId tenantId, EntityId entityId, List keys, FutureCallback callback) { - ListenableFuture> deleteFuture = tsService.removeLatest(tenantId, entityId, keys); + public void deleteLatestAndNotify(TenantId tenantId, EntityId entityId, List keys, boolean rewrite, FutureCallback callback) { + ListenableFuture> deleteFuture = tsService.removeLatest(tenantId, entityId, keys, rewrite); addVoidCallback(deleteFuture, callback); addWsCallback(deleteFuture, list -> onTimeSeriesDelete(tenantId, entityId, keys, list)); } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java index c2bc997235..06e42e09e7 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java @@ -58,6 +58,8 @@ public interface TimeseriesService { ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys); + ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys, boolean rewrite); + ListenableFuture> removeAllLatest(TenantId tenantId, EntityId entityId); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index 6b8bfa9d64..d101e63a65 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -46,6 +46,7 @@ import org.thingsboard.server.dao.service.Validator; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -251,13 +252,37 @@ public class BaseTimeseriesService implements TimeseriesService { @Override public ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys) { + return removeLatest(tenantId, entityId, keys, false); + } + + @Override + public ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys, boolean rewrite) { validate(entityId); List> futures = Lists.newArrayListWithExpectedSize(keys.size()); - for (String key : keys) { - DeleteTsKvQuery query = new BaseDeleteTsKvQuery(key, 0, System.currentTimeMillis(), false); - futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); + + ListenableFuture> latestFuture; + + if (rewrite) { + latestFuture = findLatest(tenantId, entityId, keys); + } else { + latestFuture = Futures.immediateFuture(null); } - return Futures.allAsList(futures); + + return Futures.transformAsync(latestFuture, latest -> { + Map keyTsMap; + if (latest != null) { + keyTsMap = latest.stream().collect(Collectors.toMap(TsKvEntry::getKey, TsKvEntry::getTs)); + } else { + keyTsMap = Collections.emptyMap(); + } + + for (String key : keys) { + long startTs = keyTsMap.getOrDefault(key, 0L); + DeleteTsKvQuery query = new BaseDeleteTsKvQuery(key, startTs, System.currentTimeMillis(), rewrite); + futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); + } + return Futures.allAsList(futures); + }, MoreExecutors.directExecutor()); } @Override diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java index 9acd03f665..795eaeb785 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java @@ -72,5 +72,5 @@ public interface RuleEngineTelemetryService { void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback); - void deleteLatestAndNotify(TenantId tenantId, EntityId entityId, List keys, FutureCallback callback); + void deleteLatestAndNotify(TenantId tenantId, EntityId entityId, List keys, boolean rewrite, FutureCallback callback); } diff --git a/ui-ngx/src/app/core/http/attribute.service.ts b/ui-ngx/src/app/core/http/attribute.service.ts index cc20069e04..f568758f41 100644 --- a/ui-ngx/src/app/core/http/attribute.service.ts +++ b/ui-ngx/src/app/core/http/attribute.service.ts @@ -68,7 +68,7 @@ export class AttributeService { config?: RequestConfig): Observable { const keys = timeseries.map(attribute => encodeURIComponent(attribute.key)).join(','); let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/latest/delete?keys=${keys}` + - `$rewrite=${rewrite}`; + `&rewrite=${rewrite}`; return this.http.delete(url, defaultHttpOptionsFromConfig(config)); } From 038ab25403c655659c74f69c9fcb9e9e447ae925 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 14 Jul 2023 15:48:10 +0300 Subject: [PATCH 261/421] UI: Add device connectivity dialog; improve work ngrx store from user settings --- ui-ngx/src/app/core/auth/auth.actions.ts | 19 +- ui-ngx/src/app/core/auth/auth.effects.ts | 14 ++ ui-ngx/src/app/core/auth/auth.reducer.ts | 15 +- ui-ngx/src/app/core/auth/auth.selectors.ts | 6 + ui-ngx/src/app/core/http/device.service.ts | 4 + ui-ngx/src/app/core/utils.ts | 2 + .../wizard/device-wizard-dialog.component.ts | 9 +- ...e-check-connectivity-dialog.component.html | 226 ++++++++++++++++++ ...e-check-connectivity-dialog.component.scss | 151 ++++++++++++ ...ice-check-connectivity-dialog.component.ts | 170 +++++++++++++ .../home/pages/device/device.component.html | 6 + .../home/pages/device/device.module.ts | 4 +- .../device/devices-table-config.resolver.ts | 35 ++- .../shared/components/markdown.component.scss | 2 +- ui-ngx/src/app/shared/models/device.models.ts | 16 +- .../app/shared/models/user-settings.models.ts | 1 + .../help/en_US/device/install_coap_client.md | 40 ++++ .../assets/help/en_US/device/install_curl.md | 34 +++ .../help/en_US/device/install_mqtt_client.md | 38 +++ .../assets/locale/locale.constant-en_US.json | 27 ++- ui-ngx/src/form.scss | 49 ++-- ui-ngx/src/typings/utils.d.ts | 21 ++ 22 files changed, 846 insertions(+), 43 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html create mode 100644 ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss create mode 100644 ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts create mode 100644 ui-ngx/src/assets/help/en_US/device/install_coap_client.md create mode 100644 ui-ngx/src/assets/help/en_US/device/install_curl.md create mode 100644 ui-ngx/src/assets/help/en_US/device/install_mqtt_client.md create mode 100644 ui-ngx/src/typings/utils.d.ts diff --git a/ui-ngx/src/app/core/auth/auth.actions.ts b/ui-ngx/src/app/core/auth/auth.actions.ts index 67b122d67f..2e8c82ae2d 100644 --- a/ui-ngx/src/app/core/auth/auth.actions.ts +++ b/ui-ngx/src/app/core/auth/auth.actions.ts @@ -17,6 +17,7 @@ import { Action } from '@ngrx/store'; import { User } from '@shared/models/user.model'; import { AuthPayload } from '@core/auth/auth.models'; +import { UserSettings } from '@shared/models/user-settings.models'; export enum AuthActionTypes { AUTHENTICATED = '[Auth] Authenticated', @@ -25,7 +26,9 @@ export enum AuthActionTypes { UPDATE_USER_DETAILS = '[Auth] Update User Details', UPDATE_LAST_PUBLIC_DASHBOARD_ID = '[Auth] Update Last Public Dashboard Id', UPDATE_HAS_REPOSITORY = '[Auth] Change Has Repository', - UPDATE_OPENED_MENU_SECTION = '[Preferences] Update Opened Menu Section' + UPDATE_OPENED_MENU_SECTION = '[Preferences] Update Opened Menu Section', + UPDATE_USER_SETTINGS = '[Preferences] Update user settings', + DELETE_USER_SETTINGS = '[Preferences] Delete user settings', } export class ActionAuthAuthenticated implements Action { @@ -68,6 +71,18 @@ export class ActionPreferencesUpdateOpenedMenuSection implements Action { constructor(readonly payload: { path: string; opened: boolean }) {} } +export class ActionPreferencesUpdateUserSettings implements Action { + readonly type = AuthActionTypes.UPDATE_USER_SETTINGS; + + constructor(readonly payload: Partial) {} +} + +export class ActionPreferencesDeleteUserSettings implements Action { + readonly type = AuthActionTypes.DELETE_USER_SETTINGS; + + constructor(readonly payload: Array>) {} +} + export type AuthActions = ActionAuthAuthenticated | ActionAuthUnauthenticated | ActionAuthLoadUser | ActionAuthUpdateUserDetails | ActionAuthUpdateLastPublicDashboardId | ActionAuthUpdateHasRepository | - ActionPreferencesUpdateOpenedMenuSection; + ActionPreferencesUpdateOpenedMenuSection | ActionPreferencesUpdateUserSettings | ActionPreferencesDeleteUserSettings; diff --git a/ui-ngx/src/app/core/auth/auth.effects.ts b/ui-ngx/src/app/core/auth/auth.effects.ts index d2ebe2b4c5..76b9dce9fa 100644 --- a/ui-ngx/src/app/core/auth/auth.effects.ts +++ b/ui-ngx/src/app/core/auth/auth.effects.ts @@ -39,4 +39,18 @@ export class AuthEffects { withLatestFrom(this.store.pipe(select(selectAuthState))), mergeMap(([action, state]) => this.userSettingsService.putUserSettings({ openedMenuSections: state.userSettings.openedMenuSections })) ), {dispatch: false}); + + updatedUserSettings = createEffect(() => this.actions$.pipe( + ofType( + AuthActionTypes.UPDATE_USER_SETTINGS, + ), + mergeMap((state) => this.userSettingsService.putUserSettings(state.payload)) + ), {dispatch: false}); + + deleteUserSettings = createEffect(() => this.actions$.pipe( + ofType( + AuthActionTypes.DELETE_USER_SETTINGS, + ), + mergeMap((state) => this.userSettingsService.deleteUserSettings(state.payload)) + ), {dispatch: false}); } diff --git a/ui-ngx/src/app/core/auth/auth.reducer.ts b/ui-ngx/src/app/core/auth/auth.reducer.ts index 0847654399..6fd80d7052 100644 --- a/ui-ngx/src/app/core/auth/auth.reducer.ts +++ b/ui-ngx/src/app/core/auth/auth.reducer.ts @@ -16,7 +16,8 @@ import { AuthPayload, AuthState } from './auth.models'; import { AuthActions, AuthActionTypes } from './auth.actions'; -import { initialUserSettings } from '@shared/models/user-settings.models'; +import { initialUserSettings, UserSettings } from '@shared/models/user-settings.models'; +import { unset } from '@core/utils'; const emptyUserAuthState: AuthPayload = { authUser: null, @@ -42,6 +43,7 @@ export const authReducer = ( state: AuthState = initialState, action: AuthActions ): AuthState => { + let userSettings: UserSettings; switch (action.type) { case AuthActionTypes.AUTHENTICATED: return { ...state, isAuthenticated: true, ...action.payload }; @@ -71,7 +73,16 @@ export const authReducer = ( } else { openedMenuSections.delete(action.payload.path); } - const userSettings = {...state.userSettings, ...{ openedMenuSections: Array.from(openedMenuSections)}}; + userSettings = {...state.userSettings, ...{ openedMenuSections: Array.from(openedMenuSections)}}; + return { ...state, ...{ userSettings }}; + + case AuthActionTypes.UPDATE_USER_SETTINGS: + userSettings = {...state.userSettings, ...action.payload}; + return { ...state, ...{ userSettings }}; + + case AuthActionTypes.DELETE_USER_SETTINGS: + userSettings = {...state.userSettings}; + action.payload.forEach(path => unset(userSettings, path)); return { ...state, ...{ userSettings }}; default: diff --git a/ui-ngx/src/app/core/auth/auth.selectors.ts b/ui-ngx/src/app/core/auth/auth.selectors.ts index 2e8406293e..4bf2f2276d 100644 --- a/ui-ngx/src/app/core/auth/auth.selectors.ts +++ b/ui-ngx/src/app/core/auth/auth.selectors.ts @@ -21,6 +21,7 @@ import { AuthState } from './auth.models'; import { take } from 'rxjs/operators'; import { AuthUser } from '@shared/models/user.model'; import { UserSettings } from '@shared/models/user-settings.models'; +import { getDescendantProp } from '@core/utils'; export const selectAuthState = createFeatureSelector< AuthState>( 'auth' @@ -76,6 +77,11 @@ export const selectUserSettings = createSelector( (state: AuthState) => state.userSettings ); +export const selectUserSettingsProperty = (path: NestedKeyOf) => createSelector( + selectAuthState, + (state: AuthState) => getDescendantProp(state.userSettings, path) +); + export const selectOpenedMenuSections = createSelector( selectAuthState, (state: AuthState) => state.userSettings.openedMenuSections diff --git a/ui-ngx/src/app/core/http/device.service.ts b/ui-ngx/src/app/core/http/device.service.ts index dfc2d674a2..44e91e43f8 100644 --- a/ui-ngx/src/app/core/http/device.service.ts +++ b/ui-ngx/src/app/core/http/device.service.ts @@ -208,4 +208,8 @@ export class DeviceService { return this.http.post('/api/device/bulk_import', entitiesData, defaultHttpOptionsFromConfig(config)); } + public getDevicePublishTelemetryCommands(deviceId: string, config?: RequestConfig): Observable<{[key: string]: string}> { + return this.http.get<{[key: string]: string}>(`/api/device/${deviceId}/commands`, defaultHttpOptionsFromConfig(config)); + } + } diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index c310693b03..d6a3c3c6e3 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -315,6 +315,8 @@ export const isEqual = (a: any, b: any): boolean => _.isEqual(a, b); export const isEmpty = (a: any): boolean => _.isEmpty(a); +export const unset = (object: any, path: string | symbol): boolean => _.unset(object, path); + export const isEqualIgnoreUndefined = (a: any, b: any): boolean => { if (a === b) { return true; diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index 65e7df1e90..8210f9a533 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -23,7 +23,6 @@ import { DialogComponent } from '@shared/components/dialog.component'; import { Router } from '@angular/router'; import { Device, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; import { MatStepper, StepperOrientation } from '@angular/material/stepper'; -import { BaseData, HasId } from '@shared/models/base-data'; import { EntityType } from '@shared/models/entity-type.models'; import { Observable, throwError } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; @@ -40,7 +39,7 @@ import { HttpErrorResponse } from '@angular/common/http'; templateUrl: './device-wizard-dialog.component.html', styleUrls: ['./device-wizard-dialog.component.scss'] }) -export class DeviceWizardDialogComponent extends DialogComponent { +export class DeviceWizardDialogComponent extends DialogComponent { @ViewChild('addDeviceWizardStepper', {static: true}) addDeviceWizardStepper: MatStepper; @@ -64,7 +63,7 @@ export class DeviceWizardDialogComponent extends DialogComponent, protected router: Router, - public dialogRef: MatDialogRef, + public dialogRef: MatDialogRef, private deviceService: DeviceService, private breakpointObserver: BreakpointObserver, private fb: FormBuilder) { @@ -121,7 +120,7 @@ export class DeviceWizardDialogComponent extends DialogComponent this.dialogRef.close(true) + (device) => this.dialogRef.close(device) ); } } @@ -137,7 +136,7 @@ export class DeviceWizardDialogComponent extends DialogComponent> { + private createDevice(): Observable { const device: Device = { name: this.deviceWizardFormGroup.get('name').value, label: this.deviceWizardFormGroup.get('label').value, diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html new file mode 100644 index 0000000000..75e8887da6 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html @@ -0,0 +1,226 @@ + + +

device.connectivity.check-connectivity

+ + + +
+
+
+ + + {{ deviceTransportTypeTranslationMap.get(BasicTransportType.HTTP) | translate }} + + + {{ deviceTransportTypeTranslationMap.get(DeviceTransportType.MQTT) | translate }} + + + {{ deviceTransportTypeTranslationMap.get(DeviceTransportType.COAP) | translate }} + + + {{ deviceTransportTypeTranslationMap.get(DeviceTransportType.SNMP) | translate }} + + + {{ deviceTransportTypeTranslationMap.get(DeviceTransportType.LWM2M) | translate }} + + +
+ + +
device.connectivity.use-following-instructions
+
+ device.connectivity.install-curl + +
+
+
device.connectivity.http-command
+ +
+
+
device.connectivity.https-command
+ +
+
+ +
+
device.connectivity.use-following-instructions
+
+ device.connectivity.install-mqtt-client + +
+
+
+
device.connectivity.mqtt-command
+ +
+
+
+
device.connectivity.mqtts-command
+ +
+ +
device.connectivity.mqtts-x509-command
+ +
+
+
+ +
+
device.connectivity.use-following-instructions
+
+ device.connectivity.install-coap-cli + +
+
+
+
device.connectivity.coap-command
+ +
+
+
+
device.connectivity.coaps-command
+ +
+ +
device.connectivity.coaps-x509-command
+ +
+
+
+ +
device.connectivity.snmp-command
+ +
+ +
device.connectivity.lwm2m-command
+ +
+
+
+
+
+
device.state
+
+ {{ (status ? 'device.active' : 'device.inactive') | translate }} +
+
+
attribute.latest-telemetry
+
+
+
device.time
+
attribute.key
+
attribute.value
+
+
+
+
{{ telemetry.lastUpdateTs | date: 'yyyy-MM-dd HH:mm:ss' }}
+
{{ telemetry.key }}
+
{{ telemetry.value }}
+
+
+
+
+
+
+
+ {{ 'action.dont-show-again' | translate}} + + +
+ +
+ + + {{ 'device.connectivity.loading-check-connectivity-command' | translate }} + +
+
+ +
+
+
attribute.no-latest-telemetry
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss new file mode 100644 index 0000000000..e7c88bb2cb --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss @@ -0,0 +1,151 @@ +/** + * Copyright © 2016-2023 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 { + height: 100%; + max-height: 100vh; + display: grid; + grid-template-rows: min-content minmax(auto, 1fr) min-content; + + .tb-loader { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; + height: 300px; + max-height: 100%; + + .label { + margin-bottom: 0; + text-align: center; + } + } + + .status { + margin-left: 12px; + border-radius: 12px; + height: 24px; + line-height: 24px; + padding: 0 8px; + width: fit-content; + color: #198038; + background-color: rgba(25, 128, 56, 0.08); + font-size: 14px; + + &.inactive { + color: #d12730; + background-color: rgba(209, 39, 48, 0.08); + } + } + + .tb-hint-instruction { + border-radius: 6px; + background-color: rgba(48, 86, 128, 0.04); + padding: 6px 16px; + + .content { + vertical-align: middle; + } + } + + .tb-font-14 { + font-size: 14px; + } + + .tb-form-table-body { + max-height: 88px; + overflow-y: auto; + scrollbar-gutter: stable; + + .tb-form-table-row { + min-height: 38px; + } + } + + .tb-no-data-available { + .tb-no-data-bg { + min-height: 68px; + } + } + + @media #{$mat-sm} { + width: 470px; + } + + @media #{$mat-gt-sm} { + width: 720px; + } +} + +:host-context(.mat-mdc-dialog-container) { + .tb-dialog-actions { + display: flex; + gap: 8px; + padding: 8px 16px; + } + + .mat-mdc-dialog-content { + max-height: 80vh; + padding: 16px; + } +} + +:host ::ng-deep { + .tb-markdown-view { + .tb-command-code { + .code-wrapper { + padding: 0; + pre[class*=language-] { + background: #F3F6FA; + border-color: #305680; + } + } + button.clipboard-btn { + right: 0; + p { + color: #305680; + } + p, div { + background-color: #F3F6FA; + } + div { + img { + display: none; + } + &:after { + content: ""; + position: initial; + display: block; + width: 18px; + height: 18px; + background: #305680; + mask-image: url(/assets/copy-code-icon.svg); + mask-repeat: no-repeat; + } + } + } + } + } + .mdc-button__label > span { + .mat-icon { + vertical-align: text-bottom; + box-sizing: initial; + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts new file mode 100644 index 0000000000..9e1639740e --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts @@ -0,0 +1,170 @@ +/// +/// Copyright © 2016-2023 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, NgZone, OnDestroy, OnInit } from '@angular/core'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { select, Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Router } from '@angular/router'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { DeviceService } from '@core/http/device.service'; +import { FormBuilder } from '@angular/forms'; +import { + AttributeData, + AttributeScope, + AttributesSubscriptionCmd, + LatestTelemetry, + TelemetrySubscriber +} from '@shared/models/telemetry/telemetry.models'; +import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service'; +import { EntityId } from '@shared/models/id/entity-id'; +import { EntityType } from '@shared/models/entity-type.models'; +import { selectPersistDeviceStateToTelemetry } from '@core/auth/auth.selectors'; +import { take } from 'rxjs/operators'; +import { + BasicTransportType, + DeviceTransportType, + deviceTransportTypeTranslationMap, + NetworkTransportType +} from '@shared/models/device.models'; +import { UserSettingsService } from '@core/http/user-settings.service'; +import { ActionPreferencesUpdateUserSettings } from '@core/auth/auth.actions'; + +export interface DeviceCheckConnectivityDialogData { + deviceId: EntityId; + showDontShowAgain: boolean; +} +@Component({ + selector: 'tb-device-check-connectivity-dialog', + templateUrl: './device-check-connectivity-dialog.component.html', + styleUrls: ['./device-check-connectivity-dialog.component.scss'] +}) +export class DeviceCheckConnectivityDialogComponent extends + DialogComponent implements OnInit, OnDestroy { + + loadedCommand = false; + + status: boolean; + + latestTelemetry: Array = []; + + commands: {[key: string]: string}; + + allowTransportType = new Set(); + selectTransportType: NetworkTransportType; + + BasicTransportType = BasicTransportType; + DeviceTransportType = DeviceTransportType; + deviceTransportTypeTranslationMap = deviceTransportTypeTranslationMap; + + showDontShowAgain = this.data.showDontShowAgain; + + notShowAgain = false; + + private telemetrySubscriber: TelemetrySubscriber; + + private currentTime = Date.now(); + + private transportTypes = [...Object.keys(BasicTransportType), ...Object.keys(DeviceTransportType)] as Array; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) private data: DeviceCheckConnectivityDialogData, + public dialogRef: MatDialogRef, + private fb: FormBuilder, + private deviceService: DeviceService, + private telemetryWsService: TelemetryWebsocketService, + private userSettingsService: UserSettingsService, + private zone: NgZone) { + super(store, router, dialogRef); + } + + ngOnInit() { + this.loadCommands(); + this.subscribeToLatestTelemetry(); + } + + ngOnDestroy() { + super.ngOnDestroy(); + this.telemetrySubscriber?.complete(); + this.telemetrySubscriber?.unsubscribe(); + } + + close(): void { + if (this.notShowAgain && this.showDontShowAgain) { + this.store.dispatch(new ActionPreferencesUpdateUserSettings({ notDisplayConnectivityAfterAddDevice: true })); + this.dialogRef.close(null); + } else { + this.dialogRef.close(null); + } + } + + createMarkDownCommand(command: string): string { + return '```bash\n' + + command + + '{:copy-code}\n' + + '```'; + } + + private loadCommands() { + this.deviceService.getDevicePublishTelemetryCommands(this.data.deviceId.id).subscribe( + commands => { + this.commands = commands; + const commandsProtocols = Object.keys(commands); + this.transportTypes.forEach(transport => { + const findCommand = commandsProtocols.find(item => item.toUpperCase().startsWith(transport)); + if (findCommand) { + this.allowTransportType.add(transport); + } + }); + this.selectTransportType = this.allowTransportType.values().next().value; + this.loadedCommand = true; + } + ); + } + + private subscribeToLatestTelemetry() { + this.store.pipe(select(selectPersistDeviceStateToTelemetry)).pipe( + take(1) + ).subscribe(persistToTelemetry => { + this.telemetrySubscriber = TelemetrySubscriber.createEntityAttributesSubscription( + this.telemetryWsService, this.data.deviceId, LatestTelemetry.LATEST_TELEMETRY, this.zone); + if (!persistToTelemetry) { + const subscriptionCommand = new AttributesSubscriptionCmd(); + subscriptionCommand.entityType = this.data.deviceId.entityType as EntityType; + subscriptionCommand.entityId = this.data.deviceId.id; + subscriptionCommand.scope = AttributeScope.SERVER_SCOPE; + subscriptionCommand.keys = 'active'; + this.telemetrySubscriber.subscriptionCommands.push(subscriptionCommand); + } + + this.telemetrySubscriber.subscribe(); + this.telemetrySubscriber.attributeData$().subscribe( + (data) => { + this.latestTelemetry = data.reduce>((accumulator, item) => { + if (item.key === 'active') { + this.status = item.value; + } else if (item.lastUpdateTs > this.currentTime) { + accumulator.push(item); + } + return accumulator; + }, []); + } + ); + }); + } + +} diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.html b/ui-ngx/src/app/modules/home/pages/device/device.component.html index 244b1c000b..0b1ef5225c 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.html @@ -46,6 +46,12 @@ [fxShow]="!isEdit"> {{ ((deviceScope === 'customer_user' || deviceScope === 'edge_customer_user') ? 'device.view-credentials' : 'device.manage-credentials') | translate }} + - +
Date: Fri, 14 Jul 2023 18:59:20 +0300 Subject: [PATCH 263/421] Refactoring --- .../components/details-panel.component.ts | 5 ++- .../components/event/event-table-config.ts | 2 +- .../rulechain/rule-node-config.component.ts | 16 ++++++++++ .../rule-node-details.component.html | 3 +- .../rulechain/rule-node-details.component.ts | 3 ++ .../rulechain/rulechain-page.component.html | 3 +- .../rulechain/rulechain-page.component.ts | 31 +++++++++---------- .../src/app/shared/models/rule-node.models.ts | 20 +++++------- 8 files changed, 48 insertions(+), 35 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/details-panel.component.ts b/ui-ngx/src/app/modules/home/components/details-panel.component.ts index 66facf08d4..b2f8a059f3 100644 --- a/ui-ngx/src/app/modules/home/components/details-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/details-panel.component.ts @@ -15,6 +15,7 @@ /// import { + ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, @@ -55,9 +56,7 @@ export class DetailsPanelComponent extends PageComponent implements OnDestroy { } this.theFormValue = value; if (this.theFormValue !== null) { - this.formSubscription = this.theFormValue.valueChanges.subscribe(() => { - this.cd.detectChanges() - }); + this.formSubscription = this.theFormValue.valueChanges.subscribe(() => this.cd.detectChanges()); } } } diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 565dbf14bf..4021d018ce 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -359,7 +359,7 @@ export class EventTableConfig extends EntityTableConfig { case DebugEventType.DEBUG_RULE_NODE: if (this.testButtonLabel) { this.cellActionDescriptors.push({ - name: this.translate.instant('rulenode.test-with-this-message', {test: this.testButtonLabel}), + name: this.translate.instant('rulenode.test-with-this-message', {test: this.translate.instant(this.testButtonLabel)}), icon: 'bug_report', isEnabled: (entity) => entity.body.type === 'IN', onAction: ($event, entity) => { diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts index 6c19507301..3f3071221e 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.ts @@ -87,6 +87,9 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On @Output() initRuleNode = new EventEmitter(); + @Output() + changeScript = new EventEmitter(); + nodeDefinitionValue: RuleNodeDefinition; @Input() @@ -110,6 +113,8 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On changeSubscription: Subscription; + changeScriptSubscription: Subscription; + definedConfigComponent: IRuleNodeConfigurationComponent; private definedConfigComponentRef: ComponentRef; @@ -140,6 +145,14 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On if (this.definedConfigComponentRef) { this.definedConfigComponentRef.destroy(); } + if (this.changeSubscription) { + this.changeSubscription.unsubscribe(); + this.changeSubscription = null; + } + if (this.changeScriptSubscription) { + this.changeScriptSubscription.unsubscribe(); + this.changeScriptSubscription = null; + } } ngAfterViewInit(): void { @@ -212,6 +225,9 @@ export class RuleNodeConfigComponent implements ControlValueAccessor, OnInit, On this.changeSubscription = this.definedConfigComponent.configurationChanged.subscribe((configuration) => { this.updateModel(configuration); }); + if (this.definedConfigComponent?.changeScript) { + this.changeScriptSubscription = this.definedConfigComponent.changeScript.subscribe(() => this.changeScript.emit()); + } } } diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html index 2f925ded60..34aa8167e3 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html @@ -51,7 +51,8 @@ [ruleChainId]="ruleChainId" [ruleChainType]="ruleChainType" [nodeDefinition]="ruleNode.component.configurationDescriptor.nodeDefinition" - (initRuleNode)="initRuleNode.emit($event)"> + (initRuleNode)="initRuleNode.emit($event)" + (changeScript)="changeScript.emit($event)">
diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts index 7b0f426c35..f1d6001c88 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts @@ -58,6 +58,9 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O @Output() initRuleNode = new EventEmitter(); + @Output() + changeScript = new EventEmitter(); + ruleNodeType = RuleNodeType; entityType = EntityType; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html index ba91b45f16..5f5594cc1a 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.html @@ -112,7 +112,8 @@ [ruleChainType]="ruleChainType" [isEdit]="true" [isReadOnly]="false" - (initRuleNode)="onRuleNodeInit()"> + (initRuleNode)="onRuleNodeInit()" + (changeScript)="switchToFirstTab()"> diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index d5ea093721..6b78d94ac7 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -1279,25 +1279,24 @@ export class RuleChainPageComponent extends PageComponent } onDebugEventSelected(debugEventBody: DebugRuleNodeEventBody) { - if (this.ruleNodeComponent.ruleNodeConfigComponent.useDefinedDirective() && - this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.getSupportTestFunction() && - this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.testScript$) { - this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.testScript$(debugEventBody) - .subscribe((value) => { - if (value) { - this.selectedRuleNodeTabIndex = 0; - } - }) - } + const ruleNodeConfigComponent = this.ruleNodeComponent.ruleNodeConfigComponent; + const ruleNodeConfigDefinedComponent = ruleNodeConfigComponent.definedConfigComponent; + if (ruleNodeConfigComponent.useDefinedDirective() && ruleNodeConfigDefinedComponent.hasScript && ruleNodeConfigDefinedComponent.testScript) { + ruleNodeConfigDefinedComponent.testScript(debugEventBody); + } } onRuleNodeInit() { - if (this.ruleNodeComponent.ruleNodeConfigComponent.useDefinedDirective() && - this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.getSupportTestFunction()) { - this.ruleNodeTestButtonLabel = this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent.getTestButtonLabel(); - } else { - this.ruleNodeTestButtonLabel = ''; - } + const ruleNodeConfigDefinedComponent = this.ruleNodeComponent.ruleNodeConfigComponent.definedConfigComponent; + if (this.ruleNodeComponent.ruleNodeConfigComponent.useDefinedDirective() && ruleNodeConfigDefinedComponent.hasScript) { + this.ruleNodeTestButtonLabel = ruleNodeConfigDefinedComponent.testScriptLabel; + } else { + this.ruleNodeTestButtonLabel = ''; + } + } + + switchToFirstTab() { + this.selectedRuleNodeTabIndex = 0; } saveRuleNode() { diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index dd427aaf09..2a7dedabec 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -73,13 +73,14 @@ export interface RuleNodeConfigurationDescriptor { export interface IRuleNodeConfigurationComponent { ruleNodeId: string; ruleChainId: string; + hasScript: boolean; + testScriptLabel?: string; + changeScript?: EventEmitter; ruleChainType: RuleChainType; configuration: RuleNodeConfiguration; configurationChanged: Observable; validate(); - getSupportTestFunction(): boolean; - getTestButtonLabel? (): string; - testScript$? (debugEventBody?: DebugRuleNodeEventBody): Observable; + testScript? (debugEventBody?: DebugRuleNodeEventBody); [key: string]: any; } @@ -92,6 +93,8 @@ export abstract class RuleNodeConfigurationComponent extends PageComponent imple ruleChainId: string; + hasScript: boolean = false; + ruleChainType: RuleChainType; configurationValue: RuleNodeConfiguration; @@ -115,8 +118,7 @@ export abstract class RuleNodeConfigurationComponent extends PageComponent imple configurationChangedEmiter = new EventEmitter(); configurationChanged = this.configurationChangedEmiter.asObservable(); - protected constructor(@Inject(Store) protected store: Store, - @Inject(TranslateService) protected translate: TranslateService) { + protected constructor(@Inject(Store) protected store: Store) { super(store); } @@ -134,14 +136,6 @@ export abstract class RuleNodeConfigurationComponent extends PageComponent imple this.onValidate(); } - getSupportTestFunction(): boolean { - return false; - } - - getTestButtonLabel(): string { - return this.translate.instant('rulenode.test-script-function'); - } - protected setupConfiguration(configuration: RuleNodeConfiguration) { this.onConfigurationSet(this.prepareInputConfig(configuration)); this.updateValidators(false); From 2d1ef5db8c19f52f196a886e03581d7e37439643 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 14 Jul 2023 19:30:18 +0300 Subject: [PATCH 264/421] UI: Improve load units models --- .../shared/components/unit-input.component.ts | 67 +- ui-ngx/src/app/shared/models/unit.models.ts | 2023 +---------------- ui-ngx/src/assets/model/units.json | 2022 ++++++++++++++++ 3 files changed, 2068 insertions(+), 2044 deletions(-) create mode 100644 ui-ngx/src/assets/model/units.json diff --git a/ui-ngx/src/app/shared/components/unit-input.component.ts b/ui-ngx/src/app/shared/components/unit-input.component.ts index 4b70c31cec..8700151c69 100644 --- a/ui-ngx/src/app/shared/components/unit-input.component.ts +++ b/ui-ngx/src/app/shared/components/unit-input.component.ts @@ -15,11 +15,18 @@ /// import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, UntypedFormBuilder } from '@angular/forms'; -import { Observable, of } from 'rxjs'; -import { searchUnits, Unit, unitBySymbol, units } from '@shared/models/unit.models'; -import { map, mergeMap, startWith, tap } from 'rxjs/operators'; +import { ControlValueAccessor, FormBuilder, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { EMPTY, Observable, of, ReplaySubject, switchMap } from 'rxjs'; +import { searchUnits, Unit, unitBySymbol } from '@shared/models/unit.models'; +import { map, mergeMap, share, startWith, tap } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; +import { ResourcesService } from '@core/services/resources.service'; + +const unitsModels = '/assets/model/units.json'; + +interface UnitsJson { + units: Array; +} @Component({ selector: 'tb-unit-input', @@ -51,13 +58,12 @@ export class UnitInputComponent implements ControlValueAccessor, OnInit { private dirty = false; - private translatedUnits: Array = units.map(u => ({symbol: u.symbol, - name: this.translate.instant(u.name), - tags: u.tags})); + private fetchUnits$: Observable> = null; private propagateChange = (_val: any) => {}; - constructor(private fb: UntypedFormBuilder, + constructor(private fb: FormBuilder, + private resourcesService: ResourcesService, private translate: TranslateService) { } @@ -68,7 +74,6 @@ export class UnitInputComponent implements ControlValueAccessor, OnInit { tap(value => { this.updateView(value); }), - startWith(''), map(value => (value as Unit)?.symbol ? (value as Unit).symbol : (value ? value as string : '')), mergeMap(symbol => this.fetchUnits(symbol) ) ); @@ -77,13 +82,15 @@ export class UnitInputComponent implements ControlValueAccessor, OnInit { writeValue(symbol?: string): void { this.searchText = ''; this.modelValue = symbol; - let res: Unit | string = null; - if (symbol) { - const unit = unitBySymbol(symbol); - res = unit ? unit : symbol; - } - this.unitsFormControl.patchValue(res, {emitEvent: false}); - this.dirty = true; + EMPTY.pipe( + startWith(''), + switchMap(() => symbol + ? this.unitsConstant().pipe(map(units => unitBySymbol(units, symbol) ?? symbol)) + : of(null)) + ).subscribe(result => { + this.unitsFormControl.patchValue(result, {emitEvent: false}); + this.dirty = true; + }); } onFocus() { @@ -114,12 +121,9 @@ export class UnitInputComponent implements ControlValueAccessor, OnInit { fetchUnits(searchText?: string): Observable> { this.searchText = searchText; - const result = searchUnits(this.translatedUnits, searchText); - if (result.length) { - return of(result); - } else { - return of([]); - } + return this.unitsConstant().pipe( + map(unit => searchUnits(unit, searchText)) + ); } registerOnChange(fn: any): void { @@ -145,4 +149,23 @@ export class UnitInputComponent implements ControlValueAccessor, OnInit { this.unitInput.nativeElement.focus(); }, 0); } + + private unitsConstant(): Observable> { + if (this.fetchUnits$ === null) { + this.fetchUnits$ = this.resourcesService.loadJsonResource(unitsModels).pipe( + map(units => units.units.map(u => ({ + symbol: u.symbol, + name: this.translate.instant(u.name), + tags: u.tags + }))), + share({ + connector: () => new ReplaySubject(1), + resetOnError: false, + resetOnComplete: false, + resetOnRefCountZero: false + }) + ); + } + return this.fetchUnits$; + } } diff --git a/ui-ngx/src/app/shared/models/unit.models.ts b/ui-ngx/src/app/shared/models/unit.models.ts index e5ca8aa0b3..797e8a0c4a 100644 --- a/ui-ngx/src/app/shared/models/unit.models.ts +++ b/ui-ngx/src/app/shared/models/unit.models.ts @@ -20,2028 +20,7 @@ export interface Unit { tags: string[]; } -export const units: Array = [ - { - name: 'unit.millimeter', - symbol: 'mm', - tags: ['level','height','distance','length','width','gap','depth','millimeter','millimeters','rainfall','precipitation', - 'displacement','position','movement','transition','mm'] - }, - { - name: 'unit.centimeter', - symbol: 'cm', - tags: ['level','height','distance','length','width','gap','depth','centimeter','centimeters','rainfall','precipitation', - 'displacement','position','movement','transition','cm'] - }, - { - name: 'unit.angstrom', - symbol: 'Å', - tags: ['level','height','distance','length','width','gap','depth','atomic scale','atomic distance','nanoscale', - 'angstrom','angstroms','Å'] - }, - { - name: 'unit.nanometer', - symbol: 'nm', - tags: ['level','height','distance','length','width','gap','depth','nanoscale','atomic scale','molecular scale', - 'nanometer','nanometers','nm'] - }, - { - name: 'unit.micrometer', - symbol: 'µm', - tags: ['level','height','distance','length','width','gap','depth','microns','micrometer','micrometers','µm'] - }, - { - name: 'unit.meter', - symbol: 'm', - tags: ['level','height','distance','length','width','gap','depth','meter','meters','m'] - }, - { - name: 'unit.kilometer', - symbol: 'km', - tags: ['distance','height','length','width','gap','depth','kilometer','kilometers','km'] - }, - { - name: 'unit.inch', - symbol: 'in', - tags: ['level','height','distance','length','width','gap','depth','inch','inches','in'] - }, - { - name: 'unit.foot', - symbol: 'ft', - tags: ['level','height','distance','length','width','gap','depth','foot','feet','ft'] - }, - { - name: 'unit.yard', - symbol: 'yd', - tags: ['level','height','distance','length','width','gap','depth','yard','yards','yd'] - }, - { - name: 'unit.mile', - symbol: 'mi', - tags: ['level','height','distance','length','width','gap','depth','mile','miles','mi'] - }, - { - name: 'unit.nautical-mile', - symbol: 'nm', - tags: ['level','height','distance','length','width','gap','depth','nautical mile','nm'] - }, - { - name: 'unit.astronomical-unit', - symbol: 'AU', - tags: ['distance','celestial bodies','solar system','AU'] - }, - { - name: 'unit.reciprocal-metre', - symbol: 'm⁻¹', - tags: ['wavenumber','wave density','wave frequency','m⁻¹'] - }, - { - name: 'unit.meter-per-meter', - symbol: 'm/m', - tags: ['ratio of length to length','meter per meter','m/m'] - }, - { - name: 'unit.steradian', - symbol: 'sr', - tags: ['solid angle','spatial extent','steradian','sr'] - }, - { - name: 'unit.thou', - symbol: 'thou', - tags: ['length','measurement','thou'] - }, - { - name: 'unit.barleycorn', - symbol: 'barleycorn', - tags: ['length','shoe size','barleycorn'] - }, - { - name: 'unit.hand', - symbol: 'hand', - tags: ['length','horse measurement','hand'] - }, - { - name: 'unit.chain', - symbol: 'ch', - tags: ['length','land surveying','ch'] - }, - { - name: 'unit.furlong', - symbol: 'fur', - tags: ['length','land surveying','fur'] - }, - { - name: 'unit.league', - symbol: 'league', - tags: ['length','historical measurement','league'] - }, - { - name: 'unit.fathom', - symbol: 'fathom', - tags: ['depth','nautical measurement','fathom'] - }, - { - name: 'unit.cable', - symbol: 'cable', - tags: ['distance','nautical measurement','cable'] - }, - { - name: 'unit.link', - symbol: 'link', - tags: ['length','land surveying','link'] - }, - { - name: 'unit.rod', - symbol: 'rod', - tags: ['length','land surveying','rod'] - }, - { - name: 'unit.nanogram', - symbol: 'ng', - tags: ['mass','weight','heaviness','load','nanogram','nanograms','ng'] - }, - { - name: 'unit.microgram', - symbol: 'μg', - tags: ['mass','weight','heaviness','load','μg','microgram'] - }, - { - name: 'unit.milligram', - symbol: 'mg', - tags: ['mass','weight','heaviness','load','milligram','miligrams','mg'] - }, - { - name: 'unit.gram', - symbol: 'g', - tags: ['mass','weight','heaviness','load','gram','grams','g'] - }, - { - name: 'unit.kilogram', - symbol: 'kg', - tags: ['mass','weight','heaviness','load','kilogram','kilograms','kg'] - }, - { - name: 'unit.tonne', - symbol: 't', - tags: ['mass','weight','heaviness','load','tonne','tons','t'] - }, - { - name: 'unit.ounce', - symbol: 'oz', - tags: ['mass','weight','heaviness','load','ounce','ounces','oz'] - }, - { - name: 'unit.pound', - symbol: 'lb', - tags: ['mass','weight','heaviness','load','pound','pounds','lb'] - }, - { - name: 'unit.stone', - symbol: 'st', - tags: ['mass','weight','heaviness','load','stone','stones','st'] - }, - { - name: 'unit.hundredweight-count', - symbol: 'cwt', - tags: ['mass','weight','heaviness','load','hundredweight count','cwt'] - }, - { - name: 'unit.short-tons', - symbol: 'short tons', - tags: ['mass','weight','heaviness','load','short ton','short tons'] - }, - { - name: 'unit.dalton', - symbol: 'Da', - tags: ['atomic mass unit','AMU','unified atomic mass unit','dalton','Da'] - }, - { - name: 'unit.grain', - symbol: 'gr', - tags: ['mass','measurement','grain','gr'] - }, - { - name: 'unit.drachm', - symbol: 'dr', - tags: ['mass','measurement','drachm','dr'] - }, - { - name: 'unit.quarter', - symbol: 'qr', - tags: ['mass','measurement','quarter','qr'] - }, - { - name: 'unit.slug', - symbol: 'slug', - tags: ['mass','measurement','slug'] - }, - { - name: 'unit.carat', - symbol: 'ct', - tags: ['gemstone','pearl','jewelry','carat','ct'] - }, - { - name: 'unit.cubic-millimeter', - symbol: 'mm³', - tags: ['volume','capacity','extent','cubic millimeter','mm³'] - }, - { - name: 'unit.cubic-centimeter', - symbol: 'cm³', - tags: ['volume','capacity','extent','cubic centimeter','cubic centimeters','cm³'] - }, - { - name: 'unit.cubic-meter', - symbol: 'm³', - tags: ['volume','capacity','extent','cubic meter','cubic meters','m³'] - }, - { - name: 'unit.cubic-kilometer', - symbol: 'km³', - tags: ['volume','capacity','extent','cubic kilometer','cubic kilometers','km³'] - }, - { - name: 'unit.microliter', - symbol: 'µL', - tags: ['volume','liquid measurement','microliter','µL'] - }, - { - name: 'unit.milliliter', - symbol: 'mL', - tags: ['volume','capacity','extent','milliliter','milliliters','mL'] - }, - { - name: 'unit.liter', - symbol: 'l', - tags: ['volume','capacity','extent','liter','liters','l'] - }, - { - name: 'unit.hectoliter', - symbol: 'hl', - tags: ['volume','capacity','extent','hectoliter','hectoliters','hl'] - }, - { - name: 'unit.cubic-inch', - symbol: 'in³', - tags: ['volume','capacity','extent','cubic inch','cubic inches','in³'] - }, - { - name: 'unit.cubic-foot', - symbol: 'ft³', - tags: ['volume','capacity','extent','cubic foot','cubic feet','ft³'] - }, - { - name: 'unit.cubic-yard', - symbol: 'yd³', - tags: ['volume','capacity','extent','cubic yard','cubic yards','yd³'] - }, - { - name: 'unit.fluid-ounce', - symbol: 'fl-oz', - tags: ['volume','capacity','extent','fluid ounce','fluid ounces','fl-oz'] - }, - { - name: 'unit.pint', - symbol: 'pt', - tags: ['volume','capacity','extent','pint','pints','pt'] - }, - { - name: 'unit.quart', - symbol: 'qt', - tags: ['volume','capacity','extent','quart','quarts','qt'] - }, - { - name: 'unit.gallon', - symbol: 'gal', - tags: ['volume','capacity','extent','gallon','gallons','gal'] - }, - { - name: 'unit.oil-barrels', - symbol: 'bbl', - tags: ['volume','capacity','extent','oil barrel','oil barrels','bbl'] - }, - { - name: 'unit.cubic-meter-per-kilogram', - symbol: 'm³/kg', - tags: ['specific volume','volume per unit mass','cubic meter per kilogram','m³/kg'] - }, - { - name: 'unit.gill', - symbol: 'gi', - tags: ['volume','liquid measurement','gi'] - }, - { - name: 'unit.hogshead', - symbol: 'hhd', - tags: ['volume','liquid measurement','hhd'] - }, - { - name: 'unit.teaspoon', - symbol: 'tsp', - tags: ['volume','cooking measurement','tsp'] - }, - { - name: 'unit.tablespoon', - symbol: 'tbsp', - tags: ['volume','cooking measurement','tbsp'] - }, - { - name: 'unit.cup', - symbol: 'cup', - tags: ['volume','cooking measurement','cup'] - }, - { - name: 'unit.celsius', - symbol: '°C', - tags: ['temperature','heat','cold','warmth','degrees','celsius','shipment condition','°C'] - }, - { - name: 'unit.kelvin', - symbol: 'K', - tags: ['temperature','heat','cold','warmth','degrees','kelvin','K','color quality','white balance','color temperature'] - }, - { - name: 'unit.rankine', - symbol: '°R', - tags: ['temperature','heat','cold','warmth','Rankine','°R'] - }, - { - name: 'unit.fahrenheit', - symbol: '°F', - tags: ['temperature','heat','cold','warmth','degrees','fahrenheit','°F'] - }, - { - name: 'unit.meter-per-second', - symbol: 'm/s', - tags: ['speed','velocity','pace','meter per second','m/s','peak','peak to peak','root mean square (RMS)', - 'vibration','wind speed','weather'] - }, - { - name: 'unit.kilometer-per-hour', - symbol: 'km/h', - tags: ['speed','velocity','pace','kilometer per hour','km/h'] - }, - { - name: 'unit.foot-per-second', - symbol: 'ft/s', - tags: ['speed','velocity','pace','foot per second','ft/s'] - }, - { - name: 'unit.mile-per-hour', - symbol: 'mph', - tags: ['speed','velocity','pace','mile per hour','mph'] - }, - { - name: 'unit.knot', - symbol: 'kt', - tags: ['speed','velocity','pace','knot','knots','kt'] - }, - { - name: 'unit.millimeters-per-minute', - symbol: 'mm/min', - tags: ['feed rate','cutting feed rate','millimeters per minute','mm/min'] - }, - { - name: 'unit.kilometer-per-hour-squared', - symbol: 'km/h²', - tags: ['acceleration','rate of change of velocity','kilometer per hour squared','km/h²'] - }, - { - name: 'unit.foot-per-second-squared', - symbol: 'ft/s²', - tags: ['acceleration','rate of change of velocity','foot per second squared','ft/s²'] - }, - { - name: 'unit.pascal', - symbol: 'Pa', - tags: ['pressure','force','compression','tension','pascal','pascals','Pa','atmospheric pressure','air pressure', - 'weather','altitude','flight'] - }, - { - name: 'unit.kilopascal', - symbol: 'kPa', - tags: ['pressure','force','compression','tension','kilopascal','kilopascals','kPa'] - }, - { - name: 'unit.megapascal', - symbol: 'MPa', - tags: ['pressure','force','compression','tension','megapascal','megapascals','MPa'] - }, - { - name: 'unit.gigapascal', - symbol: 'GPa', - tags: ['pressure','force','compression','tension','gigapascal','gigapascals','GPa'] - }, - { - name: 'unit.millibar', - symbol: 'mbar', - tags: ['pressure','force','compression','tension','millibar','millibars','mbar'] - }, - { - name: 'unit.bar', - symbol: 'bar', - tags: ['pressure','force','compression','tension','bar','bars'] - }, - { - name: 'unit.kilobar', - symbol: 'kbar', - tags: ['pressure','force','compression','tension','kilobar','kilobars','kbar'] - }, - { - name: 'unit.newton', - symbol: 'N', - tags: ['force','pressure','newton','newtons','N','push','pull','weight','gravity','N'] - }, - { - name: 'unit.newton-meter', - symbol: 'Nm', - tags: ['torque','rotational force','newton meter','Nm'] - }, - { - name: 'unit.foot-pounds', - symbol: 'ft·lbf', - tags: ['torque','rotational force','foot-pound','foot-pounds','ft·lbf'] - }, - { - name: 'unit.inch-pounds', - symbol: 'in·lbf', - tags: ['torque','rotational force','inch-pounds','inch-pound','in·lbf'] - }, - { - name: 'unit.newton-per-meter', - symbol: 'N/m', - tags: ['linear density','force per unit length','newton per meter','N/m'] - }, - { - name: 'unit.atmospheres', - symbol: 'atm', - tags: ['pressure','force','compression','tension','atmosphere','atmospheres','atmospheric pressure','atm'] - }, - { - name: 'unit.pounds-per-square-inch', - symbol: 'psi', - tags: ['pressure','force','compression','tension','pounds per square inch','psi'] - }, - { - name: 'unit.torr', - symbol: 'Torr', - tags: ['pressure','force','compression','tension','vacuum pressure','torr'] - }, - { - name: 'unit.inches-of-mercury', - symbol: 'inHg', - tags: ['pressure','force','compression','tension','vacuum pressure','inHg','atmospheric pressure','barometric pressure'] - }, - { - name: 'unit.pascal-per-square-meter', - symbol: 'Pa/m²', - tags: ['pressure','stress','mechanical strength','pascal per square meter','Pa/m²'] - }, - { - name: 'unit.pound-per-square-inch', - symbol: 'psi/in²', - tags: ['pressure','stress','mechanical strength','pound per square inch','psi/in²'] - }, - { - name: 'unit.newton-per-square-meter', - symbol: 'N/m²', - tags: ['pressure','stress','mechanical strength','newton per square meter','N/m²'] - }, - { - name: 'unit.kilogram-force-per-square-meter', - symbol: 'kgf/m²', - tags: ['pressure','stress','mechanical strength','kilogram-force per square meter','kgf/m²'] - }, - { - name: 'unit.pascal-per-square-centimeter', - symbol: 'Pa/cm²', - tags: ['pressure','stress','mechanical strength','pascal per square centimeter','Pa/cm²'] - }, - { - name: 'unit.ton-force-per-square-inch', - symbol: 'tonf/in²', - tags: ['pressure','stress','mechanical strength','ton-force per square inch','tonf/in²'] - }, - { - name: 'unit.kilonewton-per-square-meter', - symbol: 'kN/m²', - tags: ['stress','pressure','mechanical strength','kilonewton per square meter','kN/m²'] - }, - { - name: 'unit.newton-per-square-millimeter', - symbol: 'N/mm²', - tags: ['stress','pressure','mechanical strength','newton per square millimeter','N/mm²'] - }, - { - name: 'unit.microjoule', - symbol: 'μJ', - tags: ['energy','microjoule','microjoules','μJ'] - }, - { - name: 'unit.millijoule', - symbol: 'mJ', - tags: ['energy','millijoule','millijoules','mJ'] - }, - { - name: 'unit.joule', - symbol: 'J', - tags: ['joule','joules','energy','work done','heat','electricity','mechanical work'] - }, - { - name: 'unit.kilojoule', - symbol: 'kJ', - tags: ['energy','kilojoule','kilojoules','kJ'] - }, - { - name: 'unit.megajoule', - symbol: 'MJ', - tags: ['energy','megajoule','megajoules','MJ'] - }, - { - name: 'unit.gigajoule', - symbol: 'GJ', - tags: ['energy','gigajoule','gigajoules','GJ'] - }, - { - name: 'unit.watt-hour', - symbol: 'Wh', - tags: ['energy','watt-hour','watt-hours','energy usage','power consumption','energy consumption','electricity usage'] - }, - { - name: 'unit.kilowatt-hour', - symbol: 'kWh', - tags: ['energy','kilowatt-hour','kilowatt-hours','energy usage','power consumption','energy consumption','electricity usage'] - }, - { - name: 'unit.electron-volts', - symbol: 'eV', - tags: ['energy','subatomic particles','radiation'] - }, - { - name: 'unit.joules-per-coulomb', - symbol: 'J/C', - tags: ['electrical potential energy','voltage','joules per coulomb','J/C'] - }, - { - name: 'unit.british-thermal-unit', - symbol: 'BTU', - tags: ['energy','heat','work done','british thermal unit','british thermal units','BTU'] - }, - { - name: 'unit.foot-pound', - symbol: 'ft·lb', - tags: ['energy','foot-pound','foot-pounds','ft·lb','ft⋅lbf'] - }, - { - name: 'unit.calorie', - symbol: 'Cal', - tags: ['energy','food energy','Calorie','Calories','Cal'] - }, - { - name: 'unit.small-calorie', - symbol: 'cal', - tags: ['energy','small calorie','calories','cal'] - }, - { - name: 'unit.kilocalorie', - symbol: 'kcal', - tags: ['energy','small calorie','kilocalories','kcal'] - }, - { - name: 'unit.joule-per-kelvin', - symbol: 'J/K', - tags: ['specific heat capacity','heat capacity per unit temperature','joule per kelvin','J/K'] - }, - { - name: 'unit.joule-per-kilogram-kelvin', - symbol: 'J/(kg·K)', - tags: ['specific heat capacity','heat capacity per unit mass and temperature','joule per kilogram-kelvin','J/(kg·K)'] - }, - { - name: 'unit.joule-per-kilogram', - symbol: 'J/kg', - tags: ['specific energy','specific energy capacity','joule per kilogram','J/kg'] - }, - { - name: 'unit.watt-per-meter-kelvin', - symbol: 'W/(m·K)', - tags: ['thermal conductivity','watt per meter-kelvin','W/(m·K)'] - }, - { - name: 'unit.joule-per-cubic-meter', - symbol: 'J/m³', - tags: ['energy density','joule per cubic meter','J/m³'] - }, - { - name: 'unit.therm', - symbol: 'thm', - tags: ['energy','natural gas consumption','BTU','therm','thm'] - }, - { - name: 'unit.electric-dipole-moment', - symbol: 'C·m', - tags: ['electric dipole','dipole moment','coulomb meter','C·m'] - }, - { - name: 'unit.magnetic-dipole-moment', - symbol: 'A·m²', - tags: ['magnetic dipole','dipole moment','ampere square meter','A·m²'] - }, - { - name: 'unit.debye', - symbol: 'D', - tags: ['polarization','electric dipole moment','debye','D'] - }, - { - name: 'unit.coulomb-per-square-meter-per-volt', - symbol: 'C·m²/V', - tags: ['polarization','electric field','coulomb per square meter per volt','C·m²/V'] - }, - { - name: 'unit.milliwatt', - symbol: 'mW', - tags: ['power','horsepower','performance','milliwatt','milliwatts','electricity','mW'] - }, - { - name: 'unit.microwatt', - symbol: 'μW', - tags: ['power','horsepower','performance','microwatt','microwatts','electricity','μW'] - }, - { - name: 'unit.watt', - symbol: 'W', - tags: ['power','horsepower','performance','watt','watts','electricity','W'] - }, - { - name: 'unit.kilowatt', - symbol: 'kW', - tags: ['power','horsepower','performance','kilowatt','kilowatts','electricity','kW'] - }, - { - name: 'unit.megawatt', - symbol: 'MW', - tags: ['power','horsepower','performance','megawatt','megawatts','electricity','MW'] - }, - { - name: 'unit.gigawatt', - symbol: 'GW', - tags: ['power','horsepower','performance','gigawatt','gigawatts','electricity','GW'] - }, - { - name: 'unit.metric-horsepower', - symbol: 'PS', - tags: ['power','performance','metric horsepower','PS'] - }, - { - name: 'unit.milliwatt-per-square-centimeter', - symbol: 'mW/cm²', - tags: ['power density','radiation intensity','sunlight intensity','signal power','intensity', - 'milliwatts per square centimeter','UV Intensity','mW/cm²'] - }, - { - name: 'unit.watt-per-square-centimeter', - symbol: 'W/cm²', - tags: ['power density','intensity of power','watts per square centimeter','W/cm²'] - }, - { - name: 'unit.kilowatt-per-square-centimeter', - symbol: 'kW/cm²', - tags: ['power density','intensity of power','kilowatts per square centimeter','kW/cm²'] - }, - { - name: 'unit.milliwatt-per-square-meter', - symbol: 'mW/m²', - tags: ['power density','intensity of power','milliwatts per square meter','mW/m²'] - }, - { - name: 'unit.watt-per-square-meter', - symbol: 'W/m²', - tags: ['power density','intensity of power','watts per square meter','W/m²'] - }, - { - name: 'unit.kilowatt-per-square-meter', - symbol: 'kW/m²', - tags: ['power density','intensity of power','kilowatts per square meter','kW/m²'] - }, - { - name: 'unit.watt-per-square-inch', - symbol: 'W/in²', - tags: ['power density','intensity of power','watts per square inch','W/in²'] - }, - { - name: 'unit.kilowatt-per-square-inch', - symbol: 'kW/in²', - tags: ['power density','intensity of power','kilowatts per square inch','kW/in²'] - }, - { - name: 'unit.horsepower', - symbol: 'hp', - tags: ['power','horsepower','performance','electricity','horsepowers','hp'] - }, - { - name: 'unit.btu-per-hour', - symbol: 'BTU/h', - tags: ['power','heat transfer','thermal energy','HVAC','BTU/h'] - }, - { - name: 'unit.coulomb', - symbol: 'C', - tags: ['charge','electricity','electrostatics','Coulomb','C'] - }, - { - name: 'unit.millicoulomb', - symbol: 'mC', - tags: ['charge','electricity','electrostatics','millicoulombs','mC'] - }, - { - name: 'unit.microcoulomb', - symbol: 'µC', - tags: ['charge','electricity','electrostatics','microcoulomb','µC'] - }, - { - name: 'unit.picocoulomb', - symbol: 'pC', - tags: ['charge','electricity','electrostatics','picocoulomb','pC'] - }, - { - name: 'unit.coulomb-per-meter', - symbol: 'C/m', - tags: ['electric displacement field per length','coulomb per meter','C/m'] - }, - { - name: 'unit.coulomb-per-cubic-meter', - symbol: 'C/m³', - tags: ['electric charge density','coulomb per cubic meter','C/m³'] - }, - { - name: 'unit.coulomb-per-square-meter', - symbol: 'C/m²', - tags: ['electric surface charge density','coulomb per square meter','C/m²'] - }, - { - name: 'unit.square-millimeter', - symbol: 'mm²', - tags: ['area','lot','zone','space','region','square millimeter','square millimeters','mm²','sq-mm'] - }, - { - name: 'unit.square-centimeter', - symbol: 'cm²', - tags: ['area','lot','zone','space','region','square centimeter','square centimeters','cm²','sq-cm'] - }, - { - name: 'unit.square-meter', - symbol: 'm²', - tags: ['area','lot','zone','space','region','square meter','square meters','m²','sq-m'] - }, - { - name: 'unit.hectare', - symbol: 'ha', - tags: ['area','lot','zone','space','region','hectare','hectares','ha'] - }, - { - name: 'unit.square-kilometer', - symbol: 'km²', - tags: ['area','lot','zone','space','region','square kilometer','square kilometers','km²','sq-km'] - }, - { - name: 'unit.square-inch', - symbol: 'in²', - tags: ['area','lot','zone','space','region','square inch','square inches','in²','sq-in'] - }, - { - name: 'unit.square-foot', - symbol: 'ft²', - tags: ['area','lot','zone','space','region','square foot','square feet','ft²','sq-ft'] - }, - { - name: 'unit.square-yard', - symbol: 'yd²', - tags: ['area','lot','zone','space','region','square yard','square yards','yd²','sq-yd'] - }, - { - name: 'unit.acre', - symbol: 'a', - tags: ['area','lot','zone','space','region','acre','acres','a'] - }, - { - name: 'unit.square-mile', - symbol: 'ml²', - tags: ['area','lot','zone','space','region','square mile','square miles','ml²','sq-mi'] - }, - { - name: 'unit.are', - symbol: 'are', - tags: ['area','land measurement','are'] - }, - { - name: 'unit.barn', - symbol: 'barn', - tags: ['cross-sectional area','particle physics','nuclear physics','barn'] - }, - { - name: 'unit.circular-inch', - symbol: 'circin', - tags: ['area','circular measurement','circular inch','circin'] - }, - { - name: 'unit.milliampere-hour', - symbol: 'mAh', - tags: ['electric current','current flow','electric charge','current capacity','flow of electricity', - 'electrical flow','milliampere-hour','milliampere-hours','mAh'] - }, - { - name: 'unit.ampere-hours', - symbol: 'Ah', - tags: ['electric current','current flow','electric charge','current capacity','flow of electricity', - 'electrical flow','ampere','ampere-hours','Ah'] - }, - { - name: 'unit.kiloampere-hours', - symbol: 'kAh', - tags: ['electric current','current flow','electric charge','current capacity','flow of electricity','electrical flow', - 'kiloampere-hours','kiloampere-hour','kAh'] - }, - { - name: 'unit.nanoampere', - symbol: 'nA', - tags: ['current','amperes','nanoampere','nA'] - }, - { - name: 'unit.picoampere', - symbol: 'pA', - tags: ['current','amperes','picoampere','pA'] - }, - { - name: 'unit.microampere', - symbol: 'μA', - tags: ['electric current','microampere','microamperes','μA'] - }, - { - name: 'unit.milliampere', - symbol: 'mA', - tags: ['electric current','milliampere','milliamperes','mA'] - }, - { - name: 'unit.ampere', - symbol: 'A', - tags: ['electric current','current flow','flow of electricity','electrical flow','ampere','amperes','amperage','A'] - }, - { - name: 'unit.kiloamperes', - symbol: 'kA', - tags: ['electric current','current flow','kiloamperes','kA'] - }, - { - name: 'unit.microampere-per-square-centimeter', - symbol: 'µA/cm²', - tags: ['Current density','microampere per square centimeter','µA/cm²'] - }, - { - name: 'unit.ampere-per-square-meter', - symbol: 'A/m²', - tags: ['current density','current per unit area','ampere per square meter','A/m²'] - }, - { - name: 'unit.ampere-per-meter', - symbol: 'A/m', - tags: ['magnetic field strength','magnetic field intensity','ampere per meter','A/m'] - }, - { - name: 'unit.oersted', - symbol: 'Oe', - tags: ['magnetic field','oersted','Oe'] - }, - { - name: 'unit.bohr-magneton', - symbol: 'μB', - tags: ['atomic physics','magnetic moment','bohr magneton','μB'] - }, - { - name: 'unit.ampere-meter-squared', - symbol: 'A·m²', - tags: ['magnetic moment','dipole moment','ampere-meter squared','A·m²'] - }, - { - name: 'unit.ampere-meter', - symbol: 'A·m', - tags: ['magnetic field','current loop','ampere-meter','A·m'] - }, - { - name: 'unit.nanovolt', - symbol: 'nV', - tags: ['voltage','volts','nanovolt','nV'] - }, - { - name: 'unit.picovolt', - symbol: 'pV', - tags: ['voltage','volts','picovolt','pV'] - }, - { - name: 'unit.millivolts', - symbol: 'mV', - tags: ['electric potential','electric tension','voltage','millivolt','millivolts','mV'] - }, - { - name: 'unit.microvolts', - symbol: 'μV', - tags: ['electric potential','electric tension','voltage','microvolt','microvolts','μV'] - }, - { - name: 'unit.volt', - symbol: 'V', - tags: ['electric potential','electric tension','voltage','volt','volts','V','power source','battery','battery level'] - }, - { - name: 'unit.kilovolts', - symbol: 'kV', - tags: ['electric potential','electric tension','voltage','kilovolt','kilovolts','kV'] - }, - { - name: 'unit.dbmV', - symbol: 'dBmV', - tags: ['decibels millivolt','voltage level','signal','dBmV'] - }, - { - name: 'unit.volt-meter', - symbol: 'V·m', - tags: ['electric flux','volt-meter','V·m'] - }, - { - name: 'unit.kilovolt-meter', - symbol: 'kV·m', - tags: ['electric flux','kilovolt-meter','kV·m'] - }, - { - name: 'unit.megavolt-meter', - symbol: 'MV·m', - tags: ['electric flux','megavolt-meter','MV·m'] - }, - { - name: 'unit.microvolt-meter', - symbol: 'µV·m', - tags: ['electric flux','microvolt-meter','µV·m'] - }, - { - name: 'unit.millivolt-meter', - symbol: 'mV·m', - tags: ['electric flux','millivolt-meter','mV·m'] - }, - { - name: 'unit.nanovolt-meter', - symbol: 'nV·m', - tags: ['electric flux','nanovolt-meter','nV·m'] - }, - { - name: 'unit.ohm', - symbol: 'Ω', - tags: ['electrical resistance','resistance','impedance','ohm'] - }, - { - name: 'unit.microohm', - symbol: 'μΩ', - tags: ['electrical resistance','resistance','microohm','μΩ'] - }, - { - name: 'unit.milliohm', - symbol: 'mΩ', - tags: ['electrical resistance','resistance','milliohm','mΩ'] - }, - { - name: 'unit.kilohm', - symbol: 'kΩ', - tags: ['electrical resistance','resistance','kilohm','kΩ'] - }, - { - name: 'unit.megohm', - symbol: 'MΩ', - tags: ['electrical resistance','resistance','megohm','MΩ'] - }, - { - name: 'unit.gigohm', - symbol: 'GΩ', - tags: ['electrical resistance','resistance','gigohm','GΩ'] - }, - { - name: 'unit.hertz', - symbol: 'Hz', - tags: ['frequency','cycles per second','hertz','Hz'] - }, - { - name: 'unit.kilohertz', - symbol: 'kHz', - tags: ['frequency','cycles per second','kilohertz','kHz'] - }, - { - name: 'unit.megahertz', - symbol: 'MHz', - tags: ['frequency','cycles per second','megahertz','MHz'] - }, - { - name: 'unit.gigahertz', - symbol: 'GHz', - tags: ['frequency','cycles per second','gigahertz','GHz'] - }, - { - name: 'unit.rpm', - symbol: 'RPM', - tags: ['speed','velocity','cycle','engine','Revolutions Per Minute','RPM','angular velocity','rotation speed'] - }, - { - name: 'unit.candela-per-square-meter', - symbol: 'cd/m²', - tags: ['brightness','light level','Luminance','Candela per square meter','cd/m²'] - }, - { - name: 'unit.candela', - symbol: 'cd', - tags: ['light intensity','candle power','luminous intensity','Candela','cd'] - }, - { - name: 'unit.lumen', - symbol: 'lm', - tags: ['total light output','light power','luminous flux','Lumen','lm'] - }, - { - name: 'unit.lux', - symbol: 'lx', - tags: ['illumination','light level on a surface','illuminance','Lux','lx'] - }, - { - name: 'unit.foot-candle', - symbol: 'fc', - tags: ['illuminance','light level','foot-candle','fc'] - }, - { - name: 'unit.lumen-per-square-meter', - symbol: 'lm/m²', - tags: ['illuminance','light level','lumen per square meter','lm/m²'] - }, - { - name: 'unit.lux-second', - symbol: 'lx·s', - tags: ['light exposure','illumination time','light dosage','Lux second','lx·s'] - }, - { - name: 'unit.lumen-second', - symbol: 'lm·s', - tags: ['total light energy','luminous energy','Lumen second','lm·s'] - }, - { - name: 'unit.lumens-per-watt', - symbol: 'lm/W', - tags: ['lighting efficiency','light output per energy','luminous efficacy','Lumens per watt','lm/W'] - }, - { - name: 'unit.absorbance', - symbol: 'AU', - tags: ['optical density','light absorption','absorbance','AU'] - }, - { - name: 'unit.mole', - symbol: 'mol', - tags: ['amount of substance','substance quantity','mole','moles','mol'] - }, - { - name: 'unit.nanomole', - symbol: 'nmol', - tags: ['amount of substance','substance quantity','concentration','nanomole','nmol'] - }, - { - name: 'unit.micromole', - symbol: 'μmol', - tags: ['amount of substance','substance quantity','micromole','μmol'] - }, - { - name: 'unit.millimole', - symbol: 'mmol', - tags: ['amount of substance','substance quantity','millimole','mmol'] - }, - { - name: 'unit.kilomole', - symbol: 'kmol', - tags: ['amount of substance','substance quantity','kilomole','kmol'] - }, - { - name: 'unit.mole-per-cubic-meter', - symbol: 'mol/m³', - tags: ['concentration','amount of substance','mole per cubic meter','mol/m³'] - }, - { - name: 'unit.battery', - symbol: '%', - tags: ['power source','state of charge (SoC)','battery','battery level','level','humidity','moisture', - 'relative humidity','water content','soil moisture','irrigation','water in soil','soil water content','VWC', - 'Volumetric Water Content','Total Harmonic Distortion','THD','power quality','UV Transmittance','%'] - }, - { - name: 'unit.rssi', - symbol: 'rssi', - tags: ['signal strength','signal level','received signal strength indicator','rssi','dBm'] - }, - { - name: 'unit.ppm', - symbol: 'ppm', - tags: ['carbon dioxide','co²','carbon monoxide','co','aqi','air quality','total volatile organic compounds','tvoc','ppm'] - }, - { - name: 'unit.ppb', - symbol: 'ppb', - tags: ['ozone','o³','nitrogen dioxide','no²','sulfur dioxide','so²','aqi','air quality','tvoc','ppb'] - }, - { - name: 'unit.micrograms-per-cubic-meter', - symbol: 'µg/m³', - tags: ['coarse particulate matter','pm10','fine particulate matter','pm2.5','aqi','air quality', - 'total volatile organic compounds','tvoc','micrograms per cubic meter','µg/m³'] - }, - { - name: 'unit.aqi', - symbol: 'aqi', - tags: ['AQI','air quality index'] - }, - { - name: 'unit.gram-per-cubic-meter', - symbol: 'g/m³', - tags: ['humidity','moisture','absolute humidity','g/m³'] - }, - { - name: 'unit.gram-per-kilogram', - symbol: 'g/kg', - tags: ['humidity','moisture','specific humidity','g/kg'] - }, - { - name: 'unit.millimeters-per-second', - symbol: 'mm/s', - tags: ['velocity','speed','rate of motion','peak','peak to peak','root mean square (RMS)','vibration','mm/s'] - }, - { - name: 'unit.neper', - symbol: 'Np', - tags: ['logarithmic unit','ratio','gain','loss','attenuation','neper','Np'] - }, - { - name: 'unit.bel', - symbol: 'B', - tags: ['logarithmic unit','power ratio','intensity ratio','bel','B'] - }, - { - name: 'unit.decibel', - symbol: 'dB', - tags: ['noise level','sound level','volume','acoustics','decibel','dB'] - }, - { - name: 'unit.meters-per-second-squared', - symbol: 'm/s²', - tags: ['peak','peak to peak','root mean square (RMS)','vibration','meters per second squared','m/s²'] - }, - { - name: 'unit.becquerel', - symbol: 'Bq', - tags: ['radioactivity','radiation','becquerel','Bq'] - }, - { - name: 'unit.curie', - symbol: 'Ci', - tags: ['radioactivity','radiation','curie','Ci'] - }, - { - name: 'unit.gray', - symbol: 'Gy', - tags: ['radiation dose','gray','Gy'] - }, - { - name: 'unit.sievert', - symbol: 'Sv', - tags: ['radiation dose','sievert','radiation dose equivalent2','Sv'] - }, - { - name: 'unit.roentgen', - symbol: 'R', - tags: ['radiation exposure','roentgen','R'] - }, - { - name: 'unit.cps', - symbol: 'cps', - tags: ['radiation detection','counts per second','cps'] - }, - { - name: 'unit.rad', - symbol: 'Rad', - tags: ['radiation dose','rad'] - }, - { - name: 'unit.rem', - symbol: 'Rem', - tags: ['radiation dose equivalent','rem'] - }, - { - name: 'unit.dps', - symbol: 'dps', - tags: ['radioactive decay','radioactivity','disintegrations per second','dps'] - }, - { - name: 'unit.rutherford', - symbol: 'Rd', - tags: ['radioactive decay','radioactivity','rutherford','Rd'] - }, - { - name: 'unit.coulombs-per-kilogram', - symbol: 'C/kg', - tags: ['radiation exposure','dose','coulombs per kilogram','electric charge-to-mass ratio','C/kg'] - }, - { - name: 'unit.becquerels-per-cubic-meter', - symbol: 'Bq/m³', - tags: ['radioactivity','radiation','becquerels per cubic meter','Bq/m³'] - }, - { - name: 'unit.curies-per-liter', - symbol: 'Ci/L', - tags: ['radioactivity','radiation','curies per liter','Ci/L'] - }, - { - name: 'unit.becquerels-per-second', - symbol: 'Bq/s', - tags: ['radioactive decay rate','becquerels per second','Bq/s'] - }, - { - name: 'unit.curies-per-second', - symbol: 'Ci/s', - tags: ['radioactive decay rate','curies per second','Ci/s'] - }, - { - name: 'unit.gy-per-second', - symbol: 'Gy/s', - tags: ['absorbed dose rate','radiation dose rate','gray per second','Gy/s'] - }, - { - name: 'unit.watt-per-steradian', - symbol: 'W/sr', - tags: ['radiant intensity','power per unit solid angle','watt per steradian','W/sr'] - }, - { - name: 'unit.watt-per-square-metre-steradian', - symbol: 'W/(m²·sr)', - tags: ['radiance','radiant flux density','watt per square metre-steradian','W/(m²·sr)'] - }, - { - name: 'unit.ph-level', - symbol: 'pH', - tags: ['acidity','alkalinity','neutral','acid','base','pH','soil pH','water quality','water pH'] - }, - { - name: 'unit.turbidity', - symbol: 'NTU', - tags: ['water turbidity','water clarity','Nephelometric Turbidity Units','NTU'] - }, - { - name: 'unit.mg-per-liter', - symbol: 'mg/L', - tags: ['dissolved oxygen','water quality','mg/L'] - }, - { - name: 'unit.microsiemens-per-centimeter', - symbol: 'µS/cm', - tags: ['Electrical conductivity','water quality','soil quality','microsiemens per centimeter','µS/cm'] - }, - { - name: 'unit.millisiemens-per-meter', - symbol: 'mS/m', - tags: ['Electrical conductivity','water quality','soil quality','millisiemens per meter','mS/m'] - }, - { - name: 'unit.siemens-per-meter', - symbol: 'S/m', - tags: ['Electrical conductivity','water quality','soil quality','siemens per meter','S/m'] - }, - { - name: 'unit.kilogram-per-cubic-meter', - symbol: 'kg/m³', - tags: ['density','mass per unit volume','kg/m³'] - }, - { - name: 'unit.gram-per-cubic-centimeter', - symbol: 'g/cm³', - tags: ['density','mass per unit volume','g/cm³'] - }, - { - name: 'unit.kilogram-per-square-meter', - symbol: 'kg/m²', - tags: ['density','surface density','areal density','mass per unit area','kg/m²'] - }, - { - name: 'unit.milligram-per-milliliter', - symbol: 'mg/mL', - tags: ['concentration','mass per volume','mg/mL'] - }, - { - name: 'unit.pound-per-cubic-foot', - symbol: 'lb/ft³', - tags: ['Density','mass per unit volume','lb/ft³'] - }, - { - name: 'unit.ounces-per-cubic-inch', - symbol: 'oz/in³', - tags: ['density','mass per unit volume','oz/in³'] - }, - { - name: 'unit.tons-per-cubic-yard', - symbol: 'ton/yd³', - tags: ['density','mass per unit volume','ton/yd³'] - }, - { - name: 'unit.particle-density', - symbol: 'particles/mL', - tags: ['particle concentration','count','particles/mL'] - }, - { - name: 'unit.kilometers-per-liter', - symbol: 'km/L', - tags: ['fuel efficiency','km/L'] - }, - { - name: 'unit.miles-per-gallon', - symbol: 'mpg', - tags: ['fuel efficiency','mpg'] - }, - { - name: 'unit.liters-per-100-km', - symbol: 'L/100km', - tags: ['fuel efficiency','L/100km'] - }, - { - name: 'unit.gallons-per-mile', - symbol: 'gal/mi', - tags: ['fuel efficiency','gal/mi'] - }, - { - name: 'unit.liters-per-hour', - symbol: 'L/hr', - tags: ['fuel consumption','L/hr'] - }, - { - name: 'unit.gallons-per-hour', - symbol: 'gal/hr', - tags: ['fuel consumption','gal/hr'] - }, - { - name: 'unit.beats-per-minute', - symbol: 'bpm', - tags: ['heart rate','pulse','bpm'] - }, - { - name: 'unit.millimeters-of-mercury', - symbol: 'mmHg', - tags: ['blood pressure','systolic','diastolic','mmHg'] - }, - { - name: 'unit.milligrams-per-deciliter', - symbol: 'mg/dL', - tags: ['glucose','blood sugar','glucose level','mg/dL'] - }, - { - name: 'unit.g-force', - symbol: 'G', - tags: ['acceleration','gravity','force','g-load','G'] - }, - { - name: 'unit.kilonewton', - symbol: 'kN', - tags: ['force','kN'] - }, - { - name: 'unit.kilogram-force', - symbol: 'kgf', - tags: ['force','kgf'] - }, - { - name: 'unit.pound-force', - symbol: 'lbf', - tags: ['force','lbf'] - }, - { - name: 'unit.kilopound-force', - symbol: 'klbf', - tags: ['force','klbf'] - }, - { - name: 'unit.dyne', - symbol: 'dyn', - tags: ['force','dyn'] - }, - { - name: 'unit.poundal', - symbol: 'pdl', - tags: ['force','pdl'] - }, - { - name: 'unit.kip', - symbol: 'kip', - tags: ['force','kip'] - }, - { - name: 'unit.gal', - symbol: 'Gal', - tags: ['acceleration','gravity','g-force','Gal'] - }, - { - name: 'unit.gravity', - symbol: 'gravity', - tags: ['acceleration','gravity','g-force'] - }, - { - name: 'unit.hectopascal', - symbol: 'hPa', - tags: ['atmospheric pressure','air pressure','weather','altitude','flight','hPa'] - }, - { - name: 'unit.atmosphere', - symbol: 'atm', - tags: ['atmospheric pressure','air pressure','weather','altitude','flight','atm'] - }, - { - name: 'unit.millibars', - symbol: 'mb', - tags: ['atmospheric pressure','air pressure','weather','altitude','flight','mb'] - }, - { - name: 'unit.inch-of-mercury', - symbol: 'inHg', - tags: ['atmospheric pressure','air pressure','weather','altitude','flight','inHg','richter'] - }, - { - name: 'unit.richter-scale', - symbol: 'richter', - tags: ['earthquake','seismic activity','richter'] - }, - { - name: 'unit.percentage', - symbol: '%', - tags: ['percentage'] - }, - { - name: 'unit.second', - symbol: 's', - tags: ['time','duration','interval','angle','second','arcsecond','sec'] - }, - { - name: 'unit.minute', - symbol: 'min', - tags: ['time','duration','interval','angle','minute','arcminute','min'] - }, - { - name: 'unit.hour', - symbol: 'h', - tags: ['time','duration','interval','h'] - }, - { - name: 'unit.day', - symbol: 'd', - tags: ['time','duration','interval','d'] - }, - { - name: 'unit.week', - symbol: 'wk', - tags: ['time','duration','interval','wk'] - }, - { - name: 'unit.month', - symbol: 'mo', - tags: ['time','duration','interval','mo'] - }, - { - name: 'unit.year', - symbol: 'yr', - tags: ['time','duration','interval','yr'] - }, - { - name: 'unit.cubic-foot-per-minute', - symbol: 'ft³/min', - tags: ['airflow','ventilation','HVAC','gas flow rate','CFM','flow rate','fluid flow','cubic foot per minute','ft³/min'] - }, - { - name: 'unit.cubic-meters-per-hour', - symbol: 'm³/hr', - tags: ['airflow','ventilation','HVAC','gas flow rate','cubic meters per hour','m³/hr'] - }, - { - name: 'unit.cubic-meters-per-second', - symbol: 'm³/s', - tags: ['airflow','ventilation','HVAC','gas flow rate','cubic meters per second','m³/s'] - }, - { - name: 'unit.liter-per-second', - symbol: 'L/s', - tags: ['airflow','ventilation','HVAC','gas flow rate','liter per second','L/s'] - }, - { - name: 'unit.liter-per-minute', - symbol: 'L/min', - tags: ['airflow','ventilation','HVAC','gas flow rate','liter per minute','L/min'] - }, - { - name: 'unit.gallons-per-minute', - symbol: 'GPM', - tags: ['airflow','ventilation','HVAC','gas flow rate','gallons per minute','GPM'] - }, - { - name: 'unit.cubic-foot-per-second', - symbol: 'ft³/s', - tags: ['flow rate','fluid flow','cubic foot per second','cubic feet per second','ft³/s'] - }, - { - name: 'unit.milliliters-per-minute', - symbol: 'mL/min', - tags: ['Flow rate','fluid dynamics','milliliters per minute','mL/min'] - }, - { - name: 'unit.bit', - symbol: 'bit', - tags: ['data','binary digit','information','bit'] - }, - { - name: 'unit.byte', - symbol: 'B', - tags: ['data','byte','information','storage','memory','B'] - }, - { - name: 'unit.kilobyte', - symbol: 'KB', - tags: ['data','kilobyte','KB'] - }, - { - name: 'unit.megabyte', - symbol: 'MB', - tags: ['data','megabyte','MB'] - }, - { - name: 'unit.gigabyte', - symbol: 'GB', - tags: ['data','gigabyte','GB'] - }, - { - name: 'unit.terabyte', - symbol: 'TB', - tags: ['data','terabyte','TB'] - }, - { - name: 'unit.petabyte', - symbol: 'PB', - tags: ['data','petabyte','PB'] - }, - { - name: 'unit.exabyte', - symbol: 'EB', - tags: ['data','exabyte','EB'] - }, - { - name: 'unit.zettabyte', - symbol: 'ZB', - tags: ['data','zettabyte','ZB'] - }, - { - name: 'unit.yottabyte', - symbol: 'YB', - tags: ['data','yottabyte','YB'] - }, - { - name: 'unit.bit-per-second', - symbol: 'bps', - tags: ['data transfer rate','bps'] - }, - { - name: 'unit.kilobit-per-second', - symbol: 'kbps', - tags: ['data transfer rate','kbps'] - }, - { - name: 'unit.megabit-per-second', - symbol: 'Mbps', - tags: ['data transfer rate','Mbps'] - }, - { - name: 'unit.gigabit-per-second', - symbol: 'Gbps', - tags: ['data transfer rate','Gbps'] - }, - { - name: 'unit.terabit-per-second', - symbol: 'Tbps', - tags: ['data transfer rate','Tbps'] - }, - { - name: 'unit.byte-per-second', - symbol: 'B/s', - tags: ['data transfer rate','B/s'] - }, - { - name: 'unit.kilobyte-per-second', - symbol: 'KB/s', - tags: ['data transfer rate','KB/s'] - }, - { - name: 'unit.megabyte-per-second', - symbol: 'MB/s', - tags: ['data transfer rate','MB/s'] - }, - { - name: 'unit.gigabyte-per-second', - symbol: 'GB/s', - tags: ['data transfer rate','GB/s'] - }, - { - name: 'unit.degree', - symbol: 'deg', - tags: ['angle','degree','degrees','deg'] - }, - { - name: 'unit.radian', - symbol: 'rad', - tags: ['angle','radian','radians','rad'] - }, - { - name: 'unit.gradian', - symbol: 'grad', - tags: ['angle','gradian','grades','grad'] - }, - { - name: 'unit.mil', - symbol: 'mil', - tags: ['angle','military angle','angular mil','mil'] - }, - { - name: 'unit.revolution', - symbol: 'rev', - tags: ['angle','revolution','full circle','complete turn','rev'] - }, - { - name: 'unit.siemens', - symbol: 'S', - tags: ['electrical conductance','conductance','siemens','S'] - }, - { - name: 'unit.millisiemens', - symbol: 'mS', - tags: ['electrical conductance','conductance','millisiemens','mS'] - }, - { - name: 'unit.microsiemens', - symbol: 'μS', - tags: ['electrical conductance','conductance','microsiemens','μS'] - }, - { - name: 'unit.kilosiemens', - symbol: 'kS', - tags: ['electrical conductance','conductance','kilosiemens','kS'] - }, - { - name: 'unit.megasiemens', - symbol: 'MS', - tags: ['electrical conductance','conductance','megasiemens','MS'] - }, - { - name: 'unit.gigasiemens', - symbol: 'GS', - tags: ['electrical conductance','conductance','gigasiemens','GS'] - }, - { - name: 'unit.farad', - symbol: 'F', - tags: ['electric capacitance','capacitance','farad','F'] - }, - { - name: 'unit.millifarad', - symbol: 'mF', - tags: ['electric capacitance','capacitance','millifarad','mF'] - }, - { - name: 'unit.microfarad', - symbol: 'μF', - tags: ['electric capacitance','capacitance','microfarad','μF'] - }, - { - name: 'unit.nanofarad', - symbol: 'nF', - tags: ['electric capacitance','capacitance','nanofarad','nF'] - }, - { - name: 'unit.picofarad', - symbol: 'pF', - tags: ['electric capacitance','capacitance','picofarad','pF'] - }, - { - name: 'unit.kilofarad', - symbol: 'kF', - tags: ['electric capacitance','capacitance','kilofarad','kF'] - }, - { - name: 'unit.megafarad', - symbol: 'MF', - tags: ['electric capacitance','capacitance','megafarad','MF'] - }, - { - name: 'unit.gigafarad', - symbol: 'GF', - tags: ['electric capacitance','capacitance','gigafarad','GF'] - }, - { - name: 'unit.terfarad', - symbol: 'TF', - tags: ['electric capacitance','capacitance','terafarad','TF'] - }, - { - name: 'unit.farad-per-meter', - symbol: 'F/m', - tags: ['electric permittivity','farad per meter','F/m'] - }, - { - name: 'unit.tesla', - symbol: 'T', - tags: ['magnetic field','magnetic field strength','tesla','T','magnetic flux density'] - }, - { - name: 'unit.gauss', - symbol: 'G', - tags: ['magnetic field','magnetic field strength','gauss','G','magnetic flux density'] - }, - { - name: 'unit.kilogauss', - symbol: 'kG', - tags: ['magnetic field','magnetic field strength','kilogauss','kG','magnetic flux density'] - }, - { - name: 'unit.millitesla', - symbol: 'mT', - tags: ['magnetic field','magnetic field strength','millitesla','mT'] - }, - { - name: 'unit.microtesla', - symbol: 'μT', - tags: ['magnetic field','magnetic field strength','microtesla','μT'] - }, - { - name: 'unit.nanotesla', - symbol: 'nT', - tags: ['magnetic field','magnetic field strength','nanotesla','nT'] - }, - { - name: 'unit.kilotesla', - symbol: 'kT', - tags: ['magnetic field','magnetic field strength','kilotesla','kT'] - }, - { - name: 'unit.megatesla', - symbol: 'MT', - tags: ['magnetic field','magnetic field strength','megatesla','MT'] - }, - { - name: 'unit.millitesla-square-meters', - symbol: 'millitesla square meters', - tags: ['magnetic field','millitesla square meters'] - }, - { - name: 'unit.gamma', - symbol: 'γ', - tags: ['magnetic flux density','gamma','γ'] - }, - { - name: 'unit.lambda', - symbol: 'λ', - tags: ['wavelength','lambda','λ'] - }, - { - name: 'unit.square-meter-per-second', - symbol: 'm²/s', - tags: ['kinematic viscosity','m²/s'] - }, - { - name: 'unit.square-centimeter-per-second', - symbol: 'cm²/s', - tags: ['kinematic viscosity','cm²/s'] - }, - { - name: 'unit.stoke', - symbol: 'St', - tags: ['kinematic viscosity','stokes','St'] - }, - { - name: 'unit.centistokes', - symbol: 'cSt', - tags: ['kinematic viscosity','centistokes','cSt'] - }, - { - name: 'unit.square-foot-per-second', - symbol: 'ft²/s', - tags: ['kinematic viscosity','ft²/s'] - }, - { - name: 'unit.square-inch-per-second', - symbol: 'in²/s', - tags: ['kinematic viscosity','in²/s'] - }, - { - name: 'unit.pascal-second', - symbol: 'Pa·s', - tags: ['dynamic viscosity','viscosity','fluid mechanics','pascal-second','Pa·s'] - }, - { - name: 'unit.centipoise', - symbol: 'cP', - tags: ['viscosity','dynamic viscosity','fluid viscosity','centipoise','cP'] - }, - { - name: 'unit.poise', - symbol: 'P', - tags: ['viscosity','dynamic viscosity','fluid viscosity','poise','P'] - }, - { - name: 'unit.reynolds', - symbol: 'Re', - tags: ['fluid flow regime','fluid mechanics','reynolds','Re'] - }, - { - name: 'unit.pound-per-foot-hour', - symbol: 'lb/(ft·h)', - tags: ['pound per foot-hour','lb/(ft·h)'] - }, - { - name: 'unit.newton-second-per-square-meter', - symbol: 'N·s/m²', - tags: ['newton second per square meter','N·s/m²'] - }, - { - name: 'unit.dyne-second-per-square-centimeter', - symbol: 'dyn·s/cm²', - tags: ['dyne second per square centimeter','dyn·s/cm²'] - }, - { - name: 'unit.kilogram-per-meter-second', - symbol: 'kg/(m·s)', - tags: ['kilogram per meter-second','kg/(m·s)'] - }, - { - name: 'unit.tesla-square-meters', - symbol: 'T/m²', - tags: ['magnetic flux density','tesla square meters','T/m²'] - }, - { - name: 'unit.maxwell', - symbol: 'Mx', - tags: ['magnetic flux','magnetic field','maxwell','Mx'] - }, - { - name: 'unit.tesla-per-meter', - symbol: 'T/m', - tags: ['magnetic field','tesla per meter','T/m'] - }, - { - name: 'unit.gauss-per-centimeter', - symbol: 'G/cm', - tags: ['magnetic field','gauss per centimeter','G/cm'] - }, - { - name: 'unit.weber', - symbol: 'Wb', - tags: ['magnetic flux','weber','Wb'] - }, - { - name: 'unit.microweber', - symbol: 'µWb', - tags: ['magnetic flux','microweber','µWb'] - }, - { - name: 'unit.milliweber', - symbol: 'mWb', - tags: ['magnetic flux','milliweber','mWb'] - }, - { - name: 'unit.gauss-square-centimeter', - symbol: 'G·cm²', - tags: ['magnetic flux','gauss-square centimeter','G·cm²'] - }, - { - name: 'unit.kilogauss-square-centimeter', - symbol: 'kG·cm²', - tags: ['magnetic flux','kilogauss-square centimeter','kG·cm²'] - }, - { - name: 'unit.henry', - symbol: 'H', - tags: ['inductance','magnetic induction','H'] - }, - { - name: 'unit.millihenry', - symbol: 'mH', - tags: ['inductance','millihenry','mH'] - }, - { - name: 'unit.microhenry', - symbol: 'µH', - tags: ['inductance','microhenry','µH'] - }, - { - name: 'unit.nanohenry', - symbol: 'nH', - tags: ['inductance','nanohenry','nH'] - }, - { - name: 'unit.henry-per-meter', - symbol: 'H/m', - tags: ['magnetic permeability','henry per meter','H/m'] - }, - { - name: 'unit.tesla-meter-per-ampere', - symbol: 'T·m/A', - tags: ['magnetic field','Tesla Meter per Ampere','T·m/A','magnetic flux'] - }, - { - name: 'unit.gauss-per-oersted', - symbol: 'G/Oe', - tags: ['magnetic field','Gauss per Oersted','G/Oe'] - }, - { - name: 'unit.kilogram-per-mole', - symbol: 'kg/mol', - tags: ['molar mass','kilogram per mole','kg/mol'] - }, - { - name: 'unit.gram-per-mole', - symbol: 'g/mol', - tags: ['molar mass','gram per mole','g/mol'] - }, - { - name: 'unit.milligram-per-mole', - symbol: 'mg/mol', - tags: ['molar mass','milligram per mole','mg/mol'] - }, - { - name: 'unit.joule-per-mole', - symbol: 'J/mol', - tags: ['molar energy','joule per mole','J/mol'] - }, - { - name: 'unit.joule-per-mole-kelvin', - symbol: 'J/(mol·K)', - tags: ['molar heat capacity','joule per mole-kelvin','J/(mol·K)'] - }, - { - name: 'unit.millivolts-per-meter', - symbol: 'mV/m', - tags: ['electric field strength','millivolts per meter','mV/m'] - }, - { - name: 'unit.volts-per-meter', - symbol: 'V/m', - tags: ['electric field strength','volts per meter','V/m'] - }, - { - name: 'unit.kilovolts-per-meter', - symbol: 'kV/m', - tags: ['electric field strength','kilovolts per meter','kV/m'] - }, - { - name: 'unit.radian-per-second', - symbol: 'rad/s', - tags: ['angular velocity','rotation speed','rad/s'] - }, - { - name: 'unit.radian-per-second-squared', - symbol: 'rad/s²', - tags: ['angular acceleration','rotation rate of change','rad/s²'] - }, - { - name: 'unit.revolutions-per-minute-per-second', - symbol: 'rpm/s', - tags: ['angular acceleration','rotation rate of change','rpm/s'] - }, - { - name: 'unit.revolutions-per-minute-per-second-squared', - symbol: 'rpm/s²', - tags: ['angular acceleration','rotation rate of change','rpm/s²'] - }, - { - name: 'unit.deg-per-second', - symbol: 'deg/s', - tags: ['angular velocity','degrees per second','deg/s'] - }, - { - name: 'unit.degrees-brix', - symbol: '°Bx', - tags: ['sugar content','fruit ripeness','Bx'] - }, - { - name: 'unit.katal', - symbol: 'kat', - tags: ['catalytic activity','enzyme activity','kat'] - }, - { - name: 'unit.katal-per-cubic-metre', - symbol: 'kat/m³', - tags: ['catalytic activity concentration','enzyme concentration','kat/m³'] - } -]; - -export const unitBySymbol = (symbol: string): Unit => units.find(u => u.symbol === symbol); +export const unitBySymbol = (_units: Array, symbol: string): Unit => _units.find(u => u.symbol === symbol); const searchUnitTags = (unit: Unit, searchText: string): boolean => !!unit.tags.find(t => t.toUpperCase().includes(searchText.toUpperCase())); diff --git a/ui-ngx/src/assets/model/units.json b/ui-ngx/src/assets/model/units.json new file mode 100644 index 0000000000..ecbda65cca --- /dev/null +++ b/ui-ngx/src/assets/model/units.json @@ -0,0 +1,2022 @@ +{ + "units": [ + { + "name": "unit.millimeter", + "symbol": "mm", + "tags": ["level","height","distance","length","width","gap","depth","millimeter","millimeters","rainfall","precipitation", + "displacement","position","movement","transition","mm"] + }, + { + "name": "unit.centimeter", + "symbol": "cm", + "tags": ["level","height","distance","length","width","gap","depth","centimeter","centimeters","rainfall","precipitation", + "displacement","position","movement","transition","cm"] + }, + { + "name": "unit.angstrom", + "symbol": "Å", + "tags": ["level","height","distance","length","width","gap","depth","atomic scale","atomic distance","nanoscale", + "angstrom","angstroms","Å"] + }, + { + "name": "unit.nanometer", + "symbol": "nm", + "tags": ["level","height","distance","length","width","gap","depth","nanoscale","atomic scale","molecular scale", + "nanometer","nanometers","nm"] + }, + { + "name": "unit.micrometer", + "symbol": "µm", + "tags": ["level","height","distance","length","width","gap","depth","microns","micrometer","micrometers","µm"] + }, + { + "name": "unit.meter", + "symbol": "m", + "tags": ["level","height","distance","length","width","gap","depth","meter","meters","m"] + }, + { + "name": "unit.kilometer", + "symbol": "km", + "tags": ["distance","height","length","width","gap","depth","kilometer","kilometers","km"] + }, + { + "name": "unit.inch", + "symbol": "in", + "tags": ["level","height","distance","length","width","gap","depth","inch","inches","in"] + }, + { + "name": "unit.foot", + "symbol": "ft", + "tags": ["level","height","distance","length","width","gap","depth","foot","feet","ft"] + }, + { + "name": "unit.yard", + "symbol": "yd", + "tags": ["level","height","distance","length","width","gap","depth","yard","yards","yd"] + }, + { + "name": "unit.mile", + "symbol": "mi", + "tags": ["level","height","distance","length","width","gap","depth","mile","miles","mi"] + }, + { + "name": "unit.nautical-mile", + "symbol": "nm", + "tags": ["level","height","distance","length","width","gap","depth","nautical mile","nm"] + }, + { + "name": "unit.astronomical-unit", + "symbol": "AU", + "tags": ["distance","celestial bodies","solar system","AU"] + }, + { + "name": "unit.reciprocal-metre", + "symbol": "m⁻¹", + "tags": ["wavenumber","wave density","wave frequency","m⁻¹"] + }, + { + "name": "unit.meter-per-meter", + "symbol": "m/m", + "tags": ["ratio of length to length","meter per meter","m/m"] + }, + { + "name": "unit.steradian", + "symbol": "sr", + "tags": ["solid angle","spatial extent","steradian","sr"] + }, + { + "name": "unit.thou", + "symbol": "thou", + "tags": ["length","measurement","thou"] + }, + { + "name": "unit.barleycorn", + "symbol": "barleycorn", + "tags": ["length","shoe size","barleycorn"] + }, + { + "name": "unit.hand", + "symbol": "hand", + "tags": ["length","horse measurement","hand"] + }, + { + "name": "unit.chain", + "symbol": "ch", + "tags": ["length","land surveying","ch"] + }, + { + "name": "unit.furlong", + "symbol": "fur", + "tags": ["length","land surveying","fur"] + }, + { + "name": "unit.league", + "symbol": "league", + "tags": ["length","historical measurement","league"] + }, + { + "name": "unit.fathom", + "symbol": "fathom", + "tags": ["depth","nautical measurement","fathom"] + }, + { + "name": "unit.cable", + "symbol": "cable", + "tags": ["distance","nautical measurement","cable"] + }, + { + "name": "unit.link", + "symbol": "link", + "tags": ["length","land surveying","link"] + }, + { + "name": "unit.rod", + "symbol": "rod", + "tags": ["length","land surveying","rod"] + }, + { + "name": "unit.nanogram", + "symbol": "ng", + "tags": ["mass","weight","heaviness","load","nanogram","nanograms","ng"] + }, + { + "name": "unit.microgram", + "symbol": "μg", + "tags": ["mass","weight","heaviness","load","μg","microgram"] + }, + { + "name": "unit.milligram", + "symbol": "mg", + "tags": ["mass","weight","heaviness","load","milligram","miligrams","mg"] + }, + { + "name": "unit.gram", + "symbol": "g", + "tags": ["mass","weight","heaviness","load","gram","grams","g"] + }, + { + "name": "unit.kilogram", + "symbol": "kg", + "tags": ["mass","weight","heaviness","load","kilogram","kilograms","kg"] + }, + { + "name": "unit.tonne", + "symbol": "t", + "tags": ["mass","weight","heaviness","load","tonne","tons","t"] + }, + { + "name": "unit.ounce", + "symbol": "oz", + "tags": ["mass","weight","heaviness","load","ounce","ounces","oz"] + }, + { + "name": "unit.pound", + "symbol": "lb", + "tags": ["mass","weight","heaviness","load","pound","pounds","lb"] + }, + { + "name": "unit.stone", + "symbol": "st", + "tags": ["mass","weight","heaviness","load","stone","stones","st"] + }, + { + "name": "unit.hundredweight-count", + "symbol": "cwt", + "tags": ["mass","weight","heaviness","load","hundredweight count","cwt"] + }, + { + "name": "unit.short-tons", + "symbol": "short tons", + "tags": ["mass","weight","heaviness","load","short ton","short tons"] + }, + { + "name": "unit.dalton", + "symbol": "Da", + "tags": ["atomic mass unit","AMU","unified atomic mass unit","dalton","Da"] + }, + { + "name": "unit.grain", + "symbol": "gr", + "tags": ["mass","measurement","grain","gr"] + }, + { + "name": "unit.drachm", + "symbol": "dr", + "tags": ["mass","measurement","drachm","dr"] + }, + { + "name": "unit.quarter", + "symbol": "qr", + "tags": ["mass","measurement","quarter","qr"] + }, + { + "name": "unit.slug", + "symbol": "slug", + "tags": ["mass","measurement","slug"] + }, + { + "name": "unit.carat", + "symbol": "ct", + "tags": ["gemstone","pearl","jewelry","carat","ct"] + }, + { + "name": "unit.cubic-millimeter", + "symbol": "mm³", + "tags": ["volume","capacity","extent","cubic millimeter","mm³"] + }, + { + "name": "unit.cubic-centimeter", + "symbol": "cm³", + "tags": ["volume","capacity","extent","cubic centimeter","cubic centimeters","cm³"] + }, + { + "name": "unit.cubic-meter", + "symbol": "m³", + "tags": ["volume","capacity","extent","cubic meter","cubic meters","m³"] + }, + { + "name": "unit.cubic-kilometer", + "symbol": "km³", + "tags": ["volume","capacity","extent","cubic kilometer","cubic kilometers","km³"] + }, + { + "name": "unit.microliter", + "symbol": "µL", + "tags": ["volume","liquid measurement","microliter","µL"] + }, + { + "name": "unit.milliliter", + "symbol": "mL", + "tags": ["volume","capacity","extent","milliliter","milliliters","mL"] + }, + { + "name": "unit.liter", + "symbol": "l", + "tags": ["volume","capacity","extent","liter","liters","l"] + }, + { + "name": "unit.hectoliter", + "symbol": "hl", + "tags": ["volume","capacity","extent","hectoliter","hectoliters","hl"] + }, + { + "name": "unit.cubic-inch", + "symbol": "in³", + "tags": ["volume","capacity","extent","cubic inch","cubic inches","in³"] + }, + { + "name": "unit.cubic-foot", + "symbol": "ft³", + "tags": ["volume","capacity","extent","cubic foot","cubic feet","ft³"] + }, + { + "name": "unit.cubic-yard", + "symbol": "yd³", + "tags": ["volume","capacity","extent","cubic yard","cubic yards","yd³"] + }, + { + "name": "unit.fluid-ounce", + "symbol": "fl-oz", + "tags": ["volume","capacity","extent","fluid ounce","fluid ounces","fl-oz"] + }, + { + "name": "unit.pint", + "symbol": "pt", + "tags": ["volume","capacity","extent","pint","pints","pt"] + }, + { + "name": "unit.quart", + "symbol": "qt", + "tags": ["volume","capacity","extent","quart","quarts","qt"] + }, + { + "name": "unit.gallon", + "symbol": "gal", + "tags": ["volume","capacity","extent","gallon","gallons","gal"] + }, + { + "name": "unit.oil-barrels", + "symbol": "bbl", + "tags": ["volume","capacity","extent","oil barrel","oil barrels","bbl"] + }, + { + "name": "unit.cubic-meter-per-kilogram", + "symbol": "m³/kg", + "tags": ["specific volume","volume per unit mass","cubic meter per kilogram","m³/kg"] + }, + { + "name": "unit.gill", + "symbol": "gi", + "tags": ["volume","liquid measurement","gi"] + }, + { + "name": "unit.hogshead", + "symbol": "hhd", + "tags": ["volume","liquid measurement","hhd"] + }, + { + "name": "unit.teaspoon", + "symbol": "tsp", + "tags": ["volume","cooking measurement","tsp"] + }, + { + "name": "unit.tablespoon", + "symbol": "tbsp", + "tags": ["volume","cooking measurement","tbsp"] + }, + { + "name": "unit.cup", + "symbol": "cup", + "tags": ["volume","cooking measurement","cup"] + }, + { + "name": "unit.celsius", + "symbol": "°C", + "tags": ["temperature","heat","cold","warmth","degrees","celsius","shipment condition","°C"] + }, + { + "name": "unit.kelvin", + "symbol": "K", + "tags": ["temperature","heat","cold","warmth","degrees","kelvin","K","color quality","white balance","color temperature"] + }, + { + "name": "unit.rankine", + "symbol": "°R", + "tags": ["temperature","heat","cold","warmth","Rankine","°R"] + }, + { + "name": "unit.fahrenheit", + "symbol": "°F", + "tags": ["temperature","heat","cold","warmth","degrees","fahrenheit","°F"] + }, + { + "name": "unit.meter-per-second", + "symbol": "m/s", + "tags": ["speed","velocity","pace","meter per second","m/s","peak","peak to peak","root mean square (RMS)", + "vibration","wind speed","weather"] + }, + { + "name": "unit.kilometer-per-hour", + "symbol": "km/h", + "tags": ["speed","velocity","pace","kilometer per hour","km/h"] + }, + { + "name": "unit.foot-per-second", + "symbol": "ft/s", + "tags": ["speed","velocity","pace","foot per second","ft/s"] + }, + { + "name": "unit.mile-per-hour", + "symbol": "mph", + "tags": ["speed","velocity","pace","mile per hour","mph"] + }, + { + "name": "unit.knot", + "symbol": "kt", + "tags": ["speed","velocity","pace","knot","knots","kt"] + }, + { + "name": "unit.millimeters-per-minute", + "symbol": "mm/min", + "tags": ["feed rate","cutting feed rate","millimeters per minute","mm/min"] + }, + { + "name": "unit.kilometer-per-hour-squared", + "symbol": "km/h²", + "tags": ["acceleration","rate of change of velocity","kilometer per hour squared","km/h²"] + }, + { + "name": "unit.foot-per-second-squared", + "symbol": "ft/s²", + "tags": ["acceleration","rate of change of velocity","foot per second squared","ft/s²"] + }, + { + "name": "unit.pascal", + "symbol": "Pa", + "tags": ["pressure","force","compression","tension","pascal","pascals","Pa","atmospheric pressure","air pressure", + "weather","altitude","flight"] + }, + { + "name": "unit.kilopascal", + "symbol": "kPa", + "tags": ["pressure","force","compression","tension","kilopascal","kilopascals","kPa"] + }, + { + "name": "unit.megapascal", + "symbol": "MPa", + "tags": ["pressure","force","compression","tension","megapascal","megapascals","MPa"] + }, + { + "name": "unit.gigapascal", + "symbol": "GPa", + "tags": ["pressure","force","compression","tension","gigapascal","gigapascals","GPa"] + }, + { + "name": "unit.millibar", + "symbol": "mbar", + "tags": ["pressure","force","compression","tension","millibar","millibars","mbar"] + }, + { + "name": "unit.bar", + "symbol": "bar", + "tags": ["pressure","force","compression","tension","bar","bars"] + }, + { + "name": "unit.kilobar", + "symbol": "kbar", + "tags": ["pressure","force","compression","tension","kilobar","kilobars","kbar"] + }, + { + "name": "unit.newton", + "symbol": "N", + "tags": ["force","pressure","newton","newtons","N","push","pull","weight","gravity","N"] + }, + { + "name": "unit.newton-meter", + "symbol": "Nm", + "tags": ["torque","rotational force","newton meter","Nm"] + }, + { + "name": "unit.foot-pounds", + "symbol": "ft·lbf", + "tags": ["torque","rotational force","foot-pound","foot-pounds","ft·lbf"] + }, + { + "name": "unit.inch-pounds", + "symbol": "in·lbf", + "tags": ["torque","rotational force","inch-pounds","inch-pound","in·lbf"] + }, + { + "name": "unit.newton-per-meter", + "symbol": "N/m", + "tags": ["linear density","force per unit length","newton per meter","N/m"] + }, + { + "name": "unit.atmospheres", + "symbol": "atm", + "tags": ["pressure","force","compression","tension","atmosphere","atmospheres","atmospheric pressure","atm"] + }, + { + "name": "unit.pounds-per-square-inch", + "symbol": "psi", + "tags": ["pressure","force","compression","tension","pounds per square inch","psi"] + }, + { + "name": "unit.torr", + "symbol": "Torr", + "tags": ["pressure","force","compression","tension","vacuum pressure","torr"] + }, + { + "name": "unit.inches-of-mercury", + "symbol": "inHg", + "tags": ["pressure","force","compression","tension","vacuum pressure","inHg","atmospheric pressure","barometric pressure"] + }, + { + "name": "unit.pascal-per-square-meter", + "symbol": "Pa/m²", + "tags": ["pressure","stress","mechanical strength","pascal per square meter","Pa/m²"] + }, + { + "name": "unit.pound-per-square-inch", + "symbol": "psi/in²", + "tags": ["pressure","stress","mechanical strength","pound per square inch","psi/in²"] + }, + { + "name": "unit.newton-per-square-meter", + "symbol": "N/m²", + "tags": ["pressure","stress","mechanical strength","newton per square meter","N/m²"] + }, + { + "name": "unit.kilogram-force-per-square-meter", + "symbol": "kgf/m²", + "tags": ["pressure","stress","mechanical strength","kilogram-force per square meter","kgf/m²"] + }, + { + "name": "unit.pascal-per-square-centimeter", + "symbol": "Pa/cm²", + "tags": ["pressure","stress","mechanical strength","pascal per square centimeter","Pa/cm²"] + }, + { + "name": "unit.ton-force-per-square-inch", + "symbol": "tonf/in²", + "tags": ["pressure","stress","mechanical strength","ton-force per square inch","tonf/in²"] + }, + { + "name": "unit.kilonewton-per-square-meter", + "symbol": "kN/m²", + "tags": ["stress","pressure","mechanical strength","kilonewton per square meter","kN/m²"] + }, + { + "name": "unit.newton-per-square-millimeter", + "symbol": "N/mm²", + "tags": ["stress","pressure","mechanical strength","newton per square millimeter","N/mm²"] + }, + { + "name": "unit.microjoule", + "symbol": "μJ", + "tags": ["energy","microjoule","microjoules","μJ"] + }, + { + "name": "unit.millijoule", + "symbol": "mJ", + "tags": ["energy","millijoule","millijoules","mJ"] + }, + { + "name": "unit.joule", + "symbol": "J", + "tags": ["joule","joules","energy","work done","heat","electricity","mechanical work"] + }, + { + "name": "unit.kilojoule", + "symbol": "kJ", + "tags": ["energy","kilojoule","kilojoules","kJ"] + }, + { + "name": "unit.megajoule", + "symbol": "MJ", + "tags": ["energy","megajoule","megajoules","MJ"] + }, + { + "name": "unit.gigajoule", + "symbol": "GJ", + "tags": ["energy","gigajoule","gigajoules","GJ"] + }, + { + "name": "unit.watt-hour", + "symbol": "Wh", + "tags": ["energy","watt-hour","watt-hours","energy usage","power consumption","energy consumption","electricity usage"] + }, + { + "name": "unit.kilowatt-hour", + "symbol": "kWh", + "tags": ["energy","kilowatt-hour","kilowatt-hours","energy usage","power consumption","energy consumption","electricity usage"] + }, + { + "name": "unit.electron-volts", + "symbol": "eV", + "tags": ["energy","subatomic particles","radiation"] + }, + { + "name": "unit.joules-per-coulomb", + "symbol": "J/C", + "tags": ["electrical potential energy","voltage","joules per coulomb","J/C"] + }, + { + "name": "unit.british-thermal-unit", + "symbol": "BTU", + "tags": ["energy","heat","work done","british thermal unit","british thermal units","BTU"] + }, + { + "name": "unit.foot-pound", + "symbol": "ft·lb", + "tags": ["energy","foot-pound","foot-pounds","ft·lb","ft⋅lbf"] + }, + { + "name": "unit.calorie", + "symbol": "Cal", + "tags": ["energy","food energy","Calorie","Calories","Cal"] + }, + { + "name": "unit.small-calorie", + "symbol": "cal", + "tags": ["energy","small calorie","calories","cal"] + }, + { + "name": "unit.kilocalorie", + "symbol": "kcal", + "tags": ["energy","small calorie","kilocalories","kcal"] + }, + { + "name": "unit.joule-per-kelvin", + "symbol": "J/K", + "tags": ["specific heat capacity","heat capacity per unit temperature","joule per kelvin","J/K"] + }, + { + "name": "unit.joule-per-kilogram-kelvin", + "symbol": "J/(kg·K)", + "tags": ["specific heat capacity","heat capacity per unit mass and temperature","joule per kilogram-kelvin","J/(kg·K)"] + }, + { + "name": "unit.joule-per-kilogram", + "symbol": "J/kg", + "tags": ["specific energy","specific energy capacity","joule per kilogram","J/kg"] + }, + { + "name": "unit.watt-per-meter-kelvin", + "symbol": "W/(m·K)", + "tags": ["thermal conductivity","watt per meter-kelvin","W/(m·K)"] + }, + { + "name": "unit.joule-per-cubic-meter", + "symbol": "J/m³", + "tags": ["energy density","joule per cubic meter","J/m³"] + }, + { + "name": "unit.therm", + "symbol": "thm", + "tags": ["energy","natural gas consumption","BTU","therm","thm"] + }, + { + "name": "unit.electric-dipole-moment", + "symbol": "C·m", + "tags": ["electric dipole","dipole moment","coulomb meter","C·m"] + }, + { + "name": "unit.magnetic-dipole-moment", + "symbol": "A·m²", + "tags": ["magnetic dipole","dipole moment","ampere square meter","A·m²"] + }, + { + "name": "unit.debye", + "symbol": "D", + "tags": ["polarization","electric dipole moment","debye","D"] + }, + { + "name": "unit.coulomb-per-square-meter-per-volt", + "symbol": "C·m²/V", + "tags": ["polarization","electric field","coulomb per square meter per volt","C·m²/V"] + }, + { + "name": "unit.milliwatt", + "symbol": "mW", + "tags": ["power","horsepower","performance","milliwatt","milliwatts","electricity","mW"] + }, + { + "name": "unit.microwatt", + "symbol": "μW", + "tags": ["power","horsepower","performance","microwatt","microwatts","electricity","μW"] + }, + { + "name": "unit.watt", + "symbol": "W", + "tags": ["power","horsepower","performance","watt","watts","electricity","W"] + }, + { + "name": "unit.kilowatt", + "symbol": "kW", + "tags": ["power","horsepower","performance","kilowatt","kilowatts","electricity","kW"] + }, + { + "name": "unit.megawatt", + "symbol": "MW", + "tags": ["power","horsepower","performance","megawatt","megawatts","electricity","MW"] + }, + { + "name": "unit.gigawatt", + "symbol": "GW", + "tags": ["power","horsepower","performance","gigawatt","gigawatts","electricity","GW"] + }, + { + "name": "unit.metric-horsepower", + "symbol": "PS", + "tags": ["power","performance","metric horsepower","PS"] + }, + { + "name": "unit.milliwatt-per-square-centimeter", + "symbol": "mW/cm²", + "tags": ["power density","radiation intensity","sunlight intensity","signal power","intensity", + "milliwatts per square centimeter","UV Intensity","mW/cm²"] + }, + { + "name": "unit.watt-per-square-centimeter", + "symbol": "W/cm²", + "tags": ["power density","intensity of power","watts per square centimeter","W/cm²"] + }, + { + "name": "unit.kilowatt-per-square-centimeter", + "symbol": "kW/cm²", + "tags": ["power density","intensity of power","kilowatts per square centimeter","kW/cm²"] + }, + { + "name": "unit.milliwatt-per-square-meter", + "symbol": "mW/m²", + "tags": ["power density","intensity of power","milliwatts per square meter","mW/m²"] + }, + { + "name": "unit.watt-per-square-meter", + "symbol": "W/m²", + "tags": ["power density","intensity of power","watts per square meter","W/m²"] + }, + { + "name": "unit.kilowatt-per-square-meter", + "symbol": "kW/m²", + "tags": ["power density","intensity of power","kilowatts per square meter","kW/m²"] + }, + { + "name": "unit.watt-per-square-inch", + "symbol": "W/in²", + "tags": ["power density","intensity of power","watts per square inch","W/in²"] + }, + { + "name": "unit.kilowatt-per-square-inch", + "symbol": "kW/in²", + "tags": ["power density","intensity of power","kilowatts per square inch","kW/in²"] + }, + { + "name": "unit.horsepower", + "symbol": "hp", + "tags": ["power","horsepower","performance","electricity","horsepowers","hp"] + }, + { + "name": "unit.btu-per-hour", + "symbol": "BTU/h", + "tags": ["power","heat transfer","thermal energy","HVAC","BTU/h"] + }, + { + "name": "unit.coulomb", + "symbol": "C", + "tags": ["charge","electricity","electrostatics","Coulomb","C"] + }, + { + "name": "unit.millicoulomb", + "symbol": "mC", + "tags": ["charge","electricity","electrostatics","millicoulombs","mC"] + }, + { + "name": "unit.microcoulomb", + "symbol": "µC", + "tags": ["charge","electricity","electrostatics","microcoulomb","µC"] + }, + { + "name": "unit.picocoulomb", + "symbol": "pC", + "tags": ["charge","electricity","electrostatics","picocoulomb","pC"] + }, + { + "name": "unit.coulomb-per-meter", + "symbol": "C/m", + "tags": ["electric displacement field per length","coulomb per meter","C/m"] + }, + { + "name": "unit.coulomb-per-cubic-meter", + "symbol": "C/m³", + "tags": ["electric charge density","coulomb per cubic meter","C/m³"] + }, + { + "name": "unit.coulomb-per-square-meter", + "symbol": "C/m²", + "tags": ["electric surface charge density","coulomb per square meter","C/m²"] + }, + { + "name": "unit.square-millimeter", + "symbol": "mm²", + "tags": ["area","lot","zone","space","region","square millimeter","square millimeters","mm²","sq-mm"] + }, + { + "name": "unit.square-centimeter", + "symbol": "cm²", + "tags": ["area","lot","zone","space","region","square centimeter","square centimeters","cm²","sq-cm"] + }, + { + "name": "unit.square-meter", + "symbol": "m²", + "tags": ["area","lot","zone","space","region","square meter","square meters","m²","sq-m"] + }, + { + "name": "unit.hectare", + "symbol": "ha", + "tags": ["area","lot","zone","space","region","hectare","hectares","ha"] + }, + { + "name": "unit.square-kilometer", + "symbol": "km²", + "tags": ["area","lot","zone","space","region","square kilometer","square kilometers","km²","sq-km"] + }, + { + "name": "unit.square-inch", + "symbol": "in²", + "tags": ["area","lot","zone","space","region","square inch","square inches","in²","sq-in"] + }, + { + "name": "unit.square-foot", + "symbol": "ft²", + "tags": ["area","lot","zone","space","region","square foot","square feet","ft²","sq-ft"] + }, + { + "name": "unit.square-yard", + "symbol": "yd²", + "tags": ["area","lot","zone","space","region","square yard","square yards","yd²","sq-yd"] + }, + { + "name": "unit.acre", + "symbol": "a", + "tags": ["area","lot","zone","space","region","acre","acres","a"] + }, + { + "name": "unit.square-mile", + "symbol": "ml²", + "tags": ["area","lot","zone","space","region","square mile","square miles","ml²","sq-mi"] + }, + { + "name": "unit.are", + "symbol": "are", + "tags": ["area","land measurement","are"] + }, + { + "name": "unit.barn", + "symbol": "barn", + "tags": ["cross-sectional area","particle physics","nuclear physics","barn"] + }, + { + "name": "unit.circular-inch", + "symbol": "circin", + "tags": ["area","circular measurement","circular inch","circin"] + }, + { + "name": "unit.milliampere-hour", + "symbol": "mAh", + "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity", + "electrical flow","milliampere-hour","milliampere-hours","mAh"] + }, + { + "name": "unit.ampere-hours", + "symbol": "Ah", + "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity", + "electrical flow","ampere","ampere-hours","Ah"] + }, + { + "name": "unit.kiloampere-hours", + "symbol": "kAh", + "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity","electrical flow", + "kiloampere-hours","kiloampere-hour","kAh"] + }, + { + "name": "unit.nanoampere", + "symbol": "nA", + "tags": ["current","amperes","nanoampere","nA"] + }, + { + "name": "unit.picoampere", + "symbol": "pA", + "tags": ["current","amperes","picoampere","pA"] + }, + { + "name": "unit.microampere", + "symbol": "μA", + "tags": ["electric current","microampere","microamperes","μA"] + }, + { + "name": "unit.milliampere", + "symbol": "mA", + "tags": ["electric current","milliampere","milliamperes","mA"] + }, + { + "name": "unit.ampere", + "symbol": "A", + "tags": ["electric current","current flow","flow of electricity","electrical flow","ampere","amperes","amperage","A"] + }, + { + "name": "unit.kiloamperes", + "symbol": "kA", + "tags": ["electric current","current flow","kiloamperes","kA"] + }, + { + "name": "unit.microampere-per-square-centimeter", + "symbol": "µA/cm²", + "tags": ["Current density","microampere per square centimeter","µA/cm²"] + }, + { + "name": "unit.ampere-per-square-meter", + "symbol": "A/m²", + "tags": ["current density","current per unit area","ampere per square meter","A/m²"] + }, + { + "name": "unit.ampere-per-meter", + "symbol": "A/m", + "tags": ["magnetic field strength","magnetic field intensity","ampere per meter","A/m"] + }, + { + "name": "unit.oersted", + "symbol": "Oe", + "tags": ["magnetic field","oersted","Oe"] + }, + { + "name": "unit.bohr-magneton", + "symbol": "μB", + "tags": ["atomic physics","magnetic moment","bohr magneton","μB"] + }, + { + "name": "unit.ampere-meter-squared", + "symbol": "A·m²", + "tags": ["magnetic moment","dipole moment","ampere-meter squared","A·m²"] + }, + { + "name": "unit.ampere-meter", + "symbol": "A·m", + "tags": ["magnetic field","current loop","ampere-meter","A·m"] + }, + { + "name": "unit.nanovolt", + "symbol": "nV", + "tags": ["voltage","volts","nanovolt","nV"] + }, + { + "name": "unit.picovolt", + "symbol": "pV", + "tags": ["voltage","volts","picovolt","pV"] + }, + { + "name": "unit.millivolts", + "symbol": "mV", + "tags": ["electric potential","electric tension","voltage","millivolt","millivolts","mV"] + }, + { + "name": "unit.microvolts", + "symbol": "μV", + "tags": ["electric potential","electric tension","voltage","microvolt","microvolts","μV"] + }, + { + "name": "unit.volt", + "symbol": "V", + "tags": ["electric potential","electric tension","voltage","volt","volts","V","power source","battery","battery level"] + }, + { + "name": "unit.kilovolts", + "symbol": "kV", + "tags": ["electric potential","electric tension","voltage","kilovolt","kilovolts","kV"] + }, + { + "name": "unit.dbmV", + "symbol": "dBmV", + "tags": ["decibels millivolt","voltage level","signal","dBmV"] + }, + { + "name": "unit.volt-meter", + "symbol": "V·m", + "tags": ["electric flux","volt-meter","V·m"] + }, + { + "name": "unit.kilovolt-meter", + "symbol": "kV·m", + "tags": ["electric flux","kilovolt-meter","kV·m"] + }, + { + "name": "unit.megavolt-meter", + "symbol": "MV·m", + "tags": ["electric flux","megavolt-meter","MV·m"] + }, + { + "name": "unit.microvolt-meter", + "symbol": "µV·m", + "tags": ["electric flux","microvolt-meter","µV·m"] + }, + { + "name": "unit.millivolt-meter", + "symbol": "mV·m", + "tags": ["electric flux","millivolt-meter","mV·m"] + }, + { + "name": "unit.nanovolt-meter", + "symbol": "nV·m", + "tags": ["electric flux","nanovolt-meter","nV·m"] + }, + { + "name": "unit.ohm", + "symbol": "Ω", + "tags": ["electrical resistance","resistance","impedance","ohm"] + }, + { + "name": "unit.microohm", + "symbol": "μΩ", + "tags": ["electrical resistance","resistance","microohm","μΩ"] + }, + { + "name": "unit.milliohm", + "symbol": "mΩ", + "tags": ["electrical resistance","resistance","milliohm","mΩ"] + }, + { + "name": "unit.kilohm", + "symbol": "kΩ", + "tags": ["electrical resistance","resistance","kilohm","kΩ"] + }, + { + "name": "unit.megohm", + "symbol": "MΩ", + "tags": ["electrical resistance","resistance","megohm","MΩ"] + }, + { + "name": "unit.gigohm", + "symbol": "GΩ", + "tags": ["electrical resistance","resistance","gigohm","GΩ"] + }, + { + "name": "unit.hertz", + "symbol": "Hz", + "tags": ["frequency","cycles per second","hertz","Hz"] + }, + { + "name": "unit.kilohertz", + "symbol": "kHz", + "tags": ["frequency","cycles per second","kilohertz","kHz"] + }, + { + "name": "unit.megahertz", + "symbol": "MHz", + "tags": ["frequency","cycles per second","megahertz","MHz"] + }, + { + "name": "unit.gigahertz", + "symbol": "GHz", + "tags": ["frequency","cycles per second","gigahertz","GHz"] + }, + { + "name": "unit.rpm", + "symbol": "RPM", + "tags": ["speed","velocity","cycle","engine","Revolutions Per Minute","RPM","angular velocity","rotation speed"] + }, + { + "name": "unit.candela-per-square-meter", + "symbol": "cd/m²", + "tags": ["brightness","light level","Luminance","Candela per square meter","cd/m²"] + }, + { + "name": "unit.candela", + "symbol": "cd", + "tags": ["light intensity","candle power","luminous intensity","Candela","cd"] + }, + { + "name": "unit.lumen", + "symbol": "lm", + "tags": ["total light output","light power","luminous flux","Lumen","lm"] + }, + { + "name": "unit.lux", + "symbol": "lx", + "tags": ["illumination","light level on a surface","illuminance","Lux","lx"] + }, + { + "name": "unit.foot-candle", + "symbol": "fc", + "tags": ["illuminance","light level","foot-candle","fc"] + }, + { + "name": "unit.lumen-per-square-meter", + "symbol": "lm/m²", + "tags": ["illuminance","light level","lumen per square meter","lm/m²"] + }, + { + "name": "unit.lux-second", + "symbol": "lx·s", + "tags": ["light exposure","illumination time","light dosage","Lux second","lx·s"] + }, + { + "name": "unit.lumen-second", + "symbol": "lm·s", + "tags": ["total light energy","luminous energy","Lumen second","lm·s"] + }, + { + "name": "unit.lumens-per-watt", + "symbol": "lm/W", + "tags": ["lighting efficiency","light output per energy","luminous efficacy","Lumens per watt","lm/W"] + }, + { + "name": "unit.absorbance", + "symbol": "AU", + "tags": ["optical density","light absorption","absorbance","AU"] + }, + { + "name": "unit.mole", + "symbol": "mol", + "tags": ["amount of substance","substance quantity","mole","moles","mol"] + }, + { + "name": "unit.nanomole", + "symbol": "nmol", + "tags": ["amount of substance","substance quantity","concentration","nanomole","nmol"] + }, + { + "name": "unit.micromole", + "symbol": "μmol", + "tags": ["amount of substance","substance quantity","micromole","μmol"] + }, + { + "name": "unit.millimole", + "symbol": "mmol", + "tags": ["amount of substance","substance quantity","millimole","mmol"] + }, + { + "name": "unit.kilomole", + "symbol": "kmol", + "tags": ["amount of substance","substance quantity","kilomole","kmol"] + }, + { + "name": "unit.mole-per-cubic-meter", + "symbol": "mol/m³", + "tags": ["concentration","amount of substance","mole per cubic meter","mol/m³"] + }, + { + "name": "unit.battery", + "symbol": "%", + "tags": ["power source","state of charge (SoC)","battery","battery level","level","humidity","moisture", + "relative humidity","water content","soil moisture","irrigation","water in soil","soil water content","VWC", + "Volumetric Water Content","Total Harmonic Distortion","THD","power quality","UV Transmittance","%"] + }, + { + "name": "unit.rssi", + "symbol": "rssi", + "tags": ["signal strength","signal level","received signal strength indicator","rssi","dBm"] + }, + { + "name": "unit.ppm", + "symbol": "ppm", + "tags": ["carbon dioxide","co²","carbon monoxide","co","aqi","air quality","total volatile organic compounds","tvoc","ppm"] + }, + { + "name": "unit.ppb", + "symbol": "ppb", + "tags": ["ozone","o³","nitrogen dioxide","no²","sulfur dioxide","so²","aqi","air quality","tvoc","ppb"] + }, + { + "name": "unit.micrograms-per-cubic-meter", + "symbol": "µg/m³", + "tags": ["coarse particulate matter","pm10","fine particulate matter","pm2.5","aqi","air quality", + "total volatile organic compounds","tvoc","micrograms per cubic meter","µg/m³"] + }, + { + "name": "unit.aqi", + "symbol": "aqi", + "tags": ["AQI","air quality index"] + }, + { + "name": "unit.gram-per-cubic-meter", + "symbol": "g/m³", + "tags": ["humidity","moisture","absolute humidity","g/m³"] + }, + { + "name": "unit.gram-per-kilogram", + "symbol": "g/kg", + "tags": ["humidity","moisture","specific humidity","g/kg"] + }, + { + "name": "unit.millimeters-per-second", + "symbol": "mm/s", + "tags": ["velocity","speed","rate of motion","peak","peak to peak","root mean square (RMS)","vibration","mm/s"] + }, + { + "name": "unit.neper", + "symbol": "Np", + "tags": ["logarithmic unit","ratio","gain","loss","attenuation","neper","Np"] + }, + { + "name": "unit.bel", + "symbol": "B", + "tags": ["logarithmic unit","power ratio","intensity ratio","bel","B"] + }, + { + "name": "unit.decibel", + "symbol": "dB", + "tags": ["noise level","sound level","volume","acoustics","decibel","dB"] + }, + { + "name": "unit.meters-per-second-squared", + "symbol": "m/s²", + "tags": ["peak","peak to peak","root mean square (RMS)","vibration","meters per second squared","m/s²"] + }, + { + "name": "unit.becquerel", + "symbol": "Bq", + "tags": ["radioactivity","radiation","becquerel","Bq"] + }, + { + "name": "unit.curie", + "symbol": "Ci", + "tags": ["radioactivity","radiation","curie","Ci"] + }, + { + "name": "unit.gray", + "symbol": "Gy", + "tags": ["radiation dose","gray","Gy"] + }, + { + "name": "unit.sievert", + "symbol": "Sv", + "tags": ["radiation dose","sievert","radiation dose equivalent2","Sv"] + }, + { + "name": "unit.roentgen", + "symbol": "R", + "tags": ["radiation exposure","roentgen","R"] + }, + { + "name": "unit.cps", + "symbol": "cps", + "tags": ["radiation detection","counts per second","cps"] + }, + { + "name": "unit.rad", + "symbol": "Rad", + "tags": ["radiation dose","rad"] + }, + { + "name": "unit.rem", + "symbol": "Rem", + "tags": ["radiation dose equivalent","rem"] + }, + { + "name": "unit.dps", + "symbol": "dps", + "tags": ["radioactive decay","radioactivity","disintegrations per second","dps"] + }, + { + "name": "unit.rutherford", + "symbol": "Rd", + "tags": ["radioactive decay","radioactivity","rutherford","Rd"] + }, + { + "name": "unit.coulombs-per-kilogram", + "symbol": "C/kg", + "tags": ["radiation exposure","dose","coulombs per kilogram","electric charge-to-mass ratio","C/kg"] + }, + { + "name": "unit.becquerels-per-cubic-meter", + "symbol": "Bq/m³", + "tags": ["radioactivity","radiation","becquerels per cubic meter","Bq/m³"] + }, + { + "name": "unit.curies-per-liter", + "symbol": "Ci/L", + "tags": ["radioactivity","radiation","curies per liter","Ci/L"] + }, + { + "name": "unit.becquerels-per-second", + "symbol": "Bq/s", + "tags": ["radioactive decay rate","becquerels per second","Bq/s"] + }, + { + "name": "unit.curies-per-second", + "symbol": "Ci/s", + "tags": ["radioactive decay rate","curies per second","Ci/s"] + }, + { + "name": "unit.gy-per-second", + "symbol": "Gy/s", + "tags": ["absorbed dose rate","radiation dose rate","gray per second","Gy/s"] + }, + { + "name": "unit.watt-per-steradian", + "symbol": "W/sr", + "tags": ["radiant intensity","power per unit solid angle","watt per steradian","W/sr"] + }, + { + "name": "unit.watt-per-square-metre-steradian", + "symbol": "W/(m²·sr)", + "tags": ["radiance","radiant flux density","watt per square metre-steradian","W/(m²·sr)"] + }, + { + "name": "unit.ph-level", + "symbol": "pH", + "tags": ["acidity","alkalinity","neutral","acid","base","pH","soil pH","water quality","water pH"] + }, + { + "name": "unit.turbidity", + "symbol": "NTU", + "tags": ["water turbidity","water clarity","Nephelometric Turbidity Units","NTU"] + }, + { + "name": "unit.mg-per-liter", + "symbol": "mg/L", + "tags": ["dissolved oxygen","water quality","mg/L"] + }, + { + "name": "unit.microsiemens-per-centimeter", + "symbol": "µS/cm", + "tags": ["Electrical conductivity","water quality","soil quality","microsiemens per centimeter","µS/cm"] + }, + { + "name": "unit.millisiemens-per-meter", + "symbol": "mS/m", + "tags": ["Electrical conductivity","water quality","soil quality","millisiemens per meter","mS/m"] + }, + { + "name": "unit.siemens-per-meter", + "symbol": "S/m", + "tags": ["Electrical conductivity","water quality","soil quality","siemens per meter","S/m"] + }, + { + "name": "unit.kilogram-per-cubic-meter", + "symbol": "kg/m³", + "tags": ["density","mass per unit volume","kg/m³"] + }, + { + "name": "unit.gram-per-cubic-centimeter", + "symbol": "g/cm³", + "tags": ["density","mass per unit volume","g/cm³"] + }, + { + "name": "unit.kilogram-per-square-meter", + "symbol": "kg/m²", + "tags": ["density","surface density","areal density","mass per unit area","kg/m²"] + }, + { + "name": "unit.milligram-per-milliliter", + "symbol": "mg/mL", + "tags": ["concentration","mass per volume","mg/mL"] + }, + { + "name": "unit.pound-per-cubic-foot", + "symbol": "lb/ft³", + "tags": ["Density","mass per unit volume","lb/ft³"] + }, + { + "name": "unit.ounces-per-cubic-inch", + "symbol": "oz/in³", + "tags": ["density","mass per unit volume","oz/in³"] + }, + { + "name": "unit.tons-per-cubic-yard", + "symbol": "ton/yd³", + "tags": ["density","mass per unit volume","ton/yd³"] + }, + { + "name": "unit.particle-density", + "symbol": "particles/mL", + "tags": ["particle concentration","count","particles/mL"] + }, + { + "name": "unit.kilometers-per-liter", + "symbol": "km/L", + "tags": ["fuel efficiency","km/L"] + }, + { + "name": "unit.miles-per-gallon", + "symbol": "mpg", + "tags": ["fuel efficiency","mpg"] + }, + { + "name": "unit.liters-per-100-km", + "symbol": "L/100km", + "tags": ["fuel efficiency","L/100km"] + }, + { + "name": "unit.gallons-per-mile", + "symbol": "gal/mi", + "tags": ["fuel efficiency","gal/mi"] + }, + { + "name": "unit.liters-per-hour", + "symbol": "L/hr", + "tags": ["fuel consumption","L/hr"] + }, + { + "name": "unit.gallons-per-hour", + "symbol": "gal/hr", + "tags": ["fuel consumption","gal/hr"] + }, + { + "name": "unit.beats-per-minute", + "symbol": "bpm", + "tags": ["heart rate","pulse","bpm"] + }, + { + "name": "unit.millimeters-of-mercury", + "symbol": "mmHg", + "tags": ["blood pressure","systolic","diastolic","mmHg"] + }, + { + "name": "unit.milligrams-per-deciliter", + "symbol": "mg/dL", + "tags": ["glucose","blood sugar","glucose level","mg/dL"] + }, + { + "name": "unit.g-force", + "symbol": "G", + "tags": ["acceleration","gravity","force","g-load","G"] + }, + { + "name": "unit.kilonewton", + "symbol": "kN", + "tags": ["force","kN"] + }, + { + "name": "unit.kilogram-force", + "symbol": "kgf", + "tags": ["force","kgf"] + }, + { + "name": "unit.pound-force", + "symbol": "lbf", + "tags": ["force","lbf"] + }, + { + "name": "unit.kilopound-force", + "symbol": "klbf", + "tags": ["force","klbf"] + }, + { + "name": "unit.dyne", + "symbol": "dyn", + "tags": ["force","dyn"] + }, + { + "name": "unit.poundal", + "symbol": "pdl", + "tags": ["force","pdl"] + }, + { + "name": "unit.kip", + "symbol": "kip", + "tags": ["force","kip"] + }, + { + "name": "unit.gal", + "symbol": "Gal", + "tags": ["acceleration","gravity","g-force","Gal"] + }, + { + "name": "unit.gravity", + "symbol": "gravity", + "tags": ["acceleration","gravity","g-force"] + }, + { + "name": "unit.hectopascal", + "symbol": "hPa", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","hPa"] + }, + { + "name": "unit.atmosphere", + "symbol": "atm", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","atm"] + }, + { + "name": "unit.millibars", + "symbol": "mb", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","mb"] + }, + { + "name": "unit.inch-of-mercury", + "symbol": "inHg", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","inHg","richter"] + }, + { + "name": "unit.richter-scale", + "symbol": "richter", + "tags": ["earthquake","seismic activity","richter"] + }, + { + "name": "unit.percentage", + "symbol": "%", + "tags": ["percentage"] + }, + { + "name": "unit.second", + "symbol": "s", + "tags": ["time","duration","interval","angle","second","arcsecond","sec"] + }, + { + "name": "unit.minute", + "symbol": "min", + "tags": ["time","duration","interval","angle","minute","arcminute","min"] + }, + { + "name": "unit.hour", + "symbol": "h", + "tags": ["time","duration","interval","h"] + }, + { + "name": "unit.day", + "symbol": "d", + "tags": ["time","duration","interval","d"] + }, + { + "name": "unit.week", + "symbol": "wk", + "tags": ["time","duration","interval","wk"] + }, + { + "name": "unit.month", + "symbol": "mo", + "tags": ["time","duration","interval","mo"] + }, + { + "name": "unit.year", + "symbol": "yr", + "tags": ["time","duration","interval","yr"] + }, + { + "name": "unit.cubic-foot-per-minute", + "symbol": "ft³/min", + "tags": ["airflow","ventilation","HVAC","gas flow rate","CFM","flow rate","fluid flow","cubic foot per minute","ft³/min"] + }, + { + "name": "unit.cubic-meters-per-hour", + "symbol": "m³/hr", + "tags": ["airflow","ventilation","HVAC","gas flow rate","cubic meters per hour","m³/hr"] + }, + { + "name": "unit.cubic-meters-per-second", + "symbol": "m³/s", + "tags": ["airflow","ventilation","HVAC","gas flow rate","cubic meters per second","m³/s"] + }, + { + "name": "unit.liter-per-second", + "symbol": "L/s", + "tags": ["airflow","ventilation","HVAC","gas flow rate","liter per second","L/s"] + }, + { + "name": "unit.liter-per-minute", + "symbol": "L/min", + "tags": ["airflow","ventilation","HVAC","gas flow rate","liter per minute","L/min"] + }, + { + "name": "unit.gallons-per-minute", + "symbol": "GPM", + "tags": ["airflow","ventilation","HVAC","gas flow rate","gallons per minute","GPM"] + }, + { + "name": "unit.cubic-foot-per-second", + "symbol": "ft³/s", + "tags": ["flow rate","fluid flow","cubic foot per second","cubic feet per second","ft³/s"] + }, + { + "name": "unit.milliliters-per-minute", + "symbol": "mL/min", + "tags": ["Flow rate","fluid dynamics","milliliters per minute","mL/min"] + }, + { + "name": "unit.bit", + "symbol": "bit", + "tags": ["data","binary digit","information","bit"] + }, + { + "name": "unit.byte", + "symbol": "B", + "tags": ["data","byte","information","storage","memory","B"] + }, + { + "name": "unit.kilobyte", + "symbol": "KB", + "tags": ["data","kilobyte","KB"] + }, + { + "name": "unit.megabyte", + "symbol": "MB", + "tags": ["data","megabyte","MB"] + }, + { + "name": "unit.gigabyte", + "symbol": "GB", + "tags": ["data","gigabyte","GB"] + }, + { + "name": "unit.terabyte", + "symbol": "TB", + "tags": ["data","terabyte","TB"] + }, + { + "name": "unit.petabyte", + "symbol": "PB", + "tags": ["data","petabyte","PB"] + }, + { + "name": "unit.exabyte", + "symbol": "EB", + "tags": ["data","exabyte","EB"] + }, + { + "name": "unit.zettabyte", + "symbol": "ZB", + "tags": ["data","zettabyte","ZB"] + }, + { + "name": "unit.yottabyte", + "symbol": "YB", + "tags": ["data","yottabyte","YB"] + }, + { + "name": "unit.bit-per-second", + "symbol": "bps", + "tags": ["data transfer rate","bps"] + }, + { + "name": "unit.kilobit-per-second", + "symbol": "kbps", + "tags": ["data transfer rate","kbps"] + }, + { + "name": "unit.megabit-per-second", + "symbol": "Mbps", + "tags": ["data transfer rate","Mbps"] + }, + { + "name": "unit.gigabit-per-second", + "symbol": "Gbps", + "tags": ["data transfer rate","Gbps"] + }, + { + "name": "unit.terabit-per-second", + "symbol": "Tbps", + "tags": ["data transfer rate","Tbps"] + }, + { + "name": "unit.byte-per-second", + "symbol": "B/s", + "tags": ["data transfer rate","B/s"] + }, + { + "name": "unit.kilobyte-per-second", + "symbol": "KB/s", + "tags": ["data transfer rate","KB/s"] + }, + { + "name": "unit.megabyte-per-second", + "symbol": "MB/s", + "tags": ["data transfer rate","MB/s"] + }, + { + "name": "unit.gigabyte-per-second", + "symbol": "GB/s", + "tags": ["data transfer rate","GB/s"] + }, + { + "name": "unit.degree", + "symbol": "deg", + "tags": ["angle","degree","degrees","deg"] + }, + { + "name": "unit.radian", + "symbol": "rad", + "tags": ["angle","radian","radians","rad"] + }, + { + "name": "unit.gradian", + "symbol": "grad", + "tags": ["angle","gradian","grades","grad"] + }, + { + "name": "unit.mil", + "symbol": "mil", + "tags": ["angle","military angle","angular mil","mil"] + }, + { + "name": "unit.revolution", + "symbol": "rev", + "tags": ["angle","revolution","full circle","complete turn","rev"] + }, + { + "name": "unit.siemens", + "symbol": "S", + "tags": ["electrical conductance","conductance","siemens","S"] + }, + { + "name": "unit.millisiemens", + "symbol": "mS", + "tags": ["electrical conductance","conductance","millisiemens","mS"] + }, + { + "name": "unit.microsiemens", + "symbol": "μS", + "tags": ["electrical conductance","conductance","microsiemens","μS"] + }, + { + "name": "unit.kilosiemens", + "symbol": "kS", + "tags": ["electrical conductance","conductance","kilosiemens","kS"] + }, + { + "name": "unit.megasiemens", + "symbol": "MS", + "tags": ["electrical conductance","conductance","megasiemens","MS"] + }, + { + "name": "unit.gigasiemens", + "symbol": "GS", + "tags": ["electrical conductance","conductance","gigasiemens","GS"] + }, + { + "name": "unit.farad", + "symbol": "F", + "tags": ["electric capacitance","capacitance","farad","F"] + }, + { + "name": "unit.millifarad", + "symbol": "mF", + "tags": ["electric capacitance","capacitance","millifarad","mF"] + }, + { + "name": "unit.microfarad", + "symbol": "μF", + "tags": ["electric capacitance","capacitance","microfarad","μF"] + }, + { + "name": "unit.nanofarad", + "symbol": "nF", + "tags": ["electric capacitance","capacitance","nanofarad","nF"] + }, + { + "name": "unit.picofarad", + "symbol": "pF", + "tags": ["electric capacitance","capacitance","picofarad","pF"] + }, + { + "name": "unit.kilofarad", + "symbol": "kF", + "tags": ["electric capacitance","capacitance","kilofarad","kF"] + }, + { + "name": "unit.megafarad", + "symbol": "MF", + "tags": ["electric capacitance","capacitance","megafarad","MF"] + }, + { + "name": "unit.gigafarad", + "symbol": "GF", + "tags": ["electric capacitance","capacitance","gigafarad","GF"] + }, + { + "name": "unit.terfarad", + "symbol": "TF", + "tags": ["electric capacitance","capacitance","terafarad","TF"] + }, + { + "name": "unit.farad-per-meter", + "symbol": "F/m", + "tags": ["electric permittivity","farad per meter","F/m"] + }, + { + "name": "unit.tesla", + "symbol": "T", + "tags": ["magnetic field","magnetic field strength","tesla","T","magnetic flux density"] + }, + { + "name": "unit.gauss", + "symbol": "G", + "tags": ["magnetic field","magnetic field strength","gauss","G","magnetic flux density"] + }, + { + "name": "unit.kilogauss", + "symbol": "kG", + "tags": ["magnetic field","magnetic field strength","kilogauss","kG","magnetic flux density"] + }, + { + "name": "unit.millitesla", + "symbol": "mT", + "tags": ["magnetic field","magnetic field strength","millitesla","mT"] + }, + { + "name": "unit.microtesla", + "symbol": "μT", + "tags": ["magnetic field","magnetic field strength","microtesla","μT"] + }, + { + "name": "unit.nanotesla", + "symbol": "nT", + "tags": ["magnetic field","magnetic field strength","nanotesla","nT"] + }, + { + "name": "unit.kilotesla", + "symbol": "kT", + "tags": ["magnetic field","magnetic field strength","kilotesla","kT"] + }, + { + "name": "unit.megatesla", + "symbol": "MT", + "tags": ["magnetic field","magnetic field strength","megatesla","MT"] + }, + { + "name": "unit.millitesla-square-meters", + "symbol": "millitesla square meters", + "tags": ["magnetic field","millitesla square meters"] + }, + { + "name": "unit.gamma", + "symbol": "γ", + "tags": ["magnetic flux density","gamma","γ"] + }, + { + "name": "unit.lambda", + "symbol": "λ", + "tags": ["wavelength","lambda","λ"] + }, + { + "name": "unit.square-meter-per-second", + "symbol": "m²/s", + "tags": ["kinematic viscosity","m²/s"] + }, + { + "name": "unit.square-centimeter-per-second", + "symbol": "cm²/s", + "tags": ["kinematic viscosity","cm²/s"] + }, + { + "name": "unit.stoke", + "symbol": "St", + "tags": ["kinematic viscosity","stokes","St"] + }, + { + "name": "unit.centistokes", + "symbol": "cSt", + "tags": ["kinematic viscosity","centistokes","cSt"] + }, + { + "name": "unit.square-foot-per-second", + "symbol": "ft²/s", + "tags": ["kinematic viscosity","ft²/s"] + }, + { + "name": "unit.square-inch-per-second", + "symbol": "in²/s", + "tags": ["kinematic viscosity","in²/s"] + }, + { + "name": "unit.pascal-second", + "symbol": "Pa·s", + "tags": ["dynamic viscosity","viscosity","fluid mechanics","pascal-second","Pa·s"] + }, + { + "name": "unit.centipoise", + "symbol": "cP", + "tags": ["viscosity","dynamic viscosity","fluid viscosity","centipoise","cP"] + }, + { + "name": "unit.poise", + "symbol": "P", + "tags": ["viscosity","dynamic viscosity","fluid viscosity","poise","P"] + }, + { + "name": "unit.reynolds", + "symbol": "Re", + "tags": ["fluid flow regime","fluid mechanics","reynolds","Re"] + }, + { + "name": "unit.pound-per-foot-hour", + "symbol": "lb/(ft·h)", + "tags": ["pound per foot-hour","lb/(ft·h)"] + }, + { + "name": "unit.newton-second-per-square-meter", + "symbol": "N·s/m²", + "tags": ["newton second per square meter","N·s/m²"] + }, + { + "name": "unit.dyne-second-per-square-centimeter", + "symbol": "dyn·s/cm²", + "tags": ["dyne second per square centimeter","dyn·s/cm²"] + }, + { + "name": "unit.kilogram-per-meter-second", + "symbol": "kg/(m·s)", + "tags": ["kilogram per meter-second","kg/(m·s)"] + }, + { + "name": "unit.tesla-square-meters", + "symbol": "T/m²", + "tags": ["magnetic flux density","tesla square meters","T/m²"] + }, + { + "name": "unit.maxwell", + "symbol": "Mx", + "tags": ["magnetic flux","magnetic field","maxwell","Mx"] + }, + { + "name": "unit.tesla-per-meter", + "symbol": "T/m", + "tags": ["magnetic field","tesla per meter","T/m"] + }, + { + "name": "unit.gauss-per-centimeter", + "symbol": "G/cm", + "tags": ["magnetic field","gauss per centimeter","G/cm"] + }, + { + "name": "unit.weber", + "symbol": "Wb", + "tags": ["magnetic flux","weber","Wb"] + }, + { + "name": "unit.microweber", + "symbol": "µWb", + "tags": ["magnetic flux","microweber","µWb"] + }, + { + "name": "unit.milliweber", + "symbol": "mWb", + "tags": ["magnetic flux","milliweber","mWb"] + }, + { + "name": "unit.gauss-square-centimeter", + "symbol": "G·cm²", + "tags": ["magnetic flux","gauss-square centimeter","G·cm²"] + }, + { + "name": "unit.kilogauss-square-centimeter", + "symbol": "kG·cm²", + "tags": ["magnetic flux","kilogauss-square centimeter","kG·cm²"] + }, + { + "name": "unit.henry", + "symbol": "H", + "tags": ["inductance","magnetic induction","H"] + }, + { + "name": "unit.millihenry", + "symbol": "mH", + "tags": ["inductance","millihenry","mH"] + }, + { + "name": "unit.microhenry", + "symbol": "µH", + "tags": ["inductance","microhenry","µH"] + }, + { + "name": "unit.nanohenry", + "symbol": "nH", + "tags": ["inductance","nanohenry","nH"] + }, + { + "name": "unit.henry-per-meter", + "symbol": "H/m", + "tags": ["magnetic permeability","henry per meter","H/m"] + }, + { + "name": "unit.tesla-meter-per-ampere", + "symbol": "T·m/A", + "tags": ["magnetic field","Tesla Meter per Ampere","T·m/A","magnetic flux"] + }, + { + "name": "unit.gauss-per-oersted", + "symbol": "G/Oe", + "tags": ["magnetic field","Gauss per Oersted","G/Oe"] + }, + { + "name": "unit.kilogram-per-mole", + "symbol": "kg/mol", + "tags": ["molar mass","kilogram per mole","kg/mol"] + }, + { + "name": "unit.gram-per-mole", + "symbol": "g/mol", + "tags": ["molar mass","gram per mole","g/mol"] + }, + { + "name": "unit.milligram-per-mole", + "symbol": "mg/mol", + "tags": ["molar mass","milligram per mole","mg/mol"] + }, + { + "name": "unit.joule-per-mole", + "symbol": "J/mol", + "tags": ["molar energy","joule per mole","J/mol"] + }, + { + "name": "unit.joule-per-mole-kelvin", + "symbol": "J/(mol·K)", + "tags": ["molar heat capacity","joule per mole-kelvin","J/(mol·K)"] + }, + { + "name": "unit.millivolts-per-meter", + "symbol": "mV/m", + "tags": ["electric field strength","millivolts per meter","mV/m"] + }, + { + "name": "unit.volts-per-meter", + "symbol": "V/m", + "tags": ["electric field strength","volts per meter","V/m"] + }, + { + "name": "unit.kilovolts-per-meter", + "symbol": "kV/m", + "tags": ["electric field strength","kilovolts per meter","kV/m"] + }, + { + "name": "unit.radian-per-second", + "symbol": "rad/s", + "tags": ["angular velocity","rotation speed","rad/s"] + }, + { + "name": "unit.radian-per-second-squared", + "symbol": "rad/s²", + "tags": ["angular acceleration","rotation rate of change","rad/s²"] + }, + { + "name": "unit.revolutions-per-minute-per-second", + "symbol": "rpm/s", + "tags": ["angular acceleration","rotation rate of change","rpm/s"] + }, + { + "name": "unit.revolutions-per-minute-per-second-squared", + "symbol": "rpm/s²", + "tags": ["angular acceleration","rotation rate of change","rpm/s²"] + }, + { + "name": "unit.deg-per-second", + "symbol": "deg/s", + "tags": ["angular velocity","degrees per second","deg/s"] + }, + { + "name": "unit.degrees-brix", + "symbol": "°Bx", + "tags": ["sugar content","fruit ripeness","Bx"] + }, + { + "name": "unit.katal", + "symbol": "kat", + "tags": ["catalytic activity","enzyme activity","kat"] + }, + { + "name": "unit.katal-per-cubic-metre", + "symbol": "kat/m³", + "tags": ["catalytic activity concentration","enzyme concentration","kat/m³"] + } + ] +} From 75b38827820814880452b8c5dc68bf55050239b9 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 14 Jul 2023 19:45:23 +0200 Subject: [PATCH 265/421] added zk restart node tests --- .../queue/discovery/ZkDiscoveryService.java | 2 +- .../discovery/ZkDiscoveryServiceTest.java | 173 ++++++++++++++++++ 2 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index 24a7863b24..50378d3387 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -71,7 +71,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi @Value("${zk.recalculate_delay:120000}") private Long recalculateDelay; - private final ConcurrentHashMap> delayedTasks; + protected final ConcurrentHashMap> delayedTasks; private final TbServiceInfoProvider serviceInfoProvider; private final PartitionService partitionService; diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java new file mode 100644 index 0000000000..38cad217aa --- /dev/null +++ b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java @@ -0,0 +1,173 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.queue.discovery; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.imps.CuratorFrameworkState; +import org.apache.curator.framework.recipes.cache.ChildData; +import org.apache.curator.framework.recipes.cache.PathChildrenCache; +import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.gen.transport.TransportProtos; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_ADDED; +import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_REMOVED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ZkDiscoveryServiceTest { + + @Mock + private TbServiceInfoProvider serviceInfoProvider; + + @Mock + private PartitionService partitionService; + + @Mock + private CuratorFramework client; + + @Mock + private PathChildrenCache cache; + + private ScheduledExecutorService zkExecutorService; + + @Mock + private CuratorFramework curatorFramework; + + private ZkDiscoveryService zkDiscoveryService; + + @Before + public void setup() { + zkDiscoveryService = Mockito.spy(new ZkDiscoveryService(serviceInfoProvider, partitionService)); + zkExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("zk-discovery")); + when(client.getState()).thenReturn(CuratorFrameworkState.STARTED); + ReflectionTestUtils.setField(zkDiscoveryService, "stopped", false); + ReflectionTestUtils.setField(zkDiscoveryService, "client", client); + ReflectionTestUtils.setField(zkDiscoveryService, "cache", cache); + ReflectionTestUtils.setField(zkDiscoveryService, "nodePath", "/thingsboard/nodes/0000000010"); + ReflectionTestUtils.setField(zkDiscoveryService, "zkExecutorService", zkExecutorService); + ReflectionTestUtils.setField(zkDiscoveryService, "recalculateDelay", 1000L); + ReflectionTestUtils.setField(zkDiscoveryService, "zkDir", "/thingsboard"); + } + + @Test + public void restartNodeTest() throws Exception { + var currentInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("currentId").build(); + var currentData = new ChildData("/thingsboard/nodes/0000000010", null, currentInfo.toByteArray()); + var childInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("childId").build(); + var childData = new ChildData("/thingsboard/nodes/0000000020", null, childInfo.toByteArray()); + + when(serviceInfoProvider.getServiceInfo()).thenReturn(currentInfo); + List dataList = new ArrayList<>(); + dataList.add(currentData); + when(cache.getCurrentData()).thenReturn(dataList); + + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + + //Restart in timeAssert.assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + stopNode(childData); + + assertEquals(1, zkDiscoveryService.delayedTasks.size()); + + verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + + startNode(childData); + + verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + + Thread.sleep(2000); + + verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + + assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + + //Restart not in time + stopNode(childData); + + assertEquals(1, zkDiscoveryService.delayedTasks.size()); + + Thread.sleep(2000); + + assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(Collections.emptyList())); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + + //Start another node during restart + var anotherInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("anotherId").build(); + var anotherData = new ChildData("/thingsboard/nodes/0000000030", null, anotherInfo.toByteArray()); + + stopNode(childData); + + assertEquals(1, zkDiscoveryService.delayedTasks.size()); + + startNode(anotherData); + + assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo))); + reset(partitionService); + + Thread.sleep(2000); + + verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo, childInfo))); + } + + private void startNode(ChildData data) throws Exception { + cache.getCurrentData().add(data); + zkDiscoveryService.childEvent(curatorFramework, new PathChildrenCacheEvent(CHILD_ADDED, data)); + } + + private void stopNode(ChildData data) throws Exception { + cache.getCurrentData().remove(data); + zkDiscoveryService.childEvent(curatorFramework, new PathChildrenCacheEvent(CHILD_REMOVED, data)); + } + +} From b271baefd443023d8f58c5fe6883bd18924e0966 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 17 Jul 2023 11:17:56 +0300 Subject: [PATCH 266/421] updated rule node templatization help pages with new screenshots and updated key names in text --- ...r_attributes_node_fields_templatization.md | 12 +-- ...nator_fields_node_fields_templatization.md | 20 ++-- ...or_telemetry_node_fields_templatization.md | 95 +++++++++--------- ..._entity_data_node_fields_templatization.md | 13 ++- ...t_attributes_node_fields_templatization.md | 12 +-- .../examples/customer-attributes-ft.png | Bin 85413 -> 88911 bytes .../examples/originator-attributes-ft.png | Bin 73529 -> 86148 bytes .../examples/originator-fields-ft.png | Bin 70946 -> 75513 bytes .../examples/originator-telemetry-ft-2.png | Bin 60659 -> 128981 bytes .../examples/originator-telemetry-ft-3.png | Bin 78213 -> 0 bytes .../examples/originator-telemetry-ft.png | Bin 69883 -> 114627 bytes .../examples/related-device-attributes-ft.png | Bin 60303 -> 93697 bytes .../examples/related-entity-data-ft-2.png | Bin 76684 -> 0 bytes .../examples/related-entity-data-ft.png | Bin 59833 -> 113138 bytes .../examples/tenant-attributes-ft.png | Bin 82917 -> 87964 bytes 15 files changed, 75 insertions(+), 77 deletions(-) delete mode 100644 ui-ngx/src/assets/help/images/rulenode/examples/originator-telemetry-ft-3.png delete mode 100644 ui-ngx/src/assets/help/images/rulenode/examples/related-entity-data-ft-2.png diff --git a/ui-ngx/src/assets/help/en_US/rulenode/customer_attributes_node_fields_templatization.md b/ui-ngx/src/assets/help/en_US/rulenode/customer_attributes_node_fields_templatization.md index e01d90faf4..2092a0cdb5 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/customer_attributes_node_fields_templatization.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/customer_attributes_node_fields_templatization.md @@ -11,8 +11,8 @@ Let's assume that we have a customer-based solution where customer manage two ty Additionally, let's assume that customer configured the thresholds settings for each device type. Threshold settings stored as an attributes on a customer level: -- *temperature_min_threshold* and *temperature_max_threshold* for temperature sensor with values set to *10* and *30* accordingly. -- *humidity_min_threshold* and *humidity_max_threshold* for humidity sensor with values set to *70* and *85* accordingly. +- *temperatureMinThreshold* and *temperatureMaxThreshold* for temperature sensor with values set to *10* and *30* accordingly. +- *humidityMinThreshold* and *humidityMaxThreshold* for humidity sensor with values set to *70* and *85* accordingly. Each message received from device includes `deviceType` property in the message metadata with either `temperature` or `humidity` value according to the sensor type. @@ -73,8 +73,8 @@ Rule node configuration set to fetch data to the message metadata. In the follow "deviceType": "temperature", "deviceName": "TH-001", "ts": "1685379440000", - "min_threshold": "10", - "max_threshold": "30" + "minThreshold": "10", + "maxThreshold": "30" } } ``` @@ -92,8 +92,8 @@ Rule node configuration set to fetch data to the message metadata. In the follow "deviceType": "humidity", "deviceName": "HM-001", "ts": "1685379440000", - "min_threshold": "70", - "max_threshold": "85" + "minThreshold": "70", + "maxThreshold": "85" } } ``` diff --git a/ui-ngx/src/assets/help/en_US/rulenode/originator_fields_node_fields_templatization.md b/ui-ngx/src/assets/help/en_US/rulenode/originator_fields_node_fields_templatization.md index 42f4ea6138..5f22261b73 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/originator_fields_node_fields_templatization.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/originator_fields_node_fields_templatization.md @@ -9,10 +9,10 @@ Let's assume that we have two device types in our use case: -- `smart_door_lock` -- `motion_detector` +- `smartDoorLock` +- `motionDetector` -Let's assume that device of type `smart_door_lock` and name `SDL-001` publish next type of messages to the system: +Let's assume that device of type `smartDoorLock` and name `SDL-001` publish next type of messages to the system: ```json { @@ -21,7 +21,7 @@ Let's assume that device of type `smart_door_lock` and name `SDL-001` publish ne }, "metadata": { "deviceName": "SDL-001", - "deviceType": "smart_door_lock", + "deviceType": "smartDoorLock", "ts": "1685379440000" } } @@ -29,7 +29,7 @@ Let's assume that device of type `smart_door_lock` and name `SDL-001` publish ne
-and device of type `motion_detector` and name `MD-001` publish next type of messages to the system: +and device of type `motionDetector` and name `MD-001` publish next type of messages to the system: ```json { @@ -38,7 +38,7 @@ and device of type `motion_detector` and name `MD-001` publish next type of mess }, "metadata": { "deviceName": "MD-001", - "deviceType": "motion_detector", + "deviceType": "motionDetector", "ts": "1685379440000" } } @@ -70,11 +70,11 @@ Rule node configuration set to fetch data to the message. In the following way: { "msg": { "status": "locked", - "smart_door_lock": "Grocery warehouse door" + "smartDoorLock": "Grocery warehouse door" }, "metadata": { "deviceName": "SDL-001", - "deviceType": "smart_door_lock", + "deviceType": "smartDoorLock", "ts": "1685379440000" } } @@ -88,11 +88,11 @@ Rule node configuration set to fetch data to the message. In the following way: { "msg": { "motionDetected": "true", - "motion_detector": "Grocery Warehouse motion detector" + "motionDetector": "Grocery Warehouse motion detector" }, "metadata": { "deviceName": "MD-001", - "deviceType": "motion_detector", + "deviceType": "motionDetector", "ts": "1685379440000" } } diff --git a/ui-ngx/src/assets/help/en_US/rulenode/originator_telemetry_node_fields_templatization.md b/ui-ngx/src/assets/help/en_US/rulenode/originator_telemetry_node_fields_templatization.md index e433536726..5ee59f7161 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/originator_telemetry_node_fields_templatization.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/originator_telemetry_node_fields_templatization.md @@ -24,27 +24,28 @@ Additionally let's imagine that devices periodically publishes other telemetry m - `speed` - current speed value. - `direction` - compass direction in which the device is moving. - `acceleration` - how quickly the speed of the device is changing. -- `fuel_level` - current fuel level. -- `battery_level` - current battery level. -- `parked_location` - precise location where the device is parked. -- `parked_duration` - current park duration value. -- `parked_time` - timestamp when the device was parked. +- `fuelLevel` - current fuel level. +- `batteryLevel` - current battery level. +- `parkedLocation` - precise location where the device is parked. +- `parkedDuration` - current park duration value. +- `parkedTime` - timestamp when the device was parked. -Let's imagine that we need to make some historical analysis by fetching 3 latest telemetry readings for the keys listed below if the `event` value is set to *motion*: +Let's imagine that we need to make some historical analysis by fetching 3 latest telemetry readings in the range from 1 hour ago to 1 millisecond ago. +If the `event` value is set to *motion* we need to fetch data for keys: - `speed` - `direction` - `acceleration` -- `fuel_level` -- `battery_level` +- `fuelLevel` +- `batteryLevel` -Otherwise, if the `event` value is set to *parked* value we need to fetch 3 latest telemetry readings for the following data keys: +Otherwise, if the `event` value is set to *parked* value we need to fetch data for keys: -- `parked_location` -- `parked_duration` -- `parked_time` -- `fuel_level` -- `battery_level` +- `parkedLocation` +- `parkedDuration` +- `parkedTime` +- `fuelLevel` +- `batteryLevel` Imagine that you created a script node that depending on the `event` value adds to the message metadata appropriate keyToFetch fields. @@ -83,9 +84,9 @@ Imagine that you created a script node that depending on the `event` value adds "deviceName": "GPS-001", "deviceType": "GPS Tracker", "ts": "1685379440000", - "keyToFetch1": "parked_location", - "keyToFetch2": "parked_duration", - "keyToFetch3": "parked_time" + "keyToFetch1": "parkedLocation", + "keyToFetch2": "parkedDuration", + "keyToFetch3": "parkedTime" } } ``` @@ -96,8 +97,6 @@ In order to fetch the additional telemetry key values to make some historical an ![image](${helpBaseUrl}/help/images/rulenode/examples/originator-telemetry-ft.png) -![image](${helpBaseUrl}/help/images/rulenode/examples/originator-telemetry-ft-2.png) -
Rule node configuration is set to retrieve the telemetry from the fetch interval with configurable query parameters that you can check above. @@ -106,11 +105,11 @@ So let's imagine that 3 latest values for the keys that we are going to fetch ar - `speed` - 5.2, 15.7, 30.2 (mph). - `direction` - N(North), NE(North-East), E(East). - `acceleration` - 2.2, 2.4, 2.5 (m/s²). -- `fuel_level` - 61.5, 57.4, 55.6 (%). -- `battery_level` - 88.1, 87.8, 87.2 (%). -- `parked_location` - dr5rtwceb (geohash). Same value for 3 latest data readings. -- `parked_duration` - 6300000, 7300000, 8300000 (ms). -- `parked_time` - 1685339240000 (ms). Same value for 3 latest data readings. +- `fuelLevel` - 61.5, 57.4, 55.6 (%). +- `batteryLevel` - 88.1, 87.8, 87.2 (%). +- `parkedLocation` - dr5rtwceb (geohash). Same value for 3 latest data readings. +- `parkedDuration` - 6300000, 7300000, 8300000 (ms). +- `parkedTime` - 1685339240000 (ms). Same value for 3 latest data readings. In the following way: @@ -133,8 +132,8 @@ In the following way: "speed": "[{\"ts\":1685476840000,\"value\":5.2},{\"ts\":1685477840000,\"value\":15.7},{\"ts\":1685478840000,\"value\":30.2}]", "direction": "[{\"ts\":1685476840000,\"value\":\"N\"},{\"ts\":1685477840000,\"value\":\"NE\"},{\"ts\":1685478840000,\"value\":\"N\"}]", "acceleration": "[{\"ts\":1685476840000,\"value\":2.2},{\"ts\":1685477840000,\"value\":2.4},{\"ts\":1685478840000,\"value\":2.5}]", - "fuel_level": "[{\"ts\":1685476840000,\"value\":61.5},{\"ts\":1685477840000,\"value\":57.4},{\"ts\":1685478840000,\"value\":55.6}]", - "battery_level": "[{\"ts\":1685476840000,\"value\":88.1},{\"ts\":1685477840000,\"value\":87.8},{\"ts\":1685478840000,\"value\":87.2}]" + "fuelLevel": "[{\"ts\":1685476840000,\"value\":61.5},{\"ts\":1685477840000,\"value\":57.4},{\"ts\":1685478840000,\"value\":55.6}]", + "batteryLevel": "[{\"ts\":1685476840000,\"value\":88.1},{\"ts\":1685477840000,\"value\":87.8},{\"ts\":1685478840000,\"value\":87.2}]" } } ``` @@ -154,14 +153,14 @@ In the following way: "deviceName": "GPS-001", "deviceType": "GPS Tracker", "ts": "1685379440000", - "keyToFetch1": "parked_location", - "keyToFetch2": "parked_duration", - "keyToFetch3": "parked_time", - "parked_location": "[{\"ts\":1685376840000,\"value\":\"dr5rtwceb\"},{\"ts\":1685377840000,\"value\":\"dr5rtwceb\"},{\"ts\":1685378840000,\"value\":\"dr5rtwceb\"}]", - "parked_duration": "[{\"ts\":1685376840000,\"value\":6300000},{\"ts\":1685377840000,\"value\":7300000},{\"ts\":1685378840000,\"value\":8300000}]", - "parked_time": "[{\"ts\":1685376840000,\"value\":1685376840000},{\"ts\":1685377840000,\"value\":1685377840000},{\"ts\":1685378840000,\"value\":1685378840000}]", - "fuel_level": "[{\"ts\":1685376840000,\"value\":61.5},{\"ts\":1685377840000,\"value\":57.4},{\"ts\":1685378840000,\"value\":55.6}]", - "battery_level": "[{\"ts\":1685376840000,\"value\":88.1},{\"ts\":1685377840000,\"value\":87.8},{\"ts\":1685378840000,\"value\":87.2}]" + "keyToFetch1": "parkedLocation", + "keyToFetch2": "parkedDuration", + "keyToFetch3": "parkedTime", + "parkedLocation": "[{\"ts\":1685376840000,\"value\":\"dr5rtwceb\"},{\"ts\":1685377840000,\"value\":\"dr5rtwceb\"},{\"ts\":1685378840000,\"value\":\"dr5rtwceb\"}]", + "parkedDuration": "[{\"ts\":1685376840000,\"value\":6300000},{\"ts\":1685377840000,\"value\":7300000},{\"ts\":1685378840000,\"value\":8300000}]", + "parkedTime": "[{\"ts\":1685376840000,\"value\":1685376840000},{\"ts\":1685377840000,\"value\":1685377840000},{\"ts\":1685378840000,\"value\":1685378840000}]", + "fuelLevel": "[{\"ts\":1685376840000,\"value\":61.5},{\"ts\":1685377840000,\"value\":57.4},{\"ts\":1685378840000,\"value\":55.6}]", + "batteryLevel": "[{\"ts\":1685376840000,\"value\":88.1},{\"ts\":1685377840000,\"value\":87.8},{\"ts\":1685378840000,\"value\":87.2}]" } } ``` @@ -210,9 +209,9 @@ In the following way: "deviceName": "GPS-001", "deviceType": "GPS Tracker", "ts": "1685379440000", - "keyToFetch1": "parked_location", - "keyToFetch2": "parked_duration", - "keyToFetch3": "parked_time", + "keyToFetch1": "parkedLocation", + "keyToFetch2": "parkedDuration", + "keyToFetch3": "parkedTime", "dynamicIntervalStart": "1685375840000" } } @@ -223,7 +222,7 @@ In the following way: In order to fetch the data using dynamic interval we need enable *Use dynamic interval* option in the rule node configuration and specify the templates for the *Interval start* and *Interval end*: -![image](${helpBaseUrl}/help/images/rulenode/examples/originator-telemetry-ft-3.png) +![image](${helpBaseUrl}/help/images/rulenode/examples/originator-telemetry-ft-2.png)
@@ -250,8 +249,8 @@ In the following way: "speed": "[{\"ts\":1685476840000,\"value\":5.2},{\"ts\":1685477840000,\"value\":15.7},{\"ts\":1685478840000,\"value\":30.2}]", "direction": "[{\"ts\":1685476840000,\"value\":\"N\"},{\"ts\":1685477840000,\"value\":\"NE\"},{\"ts\":1685478840000,\"value\":\"N\"}]", "acceleration": "[{\"ts\":1685476840000,\"value\":2.2},{\"ts\":1685477840000,\"value\":2.4},{\"ts\":1685478840000,\"value\":2.5}]", - "fuel_level": "[{\"ts\":1685476840000,\"value\":61.5},{\"ts\":1685477840000,\"value\":57.4},{\"ts\":1685478840000,\"value\":55.6}]", - "battery_level": "[{\"ts\":1685476840000,\"value\":88.1},{\"ts\":1685477840000,\"value\":87.8},{\"ts\":1685478840000,\"value\":87.2}]" + "fuelLevel": "[{\"ts\":1685476840000,\"value\":61.5},{\"ts\":1685477840000,\"value\":57.4},{\"ts\":1685478840000,\"value\":55.6}]", + "batteryLevel": "[{\"ts\":1685476840000,\"value\":88.1},{\"ts\":1685477840000,\"value\":87.8},{\"ts\":1685478840000,\"value\":87.2}]" } } ``` @@ -271,15 +270,15 @@ In the following way: "deviceName": "GPS-001", "deviceType": "GPS Tracker", "ts": "1685379440000", - "keyToFetch1": "parked_location", - "keyToFetch2": "parked_duration", - "keyToFetch3": "parked_time", + "keyToFetch1": "parkedLocation", + "keyToFetch2": "parkedDuration", + "keyToFetch3": "parkedTime", "dynamicIntervalStart": "1685375840000", - "parked_location": "[{\"ts\":1685376840000,\"value\":\"dr5rtwceb\"},{\"ts\":1685377840000,\"value\":\"dr5rtwceb\"},{\"ts\":1685378840000,\"value\":\"dr5rtwceb\"}]", - "parked_duration": "[{\"ts\":1685376840000,\"value\":6300000},{\"ts\":1685377840000,\"value\":7300000},{\"ts\":1685378840000,\"value\":8300000}]", - "parked_time": "[{\"ts\":1685376840000,\"value\":1685376840000},{\"ts\":1685377840000,\"value\":1685377840000},{\"ts\":1685378840000,\"value\":1685378840000}]", - "fuel_level": "[{\"ts\":1685376840000,\"value\":61.5},{\"ts\":1685377840000,\"value\":57.4},{\"ts\":1685378840000,\"value\":55.6}]", - "battery_level": "[{\"ts\":1685376840000,\"value\":88.1},{\"ts\":1685377840000,\"value\":87.8},{\"ts\":1685378840000,\"value\":87.2}]" + "parkedLocation": "[{\"ts\":1685376840000,\"value\":\"dr5rtwceb\"},{\"ts\":1685377840000,\"value\":\"dr5rtwceb\"},{\"ts\":1685378840000,\"value\":\"dr5rtwceb\"}]", + "parkedDuration": "[{\"ts\":1685376840000,\"value\":6300000},{\"ts\":1685377840000,\"value\":7300000},{\"ts\":1685378840000,\"value\":8300000}]", + "parkedTime": "[{\"ts\":1685376840000,\"value\":1685376840000},{\"ts\":1685377840000,\"value\":1685377840000},{\"ts\":1685378840000,\"value\":1685378840000}]", + "fuelLevel": "[{\"ts\":1685376840000,\"value\":61.5},{\"ts\":1685377840000,\"value\":57.4},{\"ts\":1685378840000,\"value\":55.6}]", + "batteryLevel": "[{\"ts\":1685376840000,\"value\":88.1},{\"ts\":1685377840000,\"value\":87.8},{\"ts\":1685378840000,\"value\":87.2}]" } } ``` diff --git a/ui-ngx/src/assets/help/en_US/rulenode/related_entity_data_node_fields_templatization.md b/ui-ngx/src/assets/help/en_US/rulenode/related_entity_data_node_fields_templatization.md index 8b01a5ec2b..dad46a6495 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/related_entity_data_node_fields_templatization.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/related_entity_data_node_fields_templatization.md @@ -15,8 +15,8 @@ and is responsible for overseeing two categories of devices: Additionally, let's assume that this asset has configured thresholds set as attributes for each device type: -- *temperature_min_threshold* and *temperature_max_threshold* for temperature sensor with values set to *10* and *30* accordingly. -- *humidity_min_threshold* and *humidity_max_threshold* for humidity sensor with values set to *70* and *85* accordingly. +- *temperatureMinThreshold* and *temperatureMaxThreshold* for temperature sensor with values set to *10* and *30* accordingly. +- *humidityMinThreshold* and *humidityMaxThreshold* for humidity sensor with values set to *70* and *85* accordingly. Each message received from device includes `deviceType` property in the message metadata with either `temperature` or `humidity` value according to the sensor type. @@ -24,7 +24,6 @@ with either `temperature` or `humidity` value according to the sensor type. In order to fetch the threshold value for the further message processing you can define next node configuration: ![image](${helpBaseUrl}/help/images/rulenode/examples/related-entity-data-ft.png) -![image](${helpBaseUrl}/help/images/rulenode/examples/related-entity-data-ft-2.png) Imagine that you receive message defined below from the `temperature` sensor and forwarded it to the **related entity data** node with configuration added above. @@ -78,8 +77,8 @@ Rule node configuration set to fetch data to the message metadata. In the follow "deviceType": "temperature", "deviceName": "TH-001", "ts": "1685379440000", - "min_threshold": "10", - "max_threshold": "30" + "minThreshold": "10", + "maxThreshold": "30" } } ``` @@ -97,8 +96,8 @@ Rule node configuration set to fetch data to the message metadata. In the follow "deviceType": "humidity", "deviceName": "HM-001", "ts": "1685379440000", - "min_threshold": "70", - "max_threshold": "85" + "minThreshold": "70", + "maxThreshold": "85" } } ``` diff --git a/ui-ngx/src/assets/help/en_US/rulenode/tenant_attributes_node_fields_templatization.md b/ui-ngx/src/assets/help/en_US/rulenode/tenant_attributes_node_fields_templatization.md index a478bd94f0..71eb28d086 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/tenant_attributes_node_fields_templatization.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/tenant_attributes_node_fields_templatization.md @@ -11,8 +11,8 @@ Let's assume that tenant manage two type of devices: `temperature` and `humidity Additionally, let's assume that tenant configured the thresholds settings for each device type. Threshold settings stored as an attributes on a tenant level: -- *temperature_min_threshold* and *temperature_max_threshold* for temperature sensor with values set to *10* and *30* accordingly. -- *humidity_min_threshold* and *humidity_max_threshold* for humidity sensor with values set to *70* and *85* accordingly. +- *temperatureMinThreshold* and *temperatureMaxThreshold* for temperature sensor with values set to *10* and *30* accordingly. +- *humidityMinThreshold* and *humidityMaxThreshold* for humidity sensor with values set to *70* and *85* accordingly. Each message received from device includes `deviceType` property in the message metadata with either `temperature` or `humidity` value according to the sensor type. @@ -73,8 +73,8 @@ Rule node configuration set to fetch data to the message metadata. In the follow "deviceType": "temperature", "deviceName": "TH-001", "ts": "1685379440000", - "min_threshold": "10", - "max_threshold": "30" + "minThreshold": "10", + "maxThreshold": "30" } } ``` @@ -92,8 +92,8 @@ Rule node configuration set to fetch data to the message metadata. In the follow "deviceType": "humidity", "deviceName": "HM-001", "ts": "1685379440000", - "min_threshold": "70", - "max_threshold": "85" + "minThreshold": "70", + "maxThreshold": "85" } } ``` diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/customer-attributes-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/customer-attributes-ft.png index ca208c27ed3aa8be923bd1e6dc4fda05c0f56a70..43711a83701427ebaa0a02b514b922f01061b9a8 100644 GIT binary patch literal 88911 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 z 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�!l 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 literal 85413 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
MpPaR?0tSYo68B%qqVF>K)v?j&26nNK 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⋘l1 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%0DXS-Kh`AX%tG(A1~Ey`y2%PyN# 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 z

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 E2c!m7Hvj+t literal 73529 zcmaI71z1$w+CI(<0}ddPf^?^(3P^_{-Q6Kbhja-;r!+&C(%m67bSX%8N=SFtZ+p&n z-t)fS_5J@``ZZS&j$*IFOBiUE{O=zkm%-CSi#b~+(;(KDz|RRh zxykgy{bs@Q@?XC2MO(Q4q^h-V`* zYMxU&7$p&fJ7eUJ$a^eeo@x;>7&g;y{_k_b!~3U< zij=?7>y%ZZ8f#r5>TJr%_l;~8%9{LlkmWLk7V^+5bai#mK{VlZE7%YDv~ z5vaoU|3BmY>p3lXwJ1$7?zsfpsF2`NK97ZcJreFfSgm-2?awBZZ(lKdC|}wQL!W6p z3b^2qk1pvOcn$i+#asS=pZE4Ab*%a`I4X1xQ|*@LaFO)`V6Ne}o5Pu&oSaEhJXQX7 z<&nh{uRZsWONuWzUVLv3#*r4@j{e_E{?G3T4@RaY!Ha!k)5MN6d#O`LL$!S=GHs@x z6vPmV@@=f)u$J!nmWv<0TFAfp&dLxx4y7Y}w~8cm;#7ud_*yXuG?0j?^^5-u_wRF_ zPm0DO>-J}XU_qs2Qzg5NcL5jH-RB;-xP0#rlg2u2kq=~{IQAco?)T<+_MebEumJPp z6+yVE(HO}0=v3>+{hyMEs6;1yUD0Xv+V1YQv|ci$8wNmi^r*!8B2NrExTAH*Xg9RUa7BXo3 zkak?4pwuG}^j!wGP0B=x=yZBL3%f9Ctc-$x-&XNMU%rCDt{}}40|=M$Z^xk#xZVFz z!l~4InLIZt+UcqKZQG3ufeJCr=jwqlE}TOqd-LS#9eNZP78Y&lKW{dJieQhkCn@^* zcy4y*E~Pv>q=i^F?k=Bwz3}g^JgHCL!Yilx+p~b@9-@G?RC*JwD}|odn-3y)v*<<3 ziXr%MU_uH@H%XI72G0Z*{UDOC{~l>{NW~&wy+%sVK{Xa^sPWhp3}E|_uDy%&J*;w? z|1~-tm^G~H1)X%I^CS!xqLMFPo5Iz1oK+#kPkyO9!6zC)F0TuhbQ9; zQF_0hu+#l7pdoYadmG_6~XsnD_=|u^2)bl2wln783f< z4EmeQkkA@rk;FuFAWrYGk@Z(mzO#a7pY~~=XKi_Aew%0F{-?xfm#ZPf>*2;+R?+TR z93F;MP|Yx;W(#r}V9M3VJ(E&@Qx8c588GD%Q_N8@gi~Kq9n{>F($NZbPek?w+rGD= z0`ng;KGXthL*IsAi#8%_Ww2R?5yAeb6D9P+uIEOz;D?>R?;G%)4bMD@rz$Znur$KJ();6%_L%ex>-rXdCGPSJ5G%7wymmj?_{^j^J<6P=K=kC5_pRGg7Hc*L zODX7bfgwPoO+6vU`u_BI^^Bis(mJP8+HNL+8r&% z&GNkNZ@X7MEQ|zo@?d5Wjx(jo+-tN%m(05>2Mx^^Fs=abR5Zcid1dpx-T`_#Isr>pQnbK*U`j#!tXCLdWRSbN^K5Wt2GYCW+JUx+~(-y}s zz-5)_|C(P;8nh9~P1<5{ckE898e&-WFs{byxnA})@kaVi5~oA*Y;|V51#T-yKdj%( zxiHmq(Y!O?up&&`UrXkyT_&auWN?jLtAYPYHRy;jN{Jjl(tnO=9{DWnd=u02es`{tb^BnN4eTGT-ptZ&Th;DIDhcs&}+ z#}!D~zp+p(iY*j-O!YggZy=9-YVjOy8d{O5wQfDF+U$DD>v$De4h20RW;IabdHxlA z45$?;b*_VKACi~SmBM~xQP+EzJU?8VUK@po| zS9bNoWGxgo5@h{}Oog{6mw{c81WH2Q_tfGkj}z+;go$kzc>+a#W{Iv1688G3{w6kY zV_eW5Nj`G$WY9JLnNN`K`ylw?cBkHs?R394cOM@N#jkz}*%&Jm73!WfMf}?fc#DEB zZ<-xUo`;fjI(pwk(j@jpb`sK>1?8-cd};PL*2kOb%Wf+VyZVsx4m|jA{Rtka%X3!- zWtPMI^CEVsU*h#lsNcnrAaBOJ9oM^y>-TqqChE37U={271CIX*28b1PgTmP$A7nb0 z^8}Yx(s1jQWvE+CL4j_7hny~}m23L(v502#czLu$5&jSh=a&GDrlv8Cy*SjT4mzK4 zB=LE^ITdKgR^^1T8?<_>>_5$CTZj=Rj#svs3&%-%nN^u1LoCrv{uW9i9kwn>muM>( z|E|SM`hwmxS9^rTVPjjcaOr(YVR<2LFC4``rC{l~%QN=+eL*Kj|qvfXJjSrWB@%Ky5)RweKj5-72TV8%Ex_IC*$;R)` zP(C)3XUl$r8uz@O;`!J{=!vjw>Nna561gj}50c~>)Dln{tjyL}G70v92(_EFA9Gkm zvlUM!a?K-E^`~n{S|wd5?rt~RB)B7PE6`(C@)Tg&rcET7%MO&{w_eTm5`S2e>a zmPuS7xzVFdR<}y!x~_zA9m6EL)67ot#M@C-@MP0`)~D=MQIf(7+9;Y#A)gpzAA`6U z$NGU^W)F>CrKA(mf}0T&H|ymnbFvEs8f^7W1v;`BtzIF>4^`dRx| zB~+FeHp>=TfJ^RQXXT0aKdC!_mo zd>u#LGmzsHCA*m6e8WfPcOrx*Cy;1X$tGx{3Ur(?S&wyK$>)|9g#=SYNJaCORLD~$ zFh3fx`88% z`rMBc7f?_QZ>xk}e+GTFB}w==r7v=EW@d}W^V<6)=BSKW`Kh8nq!LC^By1C{?o}b^}e{~ z@L`AJQ8J5BGq{J4b2*XTcmt`xCq3<1&T!sQGge5+=R{VjX#V#vh~{eZLYsolR>sWG zhy;?}h#~z#vKndWWvBIy=)-;SmV>UW$TgXoXJ1HJ&P*;<6Nq!A0VErDgHs1|9`T2k zvSmx2EVU0w%oM_(;13hb)H7rBvE!k}g^ie^$7}04L|k^oY0dUBxILltFK_N`wart7 zUqT%2GG4A-4N^?GMJOww2Ka^c!I-HkUxCBccYMCHQF1MIkEFD5GFWjUTpfgV>IU& zi$dM&oor^d-BP@k$3y7gcFQv*n!b*9xd}7uFStI~3PrOA#as#YKuGFnkQd2|oFe%xr_%H$CVbSQ%a|#F zC;hRtp4MG9>x@H9{(|7HeA%-_F>!(NIY;fFAB(h^ZC(lAOdX^Kw^1feQZRhm_ll%L zbuHG;ny^NVx^QdV{4hEzT-4}9OBjn|1t?l=|7e$VkQltziB{O&Rrx_Ik8)*|_Nc^dvuZPqpA89_zJHM9O7J)nzf-9nRWVbyE`Ls`}n1tj59ik z*|!c`lgL{yER*LwFLht!OEJFZpHjszc6^Q{>xoj86OBR=)z`iAFzqEIaZ>`o21ix& zkcuRomvyyWq2y8(A-fz7h4al9n$cwDl5@(hlNU2lR{ zWKx!b0anYFHo3@b|f-`^M0^$Z6L2m3a5X>L?>q{ zkb(+)x>Em?VPxZZckVCn>3+5hd)jq7<#AG-e1?E0YxhZx(j-a5W=Nxs$>KNvZKViw z(A|8U=6fL#r))~~_cN34rD@NtwdKRsW$7-+1rv{L?v^P}d!wTbY*Hs>BB} zi0&4=@G*QZ8WBpsCv+7YV)G|!g!xcbSe`z}?r|JU?c}37{ zPbRX(>78pm?Wn!{q0-Tkq1Kbz@?Jf;dIPqlFIR-Gh;ffaAuJQ~fkuGU@YG~f49VN< z#_Wzt(;7jFrGc#XT~6s;AmUp~e(q*NLPo|MS(#`meT@eHZ_T71y0ydO-dkQ*(=<}@@gh#4og(-}g)-hS`Jnf1mJKs~65s z9-Uq9Pt!$v)v&7dEsXax+tBn+ae65Z-A$fRvw_b%_xPMdCGM3xU!6f{#ZlH9WOL4{7G=I9CF2Ni!&0`E^p{P=aD;}Tk>Ci!H=n&e(BO=JCj}INHDsm|i2Rr2u zM~uD?6X?<>MJVx}(%JN#>t}Nm7%F7$pRUf|6ppyZZs~gj&!)^pn^thl)2l~X7na%l z^n|BU9U! zKL50+L_1h=O_;FycT5LUrGNSkGa3EsSFWU6F9{|VKPPfgDQ4S$*cvNI(=J&r;ZeLw z+4-`WPa}qy_o3K}*ws}*HNE7l3 zXwMYyxPOH;Znv6&3g($S^yHG~V@MUQc{uD!3%oIjbQ|HbUj;288q;3wj$r8>T8dRi z-b{X`$^;kxcB`&@r(b(Q+vswWeXV6i_`=owC!rR)@3_=z0h<38WEW?>HfqTC?l4!p ztnr7QKL1|!67`R7p>DmyUcC+GCo#A*4sOAhYOEP*9E)D?nVU?5aq zQ+{GlQOv90n3yWu!5e0FICLK7~!x3lWgpWO^2f_by*}=MOA~V3$LLSSjX4;;n5g^uDN4kzT4SRBE&Ua0sS2pSgRAAi;ZYWz~&$XUCs!6Dj-1F#|Ce(5iJTf zG^Tbf*Qw>c-G7x)6*7$r?h|dbGj*v%{ z2tXjX)pArbYQRgUAILM1D+kwxDerXDRO^3e`DArP5Vuo#n_`$K3e7U^3mi?v2z5>^ zDp6$-HYM%M>^wP)CzxaiK=PWdm)|NNxP`Nc)b)&}h>Ng$lxjh+OTJm$Mu`-u`xEr} zs%VfBfFsYx*rC3tK%t+iExxv%dZAn~qF9gad-iL#C_*2Dn=HoYA;ZCX?Ip3WI(~mT zXCeM@!aLKqVwDLvKO{X%-uwX@+i*cN?Hx1Qry4$~SVMbd#?{tO+wfVeiJnCW&B?HC z$NfU5%2FVxgLC!azg$ig%aZX|RxUPiX&U}q(i zaV?ldDSq|~qhPz#GStr9s@iR*|RvZvq;IE{>fXF6R^dYS0!$EH&? zL)%I*ma1kc?FX}WU8B?$@3qYme0y$1I3a}W6|fZz9j}EIw#NRCs44m0o;jB^+u%O|a(DCKtM5{|c`oPj7IOAU?atp~(`a zn5`+HvKYx43*Me8t?cpiU_cjbe>xX+LHq2Z!*SC^rtA^9%?^P|W+tYm!XQeuh#MI@ zSR*@HZJTGCSw`Yx2U^XD(YQsf{**=h>Ypf zhzu_K2mGyt=4KOFa*bNM15!{9tFt`2c|M~=h4eH6<#mO#1bI=T_p}ztH6I&shfRu-*=G~X-k14HgLz-BXf1JRa9ushj_9&f zoULnhnTTY<53lmE<0I~v8Y$!A<*~@G@PRY_DB4fQZZDeOaGlMJCO7=d`znSQ@qYIi zU%pO$JL_85WRl()6$)W^Avo=UwS>&~so=A?&?d_hQo;cfX}B2OjJ-pz&HX&GmI*oaow^LIj2sD%T~5`=aHtXK?b=4Fp_ zX>N~hCb=0eNG$L%+Z?^CY9X7(z5o+>+++cBsTHAGxb&c3w~+ElG6pEePWN>~s5X8w zp&ns*BQ=C0t5~A`*g@Xc-P_SqOvIGynrDLH`s-Ulzt>#fwnPJ!;-hInS>vOE>+-1+?Z4+{v@b_2C{W8vxFd^MRC8}j};gN&dhdiSRvTiDCL$e)0mYnpb;H3IXQXSOK z?GiN~rkL^;uB^9k2jhiz+^<@HW-7^08HU$hmtB_zjI*YXjl-{QdwSm1R}M}*>lk>| zGHf?MjK=Bo&@U58#MO+uJl#-mvFSuNtNHKt(_3^?1tuE)$%;_0Z4;x!y&!BR?%vs|(zZp~GFD+{{P|Y4wLP4WdGyzzWu!w-@0Tun1vqm87{KotK zIvwARdvqh_XG=@UFENC>Y?Pk&9mL33(lO&G8lpH1b{71LQFPDt!2@s87J z7B=Rc9|<-Jyza!>!vDxEb}uV65n42C(4xYL)|c+Rd9N~7{o13dVnm3a2J(|B#CMXp z;boAvp)IeQemW_}6#IA1wGfF)*Q$z`5>ad;$s?^6U_m5;u>v0F+HhO`Jb6U7*A$a3 z7mKF&y|u2oLyk-iK`gn-WPhsnjg?*7%2OdXgYAbaJ<_c)!C(( zh6990JO)cwD^+a(hbJH)La zrvd@!WGui21*3@>;&tsiBZT%^8p-&(K)!Gp#Yklk{!oVU_fJD)Hi>6{b-S7wV1bOf zxux!2Zmx9P8uToSTNX4yB`vrW^bqV<*89Xc-ofGsI5x~wq!(QgYM*i^4M8`NV z>Rlm^{$W9XgIz$aUn|P$fFGlQ9F?*Hk@R(dLeIbab``l=fp!_{dwv#H40DXXpb##M zU~l(BRciZXUqeq`4Jnk;`nNp+pI&eza7g%?Bpph1UbJecF%!>w>$k$5SL$r@4eU*k zda--K>~0@T&u8?n4koQk(6jvle+0sWjGifc;Io+?r8XpDEYS;Ogxp>P7#;}XAs%Jf zN5(5RN~%jG($)n)$yK{itY>}XH%bJTw`z>4{?;9Sc#F`5n#;iCsIvV1k6@DlNQ(vz z+ikaZ_h^tC>3{TVL7^gN5$)@HbM*t%hH_9Cif)i<1k6=T#O%ozY^dZ|@bKTSUp7E{ z4fJ&kD_kCpKD>FX2)&#tM0o!x@Bec^Xu%s|2z)GT#^|lbpyGe+JF5ag-v2q4COSxl z(-0T@zBf{B>x~ky)E)ckr9aihU&o<842LSq_|f-37y*ROaQfCq8}hpLFB$(!Ef4U1 zicxx99_ASuvD_+sf53Y6;d|1-MkS~KXrW#_N)n{~M~~PF(u@bT$9r-26?+*%{r7+Q z8U(|}fM(SOWe%arHWi($FqFtKHg zbX+gCzja@IVInXwO3H{AnK6I69R^{6Hn2dP5FEe<=IZS~o(_5t1-4C-U-A2gii+B5 z2q2E$tm?%7%Hoeus1Uq=$>v{QK+!NGs^ygxBR&bFH0yM><}Hstq>z{>*}n-<1biPZ z(%(g~25d94RdlWuc1Bl)6}BFDpk2eWC8VJI09YgC&qraL?+}})p{##b zw`f=s8c^oU;u=m+FQ;SwUTkSt_t!RfhXPj_5M!Qq zD}mu+A{5LY`lzw70}7f_jYOUg*F>AE?g_WI`R#{ESqu~fN ztPQ01*4y^q{ADn=GB7ciO1mPh_pDJ6tHl7c-`*ayzNH!IZ@5~GUI$_gPD_NFb@ zZ;d74u`9Ug4JT1pWss!I77KJZ4Ao5kkH8UHV0`dU>@R0;Utog%Uy-Od9DAJTAjSY# z%4IbH&l2_bzy)&@&o_S3i6j^N5@`cqevKymDRO=&81!cHnehDKjDg-LiuIAsVBF^} z*8LfR!Mh995*dP?%>A)+aV0ZV#oS8!4<}K;b{QK}$vm?nxe5}meQy5WM$^;_b#UYbev$R^Wy)cme;-ub|!SrKj0mn7w~JI$8LU6MHK zye)mWOl30CfnqsgP~>ERMj_24XAH#$(RN z`MyWF#rt@z@-YRUs&cM8>qOC1G(c+MzkKz#NumRj)cAcgn<)n<0#c@1JPeas8HU$^#R&LvJ9k$Ti z=(yGyj5XRIrE+__}R<(5K0KSkXu$4@<42N__*`+g{e%U zzny1F*vV2vm82n5!gE}w(i$dQN^V_E#xb;kx z*536SBPx_#czW0i??2bGDrjK_)0YnyXMA zfXG+KG#Tr`bokZdj7G*65%8Eu`AVlWI-NrEj+INu{QLZmzFDNiFh@3gb} zU!*bnm%!jW$fl01(txIGd_4K^mkR*^3|An@veF)9$^6$d=rZgivNFGu9f1RjEd zS`MckXvnd}^FdR7u#V-#6lU*ZBOoZORaB__HPpQ?3@BGHd~Q8&FDujdUFF#fT3Iy8 z_0`yV7$x~)Us)(SV_T%WvQXU+4FREpA2{%C%_soJx7koR_17TYFc?snf?(+n{*SN* zRyu>%XKSq%&xNF7X=7<5p7bX?PpraMe0=HKevi^5LUoAogqb4rFTdjoeTDf zzGeZR-W_iamzN*|e(ePXO$ ze^kulu^a=y)92sx4*kV0yQBawqJhZpDn8w~Xf@bp%V4Qxi=jwm3bk}{B4eY(&`78g zpy;5$!+?nv)yM1$$fvzl&Xs;@G4dtQ2*(#?{pw`Xbg|i;O)%f!+vWa36Bwt?aZ_F@ zn$p)`J7w;Av{Z-3v@{Ihu}GO1Kglx3Pz9n1-OnV>_p$&z0_;cy%j8^Xay{6u8@hV? z24IJYCfLOOJ3SIX&;mgU;jsmX_{IC4$4#7|^WSvxX_^CY)?xx{%_Ls!FK0sj=ZG6N}LqKiC~kC^zhL zb8f?=oD+fz1{Aq^Fi;G^MlG!6D~9Md;`P~2JKdjo!)DOP(ss8f!soQRYa-Je@z?gZ z;U3CE5jw`lYyA$lmmli|^z&qsbDXwD2R`)zJ-jEBf)+WFG0mslDcB;pa8@1Z3d44j z?@657#3BCVf*yU9?|W%2#|uWw^!V4s0{l?c`{Nksw5m+1EXL^3aHs>Ee*Y9LQY+3| zJeVraoNsnl$y3NI^L|7!4w!e@T7R5G3+iBhS18^(;ANE?9ZVtn?+|bbmpo zBLMB|;=}D#_38G642tttJ%PCbrLO{wsM!yf7pvVE69-gpf*7ZsKWH;T(w^}a+`h<_ zmYn7=%5iQw#}(H1l8WZY#$zRFGr6kD9nE)D;PpBU*h1jYXhe~7iNV=*=shneUMVlE z^Uc-U#kttrGYrDZWAT|(_$J89uz(=uc1p24eio^JdVl9xs8|+JV|^xEs99L`HPKVY zXJM9WbT5i+adK<4Hg&xCA@zH*pbVT{kNWvk$qikJEQPRld`a?4NuWQMt8PL4CUP7@T7`FiG*?;8HnlfYuKIro*_h_ZaT02SG6eH@cY zzRajezwUO*{bTFt2JzMIsPfs4JC4?!sj`@+i+$?LgcNa-6;v(o$Ud*EdPo0jhWe4|Y@ z+NBhQfS0V-vEzaCgL~-%jiC$_K@98Or|`L@8qO4U9rQQCiR$Jhs2p;mF;v1ThM88< zLEc3?%O+^wnJiT)RH(FPQ!9$sPRitSmIid3nuNy|zk$_Al-FkVm8q6U9!&@c8uBBR z2SYh~77rZ!ge>-(^A2-%43C|@R%(lx+RM%#RROiO+F`MW|0`2IA*zo&4?1U(^Rt~Bn(y}RXmXL!ClvrQC? zNkVU5yFFK5j{EqlM3l?m<$c6EKuxl|A2NM%+$uX>c&(W;DSgR#!+JZ@lB)a7O%z_H zx&G7HTM3HKuB{n{&&sU#aLLZrMF#kF`hpW?HJ@GThUyaSMlp~38NDZ@d_^yqvX%$4 z+9V8^46^-9zQ@m`*T(@NdLR&kP}W91g+qR^)%`hHlM`19{FRh)C>~E4sX&Fn`Thb8 zHfo#Lkrb7o4Jjd861zX@dE(upsHC3rs}nP2N(1r)UgYwf??jrHQ^h(ud2*Rdybc?& zKKl!CQg{pvrbf1M(A#oTM_!N95FjtmjHOdx!=ey~{*$NmVN;nLRXr{8@y>Q*fV_Hn z>Ub445i1~$uAq1RTx=QOCLQnJc}~>N0m<)AD*v2`hgr#@@xlo!pn6W2cR#-Vy}8I9 zL3gw4`KLO2&GH5GpnxIAc-Xj0YNF2n-46qBzX@|>cfk_d(C!6NI&Up;DO z+^=kARf%7jXDv=mnNz{ce18^dR(|n#IB0u-11_qF(jtWALGzDK;M(O=FI85`lTW4M zbzFBTKtcDVz_1%+=SUA7AX3SvK{m7jZ2^@1$!ItY%aA-!j3JauZfljz=T7Y ziQ5y*gKJD<<6>B*o!4ihZ3YyzH~jB6to!46!#&819oIsPq_J1C$Xy9!sO(RAFqt&! z;%`SvgU1VXhMkH@rpjfm9C8z)%XG?H`J0xVbQaNky+7UbReqIN>+FqEZhnilHQisG zJE$jyNdKs@Ih2u*!c{bo)2~9Ou;?Z4xDrUaOa=n@er6bcH&7PvA9~()_m{C`ykMY1 zVP8B`Yn509HKdBtb8Wc&?RRi>ygpc*?r6mc7W6z<^*I5I$4moi_))LQM9N~Zxv}sL zC^Dqu=;f@@L22J3$h`CnlPjFK{7gaWXi#tk|EKGk{FQ)iBsfwC(rvTXm4m682mtp( ztYmv4i0DlEqVu>O_YnCQAo@}e$5@%9=%7auTjiBsO$XK<#+li8mh^y#9VeT?p>Mm; zN_Vu{6UV*BFS*hozP6q4T)EJgSHX2>tUl9XiX2vicX)`GkSX&R)e7L@L#>36H0aJ`l`(oo@Q>8-ZO}Y;j8Vf4aUjn zH(w45=m4cC(JPYzhq;Q4j^m5MxEIEk9K1gFX~c2H-C;7p^67F~gosL~!qw4YSA&@< z_c#yK2KQICqpC$y1s2Y-fFZ))=MsjcH{DY4yILn=5Dv-w{%MqRZ`UT1TxAL*$Qcf6 zeMV@6Y|W|#no6@ZHV6G?r>lV&mX9CqZ{h*wxzbso)(OGlkeen)5GE1J&H0`h{a%Sy zHQIhA<45B$=enM;DkCf1z0WbW$QWnh7=(=B=t2^oQ@J&UcNbn8gOZ<1s9&{+(pZdC zB^1q7OSp0o9S<`}DR57tm(%V~;E$3`hTDi)R8p_pm|t{A^P0rQWQ{5 zHWOC6WuPT|5|N}a3YkLEmBw^AgA@yprOutH(m1=N)}n&}azRg^p4Y$2Xu$(dZsb3| z=yDy57WFroDx+x14Mcycv^2b!YwdJ6j8%N21Z1$jz(8oDFI&B?Mp;`VdMJ0J`JY2b zoiRK1UlX(ffZ0gQb;SpB0pCj>To?LOsBhACF zNf^E%I5f<@900}K)SZJ}vVPlO*b;yn4!?$?p!j+7)mYJJ_L=oXE8#LoeYvOXplJ52 zFSB&Tg8O~mnHuc*ypu4@qAP5e*F(W^+uln}=sgIXZ>ON`B7GZ9pvLM};dnUpTM3uR z!6aGGwbfDw!}s^dd&#j6KPFb~26E7jx6iC*YD`lhfR1m+X|l0>WWW3=)_A{I5d*;@ zkZoktZShd!wx0bGFSP&gRd^)F;)LLMd;NK>Cwlcvnmfig;p{Jos2q#9cR(#7Z!z8w z8Ww{fj9{gzuw5W#Qq0PVFIH4i&XX+MeghTozLg9G?~Z?AZP)?8#q~tZl90C%*rLST zwqNf1+el=Xc=NxcKGfpOBKGK9T<@sj|pTG4ow z$q_YBbhL)WR5+z0xQ3va|G~OQ~($sB5Hwe1E#s>Z5Ul+wS)$QR`)1e~afs-|QKQ z+5jIu%Y4b_d>kr6yNI7XRk<=bnGzHhOWAQiwk^hOH%mL1$gXyOqiHfnETKD>qlA2B zD)8}Gbt3&sAcnMm(C2Xhe)rXYYk}-|7Jbzp5-j6@xu5qC7~`w=*T*)8Ul=Y^_QM5(Cx(j%z(Cpq&uF=ktSJ~VIr`@;}ONa z_~m1x>{1NfkJxxdgIs+$;V_pIUuUF`AjU~ufBQC%GjB~hoO#^_dn1(!dmtH1n8WT$ zVuOlImh}up?hH3aiXqUhflDiz)Jr6(a;YUEu5t9r{lm^8pXyg{5C;gi(ga~8u+F(8 zfgcTL@Y2*;s>cO}!=-1Pwq(T&CwCiT>8!XX?jy9EZWHI<#-WMJ?-_3FrDz-+TmvymG4FH9eX?t_y3yl8vxio`sYlz8-VF?@1{%JJTD?y zbeq4Q@^+jUE?VW)={8rqj2a$mMGj6dLPuFaW&ZXQ z9Oe~;50e3~n4>zb%%8%V(v)FNg?iQB1U%1WxosCMtGqFZe;Ra88q#!Dy{3VrH8S*& zt~z%QaOH_?aTRMwm1hXXuS4LfaDzlxi=k0NP7-^h9+hu|=yZY$z2>z3wPM4Mta5Dj zLw5-g7MIrAVWCMZP5fW?nl0}ARGS~JFfD>Wg3%&>5ogDb)>r4WUTagbC z%Fb%D_aPQ=t9TnluEz;G9N`52#sY^Ql@Pr!QOp^sQ;z#FjlE8(KD z-`iFz)XXkLXoBpa`*XXcb#iCjBcA-B78$n@{l<7n^-btaeyWMVyRGnID zXmlrGyHUbxDKV^Fxj}pi0F%jlrd6bT_9Em$9tA?D%p#ix!rF`unve?Qr3Nj>{&fB* zwc4E!Y?#&0FLV!kxPVl^nj!71{mnp3XmHhSwqI0%akWM}m<;arQ^UMF(@i?BYb^;$ zFoXmM--YL=K+6mK6EnwmP)(~g zrC)g&^IpXF`UYsPS~LSl@O6`yUt|vko$bVTZ%>D|30}EvU+C0ZQYmBzaI+%Lc9JqL z_7`4ubD3*A89b^<^ZBC^oE^`MHwpQ#=w#sPlca;jGEma#HU-wpsj@jn0LG1*ss6z1 z`}sx;zXLaTn4rgKaFPsnXK9zHE&$e2+3nY0UTF-xu=ArDb!+%l*V?vPvB~Dp-T>}I zm73N1wf~nu*t#Iqkm1vIKiuxV>DglBaQ(vA?)ZwSGDq_{?Fb~7CiIQruezg#HgDQ5 z4IjH42xiTrDwd#uXnxsP35h}x9j5npu#d>~g=1zZd0hcVzf8_ch?u{om;#pl+Hp8? zZ;tt5_-XM}%D2PcD{m51#q3Bm@BB8x+aMs%tv5#(WZ^QqY)#7cRjdT_ed@ntuN6HX zg(YXQMBt}Mrq7gUy;NXhpQe11M{515T{(e=IQ%H(p7MK%{4zZ z#$m#9jUqnH)6Q8A=WSJmtv5K)5$DWmMLADizqzTkoH+J-a^a{7HFU(-605hF%bWE# zY(FtCMxCd`nSyl-&ZlE%!j@{WVQw%@1k=c2Bqvyg*Pljq4;%+5|l*~-b zefh)E%6@Z%-x_G05`5&CT8XMEU1g(!1%Av$Umqt#BPjZ~+Ldr~@t|ZYv;lJNi-0_= z+sxH5p9r`-sbu7?7r2CDo6j^CD(}bT$-Z2v1X$s55eu>qP5>HHW_7WeDxy*=Qg@bw ziaawNh*s~WK-ly*j~8fbY0*{49He8zGWq7MSiCQhwO9=csZBhkGBk;>kE*p&AN0F&Ob})k61K1J6jRlS2bdbWibm}R zBX%(Bg(|Ja#?$?s?CXURDVkcH@W+D1>SeE3OO7%CzNwdWd!uuz%YdLfp_P_DOE2i8 zU-h@af4BgI_gD6MV{jfFF~iw$rh(F(wI#EOO~m4K2j+-AnKddR*W%t!JXWX^%Rmz! z5Mr73r<>E*8OIH&0af8!W22SMO^3timAq-pe+B%eH_-1Xyn2zO{9C5qZgQ|W+RXfy zwhJ%Wth(ndElw~p>@Kaq=TGoES8?|li#0suns)m9e<_x;XjK&iHqtx_GgA62aB)wi zkCOUmc7kZW;%AVRnlD(m8BcRw0YKZ)@&K#4_eb`btg#q#w|v@qGHWnjAdaZg*~bL~ z@8+Mh!87JVPr+T5kjetZ5%Xj{&4Mjs`vAN48vPW(oJgfj1lXjGj^4@->IZlBaL&9D&w!zylC zKh1H+*>k?AJKr{}C-&Wc-zygl)VHbE0AS-*-`9=m8`)c7V(!%JgF^MQNc<&eOo&`q z_vE|G?(0f9DT=g9$4;4B5J*Q1Nw0TF@z!64#HC|}=0Mh$|HU2(it06G zWVR>_sp{Z@Ufq3MCImaK#6s#x8wj?L+tQ4Bt(qBtetXwrK-&$=g04s(DJO4E1QVg> zIhNX276|(6m*gY6FC#}8>L%SgZ(u+Orph%W?umKyue_UNpnrNphCTYV9_h4FDXM}k zLZ{LgAQMP3hi%D#U74^~-$$%sUv~j8m<@w~IcJnwo6YY#7Jl_v@M3{gw9C_Wd2Sbe zB}BgL7B2l1rO7UgKcG>8hhX~q*paRXuWM;nIq{ff| zjRMAnZx7HCXLaZ^vadj+SNa}|qNdo)R-ukCz`H+Toa|AW5>FWv^mHk1fVJFUCC|?u zHkK;2grV02H6^(-E0_f$`595gPL?d0uSUQ=UWQu@Vt~D4j?hJSEJpLV1mj#93$;tX z85aj45Tb8#bg$5h$i1#`=CLpm>&BlE>3BMG5H4>7J5Upk}E+5!`qEIW+-AhOl9lQwR|%Ty?*TdjPy& zPlGOV0>G8=3cM^+k@%$Wz$_iFN5-NDva^a3`xn*Qt2a-|#0KH4Doheam@u6utq+=B zkwD)H&)O!P2Fb^S<@bubpW&$4aK_+eTaRRnaks259QvVah}Na-rRe|*8Xldp_wMEU zsImL#r;iMt#q~tRVN<>7o4*Plf3&10hQtN}T9NT@Lvf3(sd(%b6}`uQBm1Srlwn~M zgsl%2sfN_|-q37MVh{_rH!P`rYx}@yEFTckdnlKgK)8i|6dK z_u6aEHP@Wa^US${VT_o%o@KwYUizd`?R(g8&uyL9wyNSKW5B_-U*rel`2bul88V~E zf=KAqYeM=`iSz(A44-FEj3M9x+O6@n<{Lpo+-hXOGuB>Nf-sd^Y>uh8FL?m(qxXF- zJ@FB?s&h@~yf|U|b0vQ*J;bL`K&-!=v{8W7;rg%2?N?D!65vobcy>Q9fqz%59_5%n z^}?V(p&mEcELSelsu?ePDNMkq_MXvK1*XN8WCn-`CdU`bCA#@o{hZRcTDqn|{etN9 zWiB&ESakj`00{&9R23a4NXCqRs%+2 zLU*!I#)h!2dxQNtWP|z|BS}=jVna46=r6{J8^sKlaXO}0zP#m z=+)i-a(mqh<0>hevZG}}p%BW@>}qHar6_F=<`1=xrrbBXry8CPlEJ)U03Z-08TV~c zV6Xr9p>O_oCY6|R^kTT-c&*{(?Q{1TQqPO2)DDk_r5P`-Zs3&UK_QyJTjV>I&PW0 z!~dl29lUO>qY0(vD*OzZ$>#kTaBuSTl6Yl5r-?}zkF5@wdQIwCbNhVcp!=Iz=yl)e zppfaLqpzYR?R`!^8?EMf^p?zLNE3rxs8Qj0_>>49z(u>pA*EhTK<5SXZki<>q&oJR zzlE05XsOyH;16lMv0SGWfKtnM_1I(ssT6BQOLA?H&k!nSZB4sHGg1Et^JY-qbJpjB z#BOnwoG4ewNe55>1Ai%0$p?B&h6)7HYL^#>QJF4l%|Gn%sN=z@J9ZP;UtH~F0ZNo< z!W)h5o3Q4qA?^=|oALOap^>GvW=A+5g?k{7OZ;=WlHi!3+nW3nxe|3?lyr;Roh7{w zRwmq3P+ccp&MCfoEmW8L8hRvnA#~Y*fh>-ZR1O=$e0(yod31#H6t;gv{_WCV=?}ow z;Shn$jVcyQpkTzg_#)Ij9Oxb5p6>h7<7uPx?2iJ1@62P}3o&WCBmSxDgaguE!u$du&kcmqBy}6L~^$YRCxeeVw zsv|55E({9!2WVV^T*Wsf_%Z*(C2vq8$hB_ZGyGO*oDbuF;K7k=0h%?=Z-8E*^~c=T zd1MPTerJc4xA#);m{gttVoZMz2T3}X+boFBeF?e))T?$YD_Bl@>yf~(N&w0l%B`Vn zdOc6~c(I4_CckqTyJ0s1XjbMIda50M2yJSwP1V*S@%65~Xp#%D>*f(KRW)MD_=LNF z3NL@T_3>LroFdb={O0jei^RrY64h7^6Mg$Pr^g32BNeupK!m3P#9bz3qR}jxQ4-P2 zj{!1sS@U@j#i4h@jO)=FCuous)YImiIterzx_xb#ZPSHXZv^c)P(_W6=*XHM0f={ zO<2Woi4R^{KQ)1)U#ET|gDnh$nml6pskZ7FqP8wYKD}&HK>;XHI4YQn#i<(cd@jJ{~B~FEm+HZ;8SFD6t(m_MpAy~ zP^1KCFV7tiWib(SPett3M(b901E0b`%F*x| zKpgnrkxIpdPLj;5y4jtTq22;LiN2F*^pclb`Zob+N6cl3P{>x9&tOrnw2P#beV;yb zS05-U!ht3Quzbk_TtGP4_|&D$Avpo)$&eDt0f!lG+4ae42Dh`5(nE|rve#%|=p>>T zaXHP^2n|?RE~Ia;W~Alaa4AEx-I!Dd!XQe$wy2$6T!J#E-BsCjVmP*=$Ll5=4+t6+ zkS2za2|_Z3Q0k`vX>9Bf+%yAV#sQt1ybZhFD6_bqo@Gz~utj!gMzhjxjY=U)=~IZ! z_jXzAcCY|49DKJHy4p@pjy?bsbD4;dD__R9?K&e75HrcRJVMI9;(-E4Jc2e^!;7qr z0-sst)pZ<T{NYJ4rxY(guuf;Qh@9(?1~^0PhDYpdx)AYx~lBD7J-vHek)f-`>>* z8Y7xzjw;Pu4ZdQ8uNZ5q5;kZY%%O%gNp3u2VR=x&?y{WH8cSHp*w+`n&pFcU;6Mrz6 z@${>Ya+}28wK0tWb|6B1h~41X@s@P4R|1PBKMRw#Rkh=eakxdLMr!QFjX4U5z&fDY z>klrSoEITsjJ-A<;FH8hE|ahGsCctKP;B-4TrrU1Wekzg=2;F_4mxCm%)~fNy)q6! z`4w(wHLr;{TA$Wht^pC%fDXP;JrJSur`;jj6o#`jV%W9GZu4~$WL=^SET~`u{ulE?K60%XObi{gKy@WTnLI;3hSrRyY5f#Tny0FdnNdkd9Ejp+*Y&R+p8me zAfW#NJYNE?c7^)^pq+H<+))GYvp6i7JW(Wogb?>pl-^j0St}39$~8t9>~?1qQyey1 zboAe?1A$Tu(?Sh-M5D%(cWK4&v*+a|wKW}9aUu#FfBqN1=KRO&m?Hr za*aG%R!a$RgeeNt+t1H0&GmD!;b4|>Z^l!aSGV~pw8`Dk1nj1-eN9qNB125;Zxwpi z0ZpQOJLLFmrgJ{)5sJ-Rh`?zccWrz29r*3M+n?33b5vl=z_@EGYTrOIv9SN_b?zJ2 z>ZT0Ks2UpT1=4nKED2EkQOYLkPA=7a&-p%O4>*K(@NNQB#xjs}8O08O&=f8JtK+c8 zufJlM3rKsS0@&h&>BPMRZp`&ZTE_hpT6ARH?wzx(Ji^U}OyBxH(#vuDkV}WZr;T z3ZbCJE2;Sbu>n(I>znQ55`yNa96?xAlhjKf?0aT+1Mdl!E|e9Q5-@$CouU@EMcv!^ z`~?v4UL~-_OIgc9xfZR|-daOFDWVcP%L9>y-FiUuLtl8c;CAv2d2YL47ysi?y3EgR@-*85#VsdE&0fmcbLp$1;$SmSn~^64P-{kYI1L=tsP z>B@`GUBKpcUj(Bt-kP5HD0!=Ioqye9X#3?gco znpv)Aw>^d}@(4#wU#r^Pf(r-UfK!-x52EBuaUaDrv^@}F{AR4^~+#G7zBkgNBiD=4RvG>hBv7#g+1;+Ya@3Ig5hC*8~ zp9ktNL*aLW(D6h}Cb1onf(224R z*gKyWYOsb`FJ>hLniuS8VsX6xgQU7&y8kM8{DEw1a~nC=5P3}FkMeAS&^WTLG%tHT zN-oc6UZlW3smI~%71!wrx<6fewGEYZi7XBtkZl89MZ<1*?K7>xXq>P0NFaaMHxtY5 z$X3wuE=2yv0}y&Cu*@mHDYQb-$5DGl=Doe;#X+!?mqZqh0}Yh@q5`X1w%%Tpja(qD+=inm6~z(Wb)Uz;c1VSQ z>p5@|LZ&gW(d^LjnumBV!EOAr>!P6#F>n%uqv#qTNeD|pe{we5cNj~uR&EI`&FVH0 zYZp#$|1xT#lIr0T>FN@3@@dsnlB%l&2}-Fep2O&k1X{_hkKTLTRlX?n0F`C_C_Z(2 z8^#7t4SIf%cbXdw3S1`OswX7Pq2NMXHl304BtB|xPdRCufOrR8Tm}5WC0Qqs#bm}u z%mk6TTG^%H&vj|PjJ0_vqr@-RQ?@6(K&j28)WSk|_CU!shT%x$&&o$Y zP~W(_X{gS|Q>EH`J$NK$6a2n!a%Jj`wZK1O>N>3%cdng-_6w~#6+91f-+&zXIiLN( z_TSGz14|I-X}xyG?(_S{AA=$zMUYE^Y|?hU;6K!sArA+Uq4wdX+`lQ>8IbFfpKdTX3`gI^U>`~3JldtE7wCd!)C1Rk%rzbilMY0goHiHgi zkkru0sRoHU6pT5=cbJf@lk)*=JCmpU-u#=L2R#;J?>AM)$Bx7B1_*hAd}^ zriQcpo7?VlgMD^V3@BXC2Cqes33{fVfhIDhhrcGj1_;6>tCP;o4s#Qa?LiF&o6Sqb zeHq(m|7;HG+~G(F2H9Sj!+)yQP4Ud_ z&jCkXbR z9q!cun@j>VPH(*djP_j!ML-z#VqvC3cFsRo22bTd*MV%rhRG0j&?CDE6emJ*7L&=53 zL4DSM38%$)=$O5^1dz^1dVSAKyrEfj^Trw|j|saYNo_UzMc$s@_NRB1+nI*-eCJ#s z-%R!evf=vZ*W$$KFaZ@YO47R{@C|Cv zZZ^y}h$wR?n1qjlMk+p(S~9L&9X4L+q$rih&-5q|KOCfh+>K2t^B}XKw+d&Kr|%n6 zYTOttf68jm!gx=oaeMbRG9d?Sh?ob&hsvzt#iw;3nFoRX*WL^p#pt7j^#$8<;lGV& z!Av0?9vAz}I62f@tu}|CXsI_Xx;>^)>}{U*x3##^U$t+5=wr7Sk$W#1l6-T@LD@rv!6 zRn-{Kz5|;DDyeZU@yq3^u(G3<>gZq4FXqfS62%AP%)-|@Nrbc}$GNS6s={cjrrO9O zPztGl6Tu;6{?HaBpCd5nUH2i7aK3YbSFXtL-qYHAEfFV&6OgOo(&;>WoIsuJedU(I z0J55Ob+T9jCWPgtk%H60L@L_yH7TjwPR=MQ&Q z3Y>Dpv9~f<`1DyhBjq-J4_^^0m!BlL0XeSx$yAk5IH=xG8Q>s<;4>&FFw5no zJ`BQr)SD`qrj{-@lntJ-yV{}~`mtxebq^9O;1 zt*l=BsZSzR^0h8@u1!+l@<1I~YzByJ`J7%T=A-Pm9Zj@VgM8>tzRs7hZ*+1>_z)9? z+%PW;oaQ8QVacI)+%77+Yh#&qKd!Bv0O`r&SoZP=I#mTGIr6)QPTTU>N66IqwKP~H z&zK(<8xOs)oT+bFmS>pnOc-mWKpje@dK@OUOU#{J@L9;MEvmz~2b=Icskx-ZhZmr+ z+~?q7KcM@i<^0$z`(A9e@p0<2C06U*b|V121UT}^FS8?)YdY1OstVCu0Vi6Zy!7c_ zu%2&|D6^dT@YK&v?t_YLOJc42W0+d4o#YQezHveYUt(^Xn1@YXM|*nRb*H^R1oHR| z>xZSA02pOxl86ce3Pi^vFkeEnrb@LM=Hq1_z0uX)))CKsM0j}ObkO{D=ld^z&lqj> zWw}3E0GAvrR7RqFGA8+tSrLrNt?SiH>RyaKCoX7rRsBK%{=9m&xmV?meIVOiyT(~RSh%u*Ha z6%xBPsds!fBAtl>X|p%$MPV!!8ntiGu)jYB7|#ds0b}tS&d2+*NL6u$T$)1Q3CQFb zOqzgFRChm*TrSO=uQ-qt)M82tB?QBrZX~%c)MpWaMW)Bu!J>9Q?n(3CKpues`9%XW_iW}>34dgpH#J;y`}O68agvFy%c+9t;uMpAH(c@r@RPb_n0bidF5O+I^_BUvJJ!_WEEIu1`<>*&m*_ zQzhb1T;20E3P2OFkj9olD_(38KM=sq`mQKE+ zNLXmPb8W2P`Byu9gCwtjt^_`YWFfyW91>n$CMdWh1wMm(2?La|5dHH2=KGJP2Uv1t zme-=a-LJia%lfOAxg13m7*3M~14u+7AR^<5)lD2p`hU!k?zcHQ023U)d=Ii|^%bXD zk2}vTvGqm-yE5xe6ki~U^UhGNddl(P4xMF%B=mUJmV|PenLN+(vvaxa%0~deNi?C5 zNulIcJ0H|fVWUz$_)Hi@;)2uIM zVFz2^PZO)RP(nT_ot6K(cgUQIMg%`b#6E}_@9BD@B7KW>bN&bvkn8B>%U5JnAsxs(2N_c4?RWs%{={BWB zqtMBF2C?T03Kcj={HpFR(`0c1 z`-rr=B~o_fx_S8$`pU!}SE-T`UFqSM`ls5mh5B9Ayti7GqEUzh%&UTk4uU4^juOm$ z-Jz%;T7baa5kIdZU}Vs$EcR=l<-JSI&!27yb7L8O9_Ahvo3~MeST(Ij^j_A8l3C~H z&2A?;&tjU4X2p<;PNU6xyES&_JDAR<>7x_H4%U>9wMYfCBT>=KtYL4X`hQnIX z*^&+9)%*2Z=Gv=tY4P6)P)+Qn3#A2$i(-xJ<|IqK3-~S1;P%0%Cm2d=JhtQQ9woOr z%I2w81}bw&UTg{`M+Y3hP?-o6ZiG&95i=4HJjG<-p24Mxv7eloEKZUk$Bc|A)USZk z`{<$xk^Q=9>}*ZPA85Sm`*UVf-#g9-@UNS#zLk}Nc?a^c%u%pG$xwdXx{o*tIf&#~ z%O1i|xj&AsKMgjFq?eyaFNhxkDDEh^A2HERM}4^&>ET=>=DMD)e5Qg8?}?!S#mUN0 zZEZAM#-Yuoi+_$-IVcrlgVi6JidNj<>vFr|-E!f}E$Tjs**J5lt3I?wfgOo%hdpL= zJX+HT8mtJ#p>EoW5`4b-{=V@g7jJic=!;IRBbg2qS}48qic~cl!oqy8-KXTS{Gn|x z%V42>Vko>hv*zH(Go|i47XH#Z5(IvYVXb*x{E}*hGP?dz(H?JZg6D_=?#n}n(jAU~ zIowpG@OEdW73K54H`e4qRUvyk@9rj(~)^4eUz`5Gm6tnWscW#y4jT;Zk;e3Ah zLbc$kt?^#eHt8$!FFh8yEeMB*{zUFB%8=*P?Bl0>55V<^JHg; z)-}}gQTYrDUN~EB(`Q_K$7E%5aIqhb8N>ZkX~UzoD{3Q+&pSzN#;2y63|Q1^Y<^e6xZ!2Gl{H8#W3QSL*x; z(|fxUGP4RJt^L<5rQSK8B^seRY{I`kK=k7NS_!YOlTZ5uwx1siPDW;gNd~T=@#PhK zv;L9(pR<#N{=V`YXjeG%*RJ4VDquX`?$K5h&??J6!vv$EVnX#s5vptBx(3lGYrcFj z%&;gFAr$gyy?AgJYP!D2A^!UAvBdfCrT&xQ`wPN!_4U7l>W4lK9Vw~cqqu|wlEbX2 z?Gq5xhm|DD=Yc9{RZy=rOHV08#_UY|&*gj(Mg)+hrKPCINWF}V426$RZVpk?(b272 zfR^?n1q%9rJs>BC!#pj?lg=byy1Kelk`3P#;NA#1&Z|CN7vu90Phtl>fW0ty$wQ-} zO5)(5C^AB@hi@s_AU=+6*7q(ZD(@?BFvtn?`Cn%Ok*nnY?(;v`OcAdB8UAOrAx(oD zQ_XE{zzW|KkZ^;kkHgD4WuIYe>Ce2U=(7FC5(D^9y%AEudIkon;9=>38MXBySok7t zoQH?=+bU6E5kiorky2feBs?NU`M+iW7rPAXh7Iy6pQ;mbVKihiS-&Q=sa1=P@sGs- zZ?5y})Bl~0jld!g1+S_q1U34ij5IV~PdYj~aa;y14qX8s_bR!S@RXWy*C9%9>Dwk|HoYI#lh4gKG)J32R2Ik(vA-Z}kvP z8y%(-$q*H|@(ku7M-45wZ}I#-S&pi&*M)^4daie8A&Oh^XX#OO?Y)Ed*Iq1w?_@ynP+R(w!a`#|J#~jC1Zywv&jjh=$CGgnJ@lxfDnr@x_GtMkGss@}^X+&R|STV<10-dh({_6sIapNu{`3d>e2uQxCI@x83|qZc8l z$_I^QMuOKy`hfO;bnk!*_0Rfh5k~Gd|8d2eL_|d3?Q!m_m6$3suz^Msp>P;fungXP zb_dGJ${LoYXG8b60Omoc=`b0^q;7l(BS8zK_ywyZBlq1-6L${`5|z6qtFuKzQg+kf zGOB1-)I!lEQsHGQ!DHETu16!UXcCC&TbBnipG;{w^fV1x)t;mf$lAu-xBbLn+TY#V zYfP;Md$K>{F-;;aE(GJnvM#7eD0~!1SiV8jZ!s;> z<%QmBkNv%?^Z@(&*hk5@@gG6AI7)zK(7W?wsNUzkUMrqS-^ZYi1kNEJauSE`&+Fjz zMnhw-m-_x~_%DYqZE{K`2PSBVOBPp|iLrMMNd-($xZh*^SDIlB~6UlF3kUTAQzT zRmfF-?nmnC4Z`FOk;|m!YoL(oWu)g#4?!=fA~bBmVSvJbGE9}h8evh+ODR+hq`dmC zNgRih6*3jp;F;GbeN_X$GZA~`)}FSW#&dR2IR|r>q;Z&y_V13Jp+qY}zJ+kxn9gWo zgE=t^HUdRHYA-#DKv_Rr6_X`0S#r!SCrIqi4uJ>uTV$w(b)6h~+vOX%eaBNN?vAEn zjFhcFLMCe|Jy6{$B$V`BgG1fnHE|cv9`MlYH(r-6(LY*W`PrO&`m^m?XZf?mfOrk= zq^~6Q&dv8uXO1>jvpJ{oym0s%Nm5L1+qCC1Pi<;zzSTK3=@+vNJ{`o?b#%+F9mU^hAvwke0o&%Q zNwi(QhI>Jtc2w2JXLVuWqOc=Cv!Y?OVnXA=zNj#L!5}i9H6(@e3;2BCydICh&1uYPwS4K+nc(;o#od2w0=eo zmneUBKam46+fyTq!MnE2CiLLh)Ht9d4kqK@Y0tMt+PuWSy)%7jZ^VaCeRhzlkplWc z&D;bzbNXEmPEysa=4-R`G8NX3V>8NWwwPB2(n3_{l0z9VQP((4=y|H(8wn$atI1d`TgyZ+)cnE&u? znRgxMl(Si)^LFwM*Rml^t0%i%yWz@bCefg1Lp6P^I4S;f^wcHTY*+8&r%+(+nz`-_i1U)7!!>GdD5`k8rO?aBZD#} zCm-A;-fWs?X_%UQN3GfoiMcOFt6!$UlAObZ>u|@k5_m!Ped0bDNQjL zb@9T%e2EBChYzsl&jayvr_FQ1}NT_t=h9{BbP&BLZXAKSV?7D zzym5felfd;?Qyhm%hYyd-E1Mj&4X8jvPb%K!HSR~A`yPWxobk|LA=%Xn9+N?8#>?0 zxLkbb(UJv$zbFi3DQEw-ZA`vll3Rnz!A=`xJ%0y^CuFm*c2J*J|^c3TTwXI?`$EDuN4J-5fJkWhnVE9&UZAsg1a=7ck$l8-sr8CE! z6~9$c?Cj!T1RL9DDT&b$F{xVbk$tN_fKjBWm?_ApB2NtT&CAu25 z&SFrABcB;Hrmer!duO-DkF+9N(95SH-y3}?0jlEuiNwEXSfTKe3QD{JTZeho5`ki= zRuDqhFqDANgb&p2cxC z`Pu2EEV~3Aa}nXOB>i#g@SWv}A>iwhx+R*d=iWrayLGgEP?v%lK7;>jsym%r>BJne zLZVm>49~l>N{O~#3}@|oN8I=?6wAKT zMMDUIvzEtFW2tKL@#DwxHztw7*b!dUM;u`%pN}>wuf167P5CK)*^orAXifMzUG#D~ z)BWOor45uDcP*1_isbzk-no1UdT*lI^HhqDN&0rrZ`dnRlbm-()!taU2pXjS%=1yx zXitX020uA@lI88lN5Pf)I2E?My^-@@UtKq?_a+q@FXl@>-C3EM!bJ5!yK*#Z(-#{! z{m6j6f&YlzDp~MHRd+|5R?8o-1M%(`Hk3O?3EV1SKZW+1Y%MuM8>Ywdz^8KiOU-mw z!bB!lhB7xqvc0I%l(99vPFCmHyWa9oG$l(Yu^SIJbFai|cL#G=b9oU4fG6ryI{bn= zjm@Av&vs>~a>_GW!zWj>8;6%oztfU(#W7h45Wr^3{Tb_MTDUCbACy`@%zZNig~KD< zJ?fRWZ;#SHqg*arXtxWD^V+-g?F*$+#H~}Id)!+(R2XV3Ds5{%Iu#`kL+mV6D$Ns~ z4`vy$#ch2h-s3#>G3A;1iO(>8KNpKZuGiL}Bi<-5n$d275QBuU%1!Vk)tBuWw0!x| zOnpfZ4_pcKsb1&$19T0*a$;S=9%QwS{u4H?5BnnJ{{*1VaH?KjgX6Cg1cp|b;c4X); zCM{i>mBlC_DOn7(zGe3xKYncG=G6uCw8gB#emGY!JrHnjY}6A?Au>uzN+Y8CrJiKa zu!@(o#D5YWIPEjY2W8mh+Yg2@J&KBoCO{P8jw?h~PaJcNw*M$RQ1AjO;1fAV44MBE z#PGjj0{M>@Wpa=I>^R6ANK6U>f<9X{G>OK+Z7Y1TV6PE=b{q%L|LJ0$WGaAn0yC@X zE76ACBwkwn)al|o6c2YKHd;6F7t|$_!TRORK6I~UuwKm3`C;n+UpNer0fzv*jGNbf z{Y7>{c=+6@zJY-s{|cvz0O+%oTH^nZLt(d*c&vnPtl%uiUQRK#{=z~~VO$Wv-{waY z=w%BX;7QP_Qk&Di`pGoMEQTr-`tF^%va)hiZ0vFw?T6G}YQ|J+VfP?~6~gmHV6 za8ct*&97p&>^t^z=;9^iz?izqtg{WSpsxN)=&;`pn_&?yp2-r6v+pR&8lDUnM zP*23djenl_dm0($J5BV8jD$$6>Vs(zV(`0JJ9?vSo8{e$=S}MfiN#M>C>K&g6NE*u zlILmn4VGR02N6SohIt`&=<(+OAcjH?k4Cln`(t-R4`501MC#gpzPg zfi(ZYFfys_HU6j!0)=cBKOBvD+JJUPqxe%amKd3v+n(i{U2o^~ z1L?AqLr+0JnJEBe7+fK`&zJ{?7mAX)HZxbwVu8aP^YJ1d{7JMCWSYpZ5>X?9`;J_L zJkR-n^%oRUwZ&2dU|G(3e#dQEdmw}kwsuRCOfarJCetK=N;_es#k*Bg3dfuZ`g7+gymy!BCF+^XDQV_qltrRf-E5caPcWaT zR88>>GX2(UVG7D12h**d^B%?9n9T>^1MEaMQ|&_lZ|yQ0IJZQ$Yy%Q@pn-zA{`qC3 zT;F7>rkbRC38C24QhTzjVKcF_NvZY{lsv5H-vZrpOs8Crf+Q2~52zHIKTk_=_2qT# zh#lCS*xxXnZ^Z}wPD!oPBUv;j)fE?j7B^NtUFI{7{kl%j-pJR?puYjj64@_mO4$+Q z3Bd<|NHqb4n|aSe)|TR@H)RiyS##;6bHgFAeLRz9NxS}&L~}*(t|27oV%{cJ%454S z3?fAvseF;ec_`_NP4eBZ@!acW+o~3YpoQjG_}R;G(Eo7J^=!3IdM!0v+D@vpv3}p` zdA3tX%9{Hn981a_!OYQ7hItS!RwU@u-BXaUR< zK5P5gB4Nj2|7#6vl~!|V&B49CS60lnK6coh1aXc;Q~Hj9cABfe2@GdXVr9yTb%HMH zNHX5+q+;j3`Kn>1!KRBjRDggy>Fzs|oNE3T>tf_^kXC7n3!H3+s{{B-LufjUl%_)V z%okMM3j#TwS#!bIMpc{7Wjb#okjXKpK7In0+SPXbll!OBQ07AXL6x_Ay_<&9jvnvQx2NOp$9=E~hJga$x&3%# z%w6)(glf>}lXQA{=fr-_>~MR@oJw;B*`Vdc zOgS8;AV2w;Tf6(o#@K0ReJ$R?=QF!mNvwqVl*tyETuLU|PW}F;vb?xp%Q?5>u?^XJg z#u~llu<<>aOI+a9e!l}ziN32>68(=jmU5@7;ie87PP?Bli z({DET^EhqJmPHnmE8s&IaV6aJldOpy+1>jfzcUEc@v&h990CmUz#PHtZhBrcAUq84c z>KT@s_R~$}+NC4VLz~J>I8zH$@Rfq4(X6jGjPGEKYEaNf!3=^+u4viu|0(pxbVk9hK&aI>jO9J-o+iDRoz!5+?FghLC z?V(SQF}7va=`yoIVihDF(;3jsx2Ycd#Lsf}!BY6xenw}C`zN-1Bz=x(*Yhz!3+z|( zm{jkN40gm-wLbbjE10A+Pp^<6hc7{=nB#!=R!-cRQPa_m6zE_QBURr zUFLUCdie}v&?<`Moljc-`8|2yf`Ak$JOVwvpzPRrRt-F3`OhmAm7CS7Fe4ZgCqF4j z>)9naa8iEoLx$8II#14zpL&SxK{8f4;%jT-f3|1r6Be$#0{fIUSY$oV5D_mfd;L6! zM%)8u2iabXF@=x2K4dUg-3PX5>=70XUdtw;!laKbuF)q)`RiCQ>+@aV6}22JOS3S* zl8oi>4rgJ#w{d@#yfuSZ#~&q%*!c+B9%7;rpgU=^;KwK<)aYYl#DCpC0vE93!11=< z127A@;L2dub_H{c1cpa{Y%%6FdJ;)V(2@zMmcTp*clF=G$n)-*xOhxnNA@&T1zo%o ztXt{Iqh5aYL@NRKy$PT^6%)iwzJnUDu^B&7^Z77CX}4;FB;#VD55V@$PbZMo&DBnOC0|M1#(C^k zm6A;6?YdvlyfXx4Z7n;_U|TFsd*?_$Ws=~uUS0x(z!N_wUM?gIg5NlY?6usrntdn% z@_CDz1O3tl@EQ|skcX9+Pw+S`Ci`W9)`|RSIP()FW^wZAp?kps6;k5j0Y-wBSsD6k z6;&Qw3QFI8i)R`I&*wAI!KbbyTb0q|L?zdxRXMWnu#Kg*Y!1}aYVS=tMtQNnEyj?j_c$1hHqzhJmCmMA< z7fvgt)J+-kK!;7gJr7LZ*C6I8yD>BBuLtXu8+LkAdD>prQ9Qh=(!3E|>2c;2EkyTC z4HY$AiU|cUJwONlx88vk;zjW89r+MIZH~@IYp$yjV-uf%*C(iSz2mdLcB#j;Z9~W# zV_wvM>bLOW)w!iB%T);_k*WG>IL!E%dkZMtx~t!QqY|_*o-i!x1%&Eq|5NE=MU9tD zyCVjP6JR5jjMW9fWZ`uJ7$LLHJyL>fckS&P7iq7qhWD&0`YIZ6)cUvoz;6_ zNwJY_RhnefG$319?tH8Wh}-a!gM~!EJ@W1;cWx;gB zsE**0*HwN?is>j-b1R&}LEOdM_*vN$kr9`@2?Nl?KOcMVV0X-7tw)r!_^QCMW%Q%s za!k~Yhl@Ob>MvmHzdo88D~(jBIYH|}(>R{@jVZD;E$yZPGlBjPe>me&}mZaZo}<$~?VGnOe; z4Iypw_;b6Bzpy_44!P4#c|0LR^x$Q8VqLSB8E@^@3i?0}U-~qp-g&)j4riq&#g9QR zPXs~EvNDuwA6$N#8v&Gmpkm!Vn!>37;9BV=aZeG$|^!l=lnM2nUtI1%7ywPn==jARZcRgaDO$nX+2$i7^ExAZp5!NntxOpH^^Aj$Er89+qj&Yr9cWG>i|$YBu> zNQgaLuS!vOV-L&C7Ar;< zFdybMO!B+d-^2(HscvH#{T%tuW*EKMos<&H)9S-MU*gWCAWX?ls~~sbvPFNn?1Cf* zANLI%ZSIIz%(CTAnOSll&c@_eZ|I$U3zr@rMP=$f0rtEk#^5l9A3|U=QzxM zvkB0R@;Q#y+@=y0MK~2Ec2GM*OTN5AXh~y)fA^?IbA+N{w**V|H+?epl%xn%Lm7=q z^bCHMs!dN`>h#P(Vdz+ZvE6g=5<>?VV@vbMpMA`6u-mS$T& z5$e*}X(lrgeeSXtBJ;s%;f@N=vA^2fGib0Dk%IPB)9s|#NLP&w>$87ZXKsQ6dw5bY zBp-(ALui!03FOkV1k`6cLz?FLg29gPhQuiyZIWD8BT09Ht0wuDdG1Qu4{+I3oIwM> zfq8J4J@0n&%uxN}!aJuq<&v!{5$`<||_ab`FLyOm}8ssvegaLHA zBAq!Ur_UbL4q}QCHiI4(rxVWv#-eY4SFuo71W zZ$phhfim-;rnaDpG&~S4^A0o=DEFzr3VHK9=h`uF%Dhx}e~y7PbiCZ0Fa_um%13ZI zo_Le8HG-;4tgmC zeg`It=YfgBja+zh%ZQPQ0`p$QM^*-NP2S}Q00LDDaykFVA$H+zxBl*h)-Xxv&xIJ0 ztEwR&kN$>tD)Qa4|LJ=MXDgd;+}q}td>$WU@ue$Q=0wtMo!QINigX`#= z!@(*qK2fDTeVmf}8Ocs~Wm9i`)nMnwlbAxPQkicfnLn2XFHZ==>LYA(eE#b(cnN6ItZ??=7D zgM2=E2Zvnyp6GuQHNm>?%asznzAv~gHnQ9TkjPKZis|Juk4PSx|G|^7e#g%5K;)|4 zZ_gl`>ls$AbWN+RTW3HGkKp{40Dy@U3q@R~gW^#XxvqWcuE5Uq3@vYjcfU{zDpK)= zM!qHZK=I4-%BY=3JSDMWp+Ey=Z@B> zAt{^1R(Q8eiIddlJR$g-K+r)wM?C&Rf`Zt<1dZ3R3Q?L;%4zTXI%9<8?IOBa+*8W*Ugmsi$O%=c?KZ6#Tb+^0%Ym{kG&uyCQ z;V;ioK?1TX2mF8wWC=W{$#bA0Mex5~2mfEeYW??Q{G_fg(iL6*(5%Q*iHgQ!CAXR< z=YkX*;tp7z2F!=50)bFc`o4|&AG`dW)`f;Y9~l{m3J-sN^XARR6A?h397e?WkH-E( zC{mpah&~^5iO37NFDPvgP6A@!_V)I8&>De9hv-1Dml1K1mHRH==8>>6&*Jm;?)#mg zB8P|f>tua>eG^0;|0kMhZ*=@_N3P4i{S1iqlZJ6=JB8f4lXOh%@QDBUJRP_oB}TRW z`^`K5j4$BVW-bHO|9a=&Ph*j6p3MJN$0p%nd8{UImzX(~=xvM}0r~7BGcPsLzcWCF z{@+q+zLf6`ez8(y*YaMj*g+BFr8qRdN>6^JO^<{To=MhCKdk}*aYA<;5?8vOM=~<< z=y|ak{y(QBhqiu5Rhkc&pXDL^rRmP<7<+rgeFUKsi4P|GL$+q?>1GovTo{(0< z$84*cmoYACU4Ttucr44)f02g+A4kS~Y4-1rQ9Ry*{HeL1sEEC9)n5)It4AQm80nru z`tlA?*qe4lu^)G0A75qH(Q~%LNlBSvsB-U1CbdxUJxVyGX~6}p=s`tu4mr^N*H_g1 zX6TDR6JZQFtSJsLUd+GH)GAR#e~0kQU(zfYm$pNQjE`@kprC+}gTuCTP1tMgVQ~=c zn4fP9)qhgBa)CWLgt+^?B!@oGdh_=oQQbS=IUf8EsOb40>B*jW|H6MufYt>mpII5b z!&Ip8kW**h5(In+97dx>sq!I*7aHYn=l=V;q&M6F=!rlL(1)mZR&hhclx*OokRu{N z#6}pmUnH$n+gF!$Mvi@cN`0meQi;-rkVS%>@xar=HqejF^y}`b5onDUQces?{!4G= zRDO}-nSaLnvw8gb(*KRv`m42ZG>x*4`&+wl3jy9Aso`5$5>ir9 zi?-wU6yLu7lPpo;pFb!vY*5c+U@*3-TxiC^g zQfBvgV3c>qf@FZ_S@Z{qsNq%aLbJY)k_zB8lO_`t#RJ)u_KSPqEmXsx>wwu(!H16~ z9|qI4L3wX6@T+?jOZm^g3`fw_jvU&aaZ)0iXqohv{V>m}IXz@JvYC9)xBB_s*WDr{ z&f$7QI{mXn`Sf`wvFiSikfL9#kS z1p45Gw@fNk%?Y*Vdg`z0`gHFjjZPEYK+fN1x}9!ew&A#wB^hToSS@<>tHn=?+ED=S z1NL;e#GysUWa3ltK!)lNcnOXfC=o6NTpecqO~A%j&v_AAL0LU6 zMBs$0$MyJ!=)&7*x~E^bld&qf0bz%%TG(yan;HSt;*tlWf5ppX72svQ&EP#)=GMC$ zLbc`-Dw!J9z6mdW(kT=h%SSInC%P4Yeu~N+u};b$9XD$Vm>(?r!M{!nyih)%uep1(EJf zrMtV8?v&hf{fGW{zTMexcJ`Z{*&T3(!OOkx`<`>2bDrlH&&5vL#&Wno8EBHnjap|D zTQFAVWW#$@)W z+|0V4?eOy6v|!{*C)e~vy6?_90G#`q{pjep3P2fbLT_Sa&(^akw!Kg1%BRg6ThYQ4 zE;LF0;Q|0)1d6af@?M5JeX!J!MHy9d8PM{#HcSf2&#{PC7?9pPa-l?$=0CQTd?{I~ z#HgGwrfF1mbHoma%7=+h&B`ioPGbn5${Igelvgji6l7js=)BDMWTsSRx_o@LsGG?vHuCpVg#A_N zBT{>f2KSBRUe(V0Ny24jy~v`CO<~YZI^7KhDT&brkdS||uJz`OXI)6iy0Yu6yBJ^P zt&9=S^Is0!29V7i-s>~>R}Q=Nv-FiME@~BT^^J`=HB%hNARSchKi27z2?}f&kTbv6 zpC1(i+QQUJ$X7LcQ1FsB@}m)#;k%9_5aXJ&m0aWPeRaugl`+fi7;wQH^W>2>_-Iy>jA-BY)E69UX+Wdg$mZ;}kh=PlnS##8>YVMf&b6>&G2n5bCSV^ht5!5K3! z7@%(tCo!1~+cF1$U6%rczV9m1pTf2j1wd#xqkvcVsKRa9zPoCBey0|$DRw_!r@L2? zIS>m9e$||i#ZAZ(9^$;~VY%DEp#Ru%PG<5gw4n*M%w&SX$m5QIG?i{5Poxn@ zV}cNEZlPcl9OFtv|tTSK{a->@`e!hn=O!^v;P zB|Om%?Q24;)gJ@%H?djcHBeD^5EsYN%zsg~_!610(W06^Y1$rb6C+SoK@K6BEL}vHuP9 zXApV;!K)u6+baq(81=SN^I(r@oW&Ms4)MI(G3RvAxcv@;1$}!YbGJ;TTsgI2tlB14 zc9uh}ARZa|6MZnA+v=U&+CVel7Hq#+UA^A-SNBe{K~|4!V?cT+ebyZ4x3~R_GjspI zL%XEAunNe9Zf@8K003#V388&K?JLBjuk4EsUp@-LKAtc?+J>^tA>gI5RkLYf+Yu;u~i6P zb@LLf`im)HREm{~yGnESQat*en)j46xP|{>gH+^Cn@$}Wj}-|&JB?x@%Z@t-njdH} zDC0jLmTbPh7zzfPZLG=#HrdQiLB|{Zi|ujkZNSnlPH@@2qZUG{YLx$YfD_O^tW5@r zywr7z?6-+s03}(2EQ~uNQK?XF*6cYCAkS20hTWwVgAWaPIBvj4DW03#r#M!2Yx5qS z#t6msCPTztGcfND+NF$YuK7>5U0ek#xfA}q^?yAG-4*ao;z&X z>#dnpgLVkk!QS56&&p+$c~|IdbHFm$xonh)U$Vy@V&=2{pI8mgA_1seG%H&RZrvs2{Vp2p)zQ1c zcy@z{E+xj<4%g$iqcd+_hmN31)b7zI89aLxQ*JRnNBs2d2Rg=4mEENR zE+oq@g@FH+7qCjL*YGN;mh0QsUJe5JI+D2@F0f$_oLW#TrtTK<8+A>7hH>ujt>X;ZdCA+V6+j?Z5_ z#1C+t>))vLn=jF2x0ED!KO&_bCpJ(#S-F{8NXRq(N3$K|j~jqN@jGeq%A%4@@D*}) zuF==muRfJV-gSKeSR`fyu47X}|GPrh|8>@`P*F7?6aT-Ewflcm-}s+MYH&3nYgnyy zs@y%Uc!&}%EDEgu7CIK5|5b6m|3Ba)cc=rPenkZw{^IcQqoWEUWj`W6SWYr6K5($beMp$2e$zrz1oeg7XS`f*k@!n`cxmS2TnI8A*dR5^)+ z@pH30_rIe8NYsRe^G`q`Y(|lgknk3eg01pn|I*LT-T=q)f5h`!#ER&TQyKm(D0sKXw+piRczM@UC`HxS7U#}-Febuog?Oz2>`0Is=e;sEC)t5gm{PAhXzsehg zGtS)jzY8>=A_iwY1m*9`TSA0%`f(iryqpiZzQTPV29SaN*c8|R+IK#PodDkJm4?h3 zu)gydoBl~S$rWIFIRPB1aegS7mMv9RW4gc&=WJO%G ze^tb8sc4S0($oO{0*(Va%x_#P)%^UCxP8#gGXI=Zh}8mdx9%_u9I5-H`SwLvzll>e zHgL8LZ^h(OUbzYv-r26&EU4`>uUUWiMY(V;h1;!I&@dw<8TiFlh*7wWkOSZrW*C*j zLuk+p1ZG}{(~0IKAR&Zi3-Wzq03y5v1m5+m_jv$sL1undb{n);Hcs`pu0GzL9_Nps z83z2E?F5qoD>55koNosH*#kzy)U3n287L+6ACCOw&kNEOi_pH!q}?!M(3fNk9%(n{ z=F$4_V_+2l4fl z8RElhZJh$j8gJzfcy<9{z$iP_y@vOr`*1*m`>=NgaP3a7nr3Od9J)T=WZ?yV>6&wZ z1k-=D4G1lrpH&;(>*1_dw0EFt;@3qlCY$MzfIP6vqeYXyNF@lTe#dINPlkqc;qibO zoo7B!iMu)<18nDwiknvP1O?y4kI8=-ywzT+3QcHxWukTqqmr$NZho&a_ItkdA>-;{_Ejs6U>Sw`SuC0z9Urjhv?+wlRsG&?-`}ZB3PbfpeA$Op&44(x1YPd%5Oqj{y@U{)+-A z`@rmYmI7#``m(na^rP#4#2yeJ4w{N1p2A^R#2mo%DR8e2TsBN`YMXS%?aF@Ag)-s? zfOhI@z>TtG$IJb))9-Z~H37z|XgC=-h7V`gD=`*sc1wRB<+Yhzlv}!G_795%B^Pm^N671-!ihkg$FkmiZ1Nso0+IK&$ ztg@m1uHRpSqyI$>BP~l9uQy@+x*w4E>>G0m2Sa?$iP->YRpHsGP?qM(H~Cdy8Bvm$ zu32Uj$=D5;JH|NtM-c>^Z+G3V&Z{pp+;TUv+$FXjy7UBpMp0CJI=j4-&WTepKC^+R zHFi(SvH92^fh0dscHUt`PVARl`z&Yfv09nsRbdzTWToil#lc2uYj=dYU@F)c!}$&Z zNcIM=3Ri{7u0iL)hGNh}qZ$E^KXC*nIDJdX#6a;HgSkqFtJx8R>zy{u)1oc)tAZ2~ zVs5mZE0vAR8h&u;aPI}M9^*m4sb0F=uAH9&vsl9;*W<-t-)9#kJK2kk_;kbfA{J#X z^6cr(W1S6e#|ySwj7J6O*SRKrx;`HE#<8^)R4t*K45SHQ<`_XY(OZ(^hJ8d5`)J|<-EI1y71u6;GW6q=scqg#|`b&p@Z{HZ?khWa04O`3`Z@QX^hAVV4Eb`(iuDt?J|f%73uK#%2sr8GZotN zrN01dAO@J9p(f6Uc=9kOGsfWsxI!ev*Uqg+R%E+W!(z(16yQ1h&3jIfZpeo!20@~ z+wrKf^cns0FVCv3#7F2up7$*Q+j|X?9O*X{swb9IxO3Q`7G$YE!ubFl!&#bNR`J?1 zTV*r-LrTg{5?Zo$-xra@E{0Y0FbVfZf>aT)SQ1U2`I`A@Ugz3J-@YGz4O%#~zYO;J zF6HA-1zMpM4_#5xY1%*bmpIMeA&UM8`dJi&2iUunSCZZzec6|5s=O-u^ZIJngO^SS z=W+p|@I=X_D{!Rz0TKth)1vP^o_1C2`Xsz$nKvt)bg3LrcYMUbE<6arF$q3J?w2my zthz1L)3OcARxGZnLrIMn^d_3V{UM%PO0Riy3(xVPgVsw*CwqkX*w!!XWOBAF8n1vo zdd*EVwb-Z8?2QKH)La+&harQFVCOos3uH=vm&9+ zC1T}rSLesG^|{R`$MFI%%ED{t&?lM;CoFn>1B06LHKL5kEu*XSEuJF4Y~4|cRyZvU z8+A*w$DqK(=!%#Q@!ZLW(-Z*=uq9$?x!bNrfrfD0`Ia~OnUtOMEXl_0W78O{4Wfu~ zs9j-agKfCP%zDc1Tz&0kY{u++p552}WIql-H7mQ|M*f09!VzUV=UVz{Udd;{fD^s| zLd25dF9kJS(2F;jhTc;WZo?kehZLum18H5sEDdWrM8|9;`n|6t<8mklw#rk+@ezR} zqW6#-tI@vfTI*C&>sq30)x+J*x#ThoPK=$-2oWXo7fm?Y8|*ERro7M3n1c(^)?xHt z0CC)bOhYdxRMc@)!f3@r29#{GItB;c(b!!(M|4st^LzWN6{)D;+=1E=8)J#$ysNp~ z^|-Mi3-IwI-ykl>5|wCe7VC~p1@GtjDNGGJNmP$IJH6FIA%4^=H|d4*0P-7Am=Ml& zFmnyPqKGzCntw?DJu~o(#v9CGAFMiWP%kmMR~u{0DSr=}__)Jvo{m^jPrAbAv^vTQ>GVn&-Ibvhj3bLEEp&&$zQAC5BLe5`C)yyRVNeL%=C5H{A5Ov<$0cW=Ti7+-$3YyV>VW zMrO^Y**r)lnbrh|i&thGpK@!@r+|-2ZHCb;VeGn{d?T2U8SP!`51j9q#3Y|)?b=x& zZ{E>MbpF(V0^YL50)%RB0m_A#M8GH$C(ajCoX-)CNfR7_Iroz0$|#?M(b*JT@g^GG zI|;f=Oej#hsQ{mvUz!aFonO6u_!yVEL@e~{=5W;j>Pj@ z;*^rNKKI)0uE*0~L=L>)gP5vZMNa{#?$jYTE%{9ApOtEzR&?F#!8Lj+b{ca1xj&kP z@2zr4znU-_68{J?9cCQA>nChL0O39 zhHq=Ygi0}lCnUMgjDEWMc#6i_xxW+?;~9)>{A`0M%FoI3(RbAPF7Uuv+466nN5PSv z6tBV!NGcyRir5m9{v=-p&KL1WF-cLNMI$$zIF1Lu>&QdE=z`J^&`H}KIV-kEp3YirJwX6@K)Jijq!s z92=+F1yFdCOYc-K%epgptD+sV3quuSz{PQVQcEkipmz16E$Y1-_~LB)86*`oWWx51@*xN8)tcABmBni-%ZKd9Z;)<13_>%-QB(KA(Cgg6v6h=lXapS`kUyPA9|78M6^z`3~o3H(p;q7d^afZn7q;&7ugdR z!A!X#cnRqcB|OPBtWVJZ@+fCZS@xu0e z2XeJnT3;NGuF102kk1*fp$tERQ85sg%TByYYUt1m$@o6(ts)(lG&M5@@#%-;ERTc! zV7(BZo4ZiNPhr|*1*GY4Bh*EweE$G3h|f6HOdrRSk8#?8Vo;04ao|KkU-y!%mOD59 zo#Ftnb%u28kJYE!ha}&U{&OvQ7rC}i%f)tRNX$q>zt8(yW4&Vf8 zJ_tmfe4kYP4jmzIp{{_1?&TZx*L>(y@7YOB<#PS2=X5C%3I_E;Z{=d+n-RN>KhqAA ztkV53A0njn9imM`iB0@1#wIKB)kmX~JOOd5izSvpt!!yB7ApAOlSB?}2X`W3A_+B4 zNFHR$+6iwe?v{aw=;qciet0ku|6)7sWT+8Pw5POAy{F_eWU0uOvWReiIIkRgx0U8% ztnOR@nhu`=PsxLE1I8%s`r!^7GL4;oWk4!>__)xfOJGG@a>iIzW_6^;bBn*wMgHo` z*J1;bqq=b&RaQoNl9*?C@w0UXNC(d3A_R!d=gh}0k?e^0u^V4#1vu8yCX00LK9z^8 z{4>xmAtElPv?aYXPG@rfY69tUCus^mh?+ZEZqfH!uWZz}10Jb4myzKU}--i`gd zJcOv}3tdak=zB?)kfei#0DWQ2z!AhE_Q?7){BjJE;~hzp5vdV6K|iNNCeMmR?1N%F zB2V)mVd_;e5X8958gBYS_iUR*J^D6b zZ;E%7>9HHWiEz+U8eFGFdTA}U59e63E(wznZow{&L9bAKM+&8o?{9jYAjRuLjTCDa|Hy>p2LZ`A?tBR>PhQ3J-lW|Kw%gM$2gN#nI zrZl~AhzDe+O%%|Md0!CQjXP5Xq8&S^(Geas5ALLjQ&IB97=6eOPOT6dE7j_kfo_6F zjg>25D^`FPp%d*na7!GwCT^Uc*nQjR%8i2xcl+n=ca1x*4dA;|_vOfIA3>dW-lNdZ z%Y(O_WI$BlvDP|D8-M{P@ysMQJENNQ(MM}unT^d)W7I-E8XG}TB6k@VP%0)+j3b0O_6P-IcAJ)=@=|qAxP=%?eTM6?W~LiesIi8BX!z@!MML z1Zow-zeEZF$`F0rx4adtBNZZ)G6b;xUu80)Bay;vNU>2l`K#kUsa+2^q1 zetgf!u$LU4O2j6^c1S``a>LYW(+O3>XUHGozpcsUxSx?Fpe~(p*JdLnLS>Bd9f}zM zCI6auC78t!FQcp1d|;PutfjmBhYR2WCWVQctB+8b4K{_q43_yi`3O@csd?Zkn11%e zQOjR0g!{RCS2`wRHH~nks5RU|QmpWAH#3=(tqN!1MqHW5G8Srjj|d{yq8RHiPq=Gb z`I>56Wu?4-Lval&o`L71Vw=10JJj@UNxjhmTb=>)onK}vVqDGxXzPVZ?}109!YUyV zySmSI)aJ)v8{KcMCA8b!6gd7fVWAZ)b`le%HMApCgJxRySBLYWNK5zd)|U>*z4po< zSreC~d)bpuzL&_%z_(abCj_3n{1QnvbR=FKoUe&Tl?Cyu50&Jic`IGYa=M~S#~=4K zd_>{p@TBC$K%w`x+}T6u{x8xanl#=W74>m22!0v3R1sYKK0LLMe6q^7}+YMBcq2#co(RCL&BS%LYbC z1ThkQ#g2f!JZS1|z}))mdr)qO(`@E*r4+q7b3pv$9Hya4I~I+E2}RO+2|b6WY4ik zdLOAb8dMqRf<0#W3a`h#T{t|JAOJyGv3RiZo0*79Zv{u*8{BoOBq=Brm$D9G@0+LH4V9*YXs53)OcFFk!u zjU5Mikh&<9X=(2yzHt-Z%+G?Cz6n@?pefjy=zINEN%u^MIH=EQXhB1P0=XP6K4VbK zSy1W$yez;CYA^y$oaI0qx8iKdhgpYy=U#`slD-cel7AQieid$cZk) z-R3THrGmNRR7&k~s=ava!$9r_tDZui|MrouPugcJtQ%T!94*kCzRRSd6V87U$A8d4 zv%{Bw6>gchUKyG)_Oh~(bj3&e?G%ZyZv1Hc$4IXVG>lJYY{E;I zJF;pR@04Bt9Q_F>V5Q4pynR4CCFmpMUW9+Y!f<1|rPp8gH*ihaU(ennooOI~ zWlgAHA&1ib8sqspKz)|1>Ae1t8Iy*WcNzdVTwJ`A?Z8-3sV_2`J^u(u3abbALEV26 zFgfx;!J(pG;9>$)+e`oxsw9QqrN-lhb-}#LE47YTHs~C#`tx6^M?&B>W;I9M*F0~~n?1;IC!!m-~ zNV4xA-gqd!1xlC`P;aWT-kbt8pVGxve_sEa+%E;z`jOA-?6=kKIhWY3%fsc9aLwOr z{!44!v?ug@o1l19bnv}W5sA`^qCRMzk25qfRq~QU2mYs|$Ygg+62b8TTc1R@vfP;bWOzS8Y zU;SPSMnNxNYJ6{S->F`mS*wD50zxBuCFld#w>+RrWY(_2J?r;P#(|o2*!}vap_s?VeU(P?+prUzCEEt zHeEkWt8aJ4K-by0sTZrKueXQWS4NcyUr{Vivk4xYE1#U~1=`P6*XNn{5}$Ns&rdGh zG1*>jFDUA|b7es9R;a1?6LeCpI~(LC;W7>*n@Ts%N$|ow)BgcW$%dBk}a@)9I)d_A-?x!t=h@@ zhyci#Ys2t;0ti#T_pwF9MLc^b#%Wz9JwCqA(+?`BTW}a4v(g&2;@UkKqY_E*X&x9p zEF@VaYlqdt1Za_V8ZOLh!NBE%aCH|-Ln$VUok}X?%d^f0OlKTc(S1CVfc1*UTpx6m zl+N$n5zt>xfO?@W9Jy5bEdLFlh{C*wJ?xtIzCwQkJ{G@QRxQ124`s?=wlcPugDb_R-4)6wb` z*JJ7yz|+XZvc(6jVD_sxOw>NVrn@g=_6vSWGyg{fWHjOON|{+#m5U>`!SkRN5a)P* zV6bc3`PW%qRPXFkcs#E3*ShL5zZ7Gcu6#|F$m0+=dw6MBVcE&BIdXDS?(op^>8l%x zn~?a|dAgki;vb?!)CeOx$fMB%(bJizeDG-kscAZy@#KuDOdhB|S7VZxEPX$#V)(OB zpnbRc#;_osx4*u?YImmJslINfr+yXM58budIdktjz2KLz!gNi?vtI2n*l@46&7WNS zM3;VjRhho2z=>zxeeovw%m?YK^bNL6Z2q%~oF1baM^28qM!vD@Qj-3xiadxa{urbkWwhhvmzir27Nuc;<|nggdZ> zy?t&>Qm%U@*E3;nd=Hk6?Xj#5k9~XZ)47%74>$ZIy2t!A^X<2xwebR~j3;8B0)KkT zcnHDXQ1b|=(x}dIk~n0n2FS?OI8x2H>$0JFaY*FC((og2BXIYO&2}b=TkpeW>?{T| zkaub}nTPwL9!U1M09nq{#^GD(`^MXC!$J$@>H2v?X^YsD%SF`$y#o|uhKqgNz9^x3 z4w)aQJyGt4n%%^Y|>l>!ktjA;;c~?=6p2w>%ZI zuvqQ;=%|tq%j}poRnSyhBb~I4&OxmDOSgLwt5bp>rOhKF$Kkl80#>Y6hdHPA07P^G zbVA~j%bxlw_66?h?!MW#cZo$}Zk1@)0<@Q1x$Yi@gPrl$!5m$<)VsOLHY`vyE}9}T z3U{GCulnd~)b@L5$=}&5&7jTuppRm?9bCk03EqW`o&(5CzZjxx5%-x zm-oj{Ba$Aqoz-VGtxjc+`yht3u{Dw$4GnmU7I&0?m~x2T^oE6}a5IKPz}_9oP%YS+ z&J~^fun5UMPA2!zW&U|PqK$;2_X@3e_->|t=EcBDa}d26W%y>$`|SRV*Q=+ppG~d! zH1ZMsWHfzBxCoom!on9$8yyy_-QN!^2BONA>5yZR@}kzK0J(@LlgWGMN^_j|vLKJJtX|>#I?iw&_d9yTJ-NE`YANC51ak)3}&}!od z+CzF!Ckf&B;=o0$R78vdrQLwcg(Lbim|%ijCb;=tg0$InhLd#27brwFrJ@)^Pe31GZxn1SX}{5;DiX>aQS9Zf#v<%lezlt? z6E@wJ8Ie2YAD$%n?Xrn^xn(T2-K-dA4Mr>ocI%X4AXIeD8WCr5@JwQVLk*q&V2yPD zQyDl!=b&6y<&}i6`uOU8T$G{V;o+I$+yN)knvl0+*=eui(6Ao*Q4V4>Co7^; zeX&%I<~=0EsK-57>hlyO@Ffh@HDQk1G9|hkE9dxN6rhIIqbG&%T&}I9c#u-pQ3(WU z%}OaCNPN>N`^e8qbrE`El@(3X^plzq9f3Ih)!O}frXwWFzAA#=pBdS{-#+8+m9=fT z*-|6%?K^Nu&#DeFKGPjX_bQp^eN5HVzg|v7^VeL|sB&M&%24@;s~ z#4rYG^^ZKA^R#%C*ZyU&&t*{Qkwd{N<6H#SsNB>gLnkwk-#qxK}*b z@vpD38*g45>S-EHeCJnW_PBk{r`*34p=@#WG{q&0A;s-XYm3(wGqkqB;_K_s+OGRv z%?GDpR|XC@Q!uAcv5e=tR&fWSBsBQ+NY0g?!|C2Cwd7(=54tai#j&k8eRw1{u{9?X zSC1(uy}pf)SnA&xuohwh7nwEpne;|Mao9Hw9C z`%CFC+jLpX`uKXy6Y;jAXc%r0s1>F`6LCwekN|A49qN~7Lw zv)JIBGDTe43K~4|?Vq-B+ocj(_;_aThSY0X_z1luQeXR7W=G0JLd5%MN zC~$wQot3$}G#Z35>Ts0uD;)%faL@PE2mhTv2I~66`!nASm-Y&-#P*H@!s4pe?$zCN zo(6=}ITEYMzllOSR(<;Uo)-B&(OBNR-(G;_q3RnL^$RWaTcv&#l4HKSiH%;gwABY{ zOUncUWjmT{lN(Eq3<+@=Juc`b(F6z)Ej-E~9=j9%rK`-I<5Hx1q+PMh2~v>D5-YkC ziaja;q9JUqXnH-LuC;i{B4@RENuQ<)e*Zm{%E9}GYK$wveLoH$BBDOalj9Gmsi|k8 zJNjAE7FoEy-FBGsd1T|!(msC~Lenmj{^Hw^W4_rlnxG*Dd#Z>i$iga97oK=_- zB0l)i%75wSz&e-o6Cs3d)fkF7StRW#@kp$RoOne7!WtQs{y0R~aB=6UgEtXHU#b(u z!|EZ~kLk_!)tem?OMtOe^(MGlw{uq4?@^H;M-5TXv(|wpT2<`*D;jP4!z!zeXB70I z_xyTfWi7|wqX@JL8wDJYb7-wKTY_1IOvYgpF^RCs%+lWMXo&88`SUQ5R+YGUY(E=Q z_stnn;p;>uJ3E{Xx3JArt45} zXX`!7OiV!tZcMJe=%i0kkvFxvJd$SJ@@|8+wy(`nk?aJ#_qsEsukEAPxmh)An$Nh& z!EnH&R+giR(|CD+0nhH3%UzJxt`_P9!9my{uScl}R>_yoX5s5ecRhDMdq-O+=Gz+$Ta}ckQsTGa=+NNXC{`>7R2oe_f-)QS?q&z?Aq@BIlxpgDzcwX>? zDNLdr^PZmLAaJbFoY(zt$ZBmA!z|4*e4I~^TlH*yqg=x1QV5yjvy;E7{HrYitRMCM zVQ&Vis^iWL67{V1$M5t7yHmL8!;JhIj&A5m*xKgF)xMs*ZDeh6L{j6-*-|U1wicn% zw#6p+GGDf;veH5Bt1fx3HAkygDp^eX`qsyw?_yH^q7&7-tO+N?E|V~wpS$VA`OF_9mS)+YVKm`HtL4@}#Sl~7H`z}_-!nL6d%~__#3KW)=w(p>rg}vAEOD& z*!TPMe4GK*2wODu1cYo-K?aNK;vrPoul4W9WTO;^@!mf1s=Kcx;vKpF<79yR;_HD{ zs_Q`@o**Gq%G^K;#leIq1J;+syJI~JF(f;^s3yrWF4l`9IK){)E0Q)`(ioDZr91Im zdhme8A2F1-Un;8t{Tm?`Ygn|6L<1o=A+bGGlPqD%)30`2$3hlJ1ex&|OU9v2jDN?g z8^i-b`hsWZib0$*u%>m#Iy}UbsjS5t0N)eu-a{rD=NJ#SdxCrOkk#M&U3iZwpPTZd ziTi3D6ZRYdRVfcvyw`D}!?G_Og;2Wd z;F;|{ah_TumW`PGliHQgnvj;{%9y51oL4QW>h`*)&6)SlV7ixO<|JD8IqsMxDz=(^ z41Rqbbe!X8W5su(^G&ak6uQjoT4RJ&Q<)p8F`2>Y*8H|^rX&XK`}*FGc5Y|tzWbfq zZ$2$}E2}T1SdVA+1=C1rr*fzsgHh&3f9}7X>Z3Xd{)GNnbQ#QQm+e z3fMjIWLfH?9km3g5TUD}w!Nmo}E4=WcI z776Gbmdn@X3#fwbT;AyEjx9pZX+C)bBQxH7tv|4@x0xMlms8i(;|IR$^{fTA%MRZTgG2qk{7P5K zXx+`GHZR-f8}>&9Nx|*@=51u3S8iX{>}%Vg588w>`#I(Y2o>S|%BC(7zGFXh_)z^U zHAZrJmkVbPr8>AL*}>0)HLJy$fz9{MGvhVi1?Hk4hz}xy^YI#*P6ugfaq}fE`J+5) z#JdQaXR?f{-1VJVM?!2a6i>uN<9t?=CNqa>O=?mhXTHD2NBeG6J)Sf2St<{f+C$vj zOF;xb30Wl8q%L%^rR-!}?+|^#?6b*1IJhUwL z_5AT1=?M=!#CU}?v~ddH;UeJSdQm>0q{7W2$TmmC@`}JkWMgBK!0gm{EyaNGUM_$B zC((RmpAycUmu~I z0`pMy-!BuPR04Z$7v8}5vp;`{ga*$Bd=^T^BcA{Bj^M3n!Pn7a_-+034H5peX;W2g zaq9j4E$**4>xS{~)qo#h5%A|M1Yvf;QvKtjgaFr1Xddy8zxBeUrKAGS>|M9kv%CL% z4){R$R2ZoI<7z}G|G#~iLbzyNfGT?rXn3E2X1g%U&u=@ZDG~quzNU_diwl^oby%+1 zEI3qtzdqFmieP~NQJ?~Rdk6*w`zbaK4p(7W^!uo&o{QJ;sY%L&F|Q{fE^c|%*MD{m zJW7V`Zq3bYfiBzuK|x^af!5b69{)KdM4Fy2taQHTb~#}>Sna3ypy+(MV+P3Xwnq=Z zBt;=rQ86{mlZ2?eYhp$^WA_zG6>vi&{tCK~7JJ;dgFi$C_Fb`tlxc>N$prrnwpSC4 zkUBRrGd7?PKTn7GMnG+TG;L;ilS5A+dW2L$4+(F#hf}lz*Dj4YEYv*3=YLKpq@Eq8 zu{_mYY3HJ#ThhAXpeK&@AJYo~4`K)AYnjSg=+tCF_g4mA^EJ7nGF0pD&U87X(1Tp zh%(4^eh(HkZWLHtFzYE!qd%`omJVFi2BXmOy?-ALxB&@p160s$;<7)lDu)1E)$yIQ z{r}tmEx3V*Bzr8iKd)*8epTn_184uafhceT;?lJ!kN>=?4fs{LAsb!(c>`1u;09>3 zHNF2_pZ{wgEBD=Bp)@cs5Jg^IKFaCkA9MB@e%60(f)cS=B+X%W4rn6?Gcq&r?%p-1 zAtxs{*UF#o?Jq7aW~S0XL#)MJ=qE&UJ3m7EwEv~>&%1>W4XMko(Qz~S&p;A=0FMkM zSq1BlzzaehABa^0=l{k?_z%B=8t%LI1yp~IPJpLR(;b!DW1nA~m~Jv!l5jryF-PxHE! zVPXDdQ_9PG>W|e>stPb$Eb2)X9ma$l=MY5+#c?%IY&9AF__T$4U``3V;h zzzCFVM5-v*pBci6j`*ymtLL^Ye}o?v_}28(bZ463rEoQV^>kRdR7*r$ z0Nvq#7(2f*inY7#Y-+vI;WbljBZ+$!T|@kDWPs2jQawhBk|uqAxhok_WyT*BwuOpM zFqA~{34xXxQvxj>_oTayV>4SN-Q7i`d@V>SzEm9ZOmwfLpvH0$5u2PZ;OxvXd|O0B zBu%IJ-NKik-zx}kt*980md5jiE|xblU4UMFp1S~e8!U!NRsPBqX!QZE%hPamqOOn)^s^nQf`W67%b}75P}?HD41FMY}}06I&&;4q!oE1A&j`*wr`>ZU9&@pNXrsndYb>;a|* zwyh@PKjVZOfdrF>+{Y{0qba1L9Sra^g-lo9nJAz8ve{a)DjX9>#4UJAL(3eGt)Yz& zne0!!G$pS^6pxBc%DTwJ1X2k!a2dQI6oPZ3v7j97eDvgu8c8&aG!X0y&`C$h5A+Ca z!!8Vf4KD;DC;)*RkV0^|tydt@K;|n^`B={8Xl+nZpgW$O?%+r7=BVqJlHbn{iN`B~ z01*?FhpQo6Ipvl#bv*(hqJ)6sZ6-Wi_p4s+*)OkuCdd34oz~oUHpP1bM zv*BzBgGr-mV4vskIm8vX&F09azgu?6dNrsVe#>G1DzdKI-hOw^O+xzC#ij(r(j0(q zKVk(mo{Dh(vD>**<66TOT81XYRqC5eTptR@!9X(nBwu^!%-I3Ya;N;0cu;NCW|E^A zzuxw7%B1RPHZHf@IR`Mx2mt=4ZC@(|&(|{7hO@)j^sXKwJ(P;`1lT{sABUptaplar zxVZbVr%n7@9n44*jX*D?v-CC4?>P*H_#&1$^s_?t5_qz$V4Exkm2*q3loVfJvzsvN z8pEs^R5|C20laV8L%HURV4>!<+fT&~g_$uO4nDHFG64BUgGR2&?~@WGC7KUtdBEj# zE9!cB`B-m&BqActrzn{h*IuVIbCW;t*3$^Z9Kw>X%&f4cShC#_K14DeTh>JufZDbK z-;}|RlJ{6E(|}o_`yE6$JcdUK0OA(AaZUe;2^Cfc&&3x^v5ZIn5%mW)yQ3?QfXofW zmweq8(5lFy>pIQIYR=MMaq_m zXk;s@=SL-a4g2k>=r3bBK1FyCsY19%rlQveIQL;1Q_}=a4hXLBZ9T!l9PX5m!TS{ zFjFVE`<2`Mt{)N`+hm~F0+26q9y=oC;>jEKrGe+u8Ra|6kJw|Q)7J{-qy~39#^TE@ zf%ggd%gWm}8OzVS_xoednf{4|mQW;^G~~?LH7A8{S)_nD1t(PetQ{^aGF6h zmMb%o3r`oud=0m1y>I`uMheqF{Y1eV4zpzsEZBjWh(eJvR%xMa!xI&a6FC+uj6*0H z93k-U2@P@wz9_hh8~9{<1vLi4Pye@B=aw+X(XRDEp%J644s3`V_#&rWk%c*q<-Cgs2-GURvXQ3~~n z)=!aPfsR8iyrW9ghdjQZ(rU7_kWX)jGpP4PqN?rugeQZgA-@=-O{9W*O7%in)UcyobIYpx!i zMRPGsh>VG|)Hu8!$ZhiwZ`{=OT8EAIed}n7sBLg;1pj$P`g-?ZdUFf+z(r@d>&cdC ztb?c4ErBX28~io)?CZdPPVpMd2<P`h3|zdrAcxJbAxKzePF zO12=GY8U!@>jVL+iokLUuOlE`xPck9_I^NcaO>Pl5=;ASnT~1`f()EpkrQuqsbMSR z7mJP!OWaOoL?Y3JA=LWjoPot5_3~Ptg-3SDf4-q0$luSz2hj;K96YlJ_DEe*GFm-C zpoXvWoC-9mdjwM!Eo3lb=$gd#YNY;&Js`JkVgct|=G&PMP__yQQC>YMkA|3jN0`uN zS+1y2{Nr^(NX&`g@TyN!=lB*s_;_P3tNen6#gjtk3)=6&$3k; zlH%Zc`QpWsLNqkA0(hkgP*sbxc|M8$c_HBE0#f*jSOz#kKvnOP{2@+d3r%m(!EO}g9uqY7U5Rd$4ZsUn-gUd7Cn`?061&pB}Aih3`N=OlqoHy=K zaUd8E;Y=m|ca00_;6se5;FfdcELSVCv@lc`*u-k{1bg^ z4Uesf;(+k*b~q)qK(+ks9r&pkoI$mR{CK^)@el!BRSZ}lSON0}o}Dk*K|9NPl9_Ks zevbsAr%(p~UV?U~D{+7rz6sD}eL-)Es!z*+7uE(;9+n`mA6|n4zec)nia=>Uox?70 zAqf(^KD!MLUqYb&rd;ux=L&FV{oA4Qf;X20pr@8_7%7z1<-|0E6guR34UUY|PoLfe zFMS4%$oqg{=*2q=%12_r1ECo7y&F*3nXBgo-cCVque`ET(10w{c75m*)``tXjvUB- z0w$?|jg)e)BREa#A8LVAXb(`d7JnpKwEb_beRWt=Yuh~xBMc=e-AD;if+AglG=fOC zf=WxukW$hpA}C0D2tiV%VdyTAP-+MV5EwvWXnxQ59zC4zd%ypFUS5K7IeR~QKe6t0 zuY279a|z$;rcRUeBm&5`aoGXHg1s_8n`sl;0ffgQpn=F;jhBAYj~AJ37xZs`Z~%2_ zvU_YGE+idReF<=6j$#;*3Qn4=KLfDBXaj>rKf_(0DA4D*U1Gru?nfqyn$PA3t&jy1 zz%Yt44gOk;G=)GWle!E39tBJ(I4)i4ep&|rW*$V?fj1Az4S8aBM#y8f6HX!Jh} zl<7%J18r_s`=V?dE*^dm%Y~?r8__iMB_!)jfdXlbAk0qvbop`|$ zo{;eC=g8K9DXFxrQQmiojn*KH6KF^GDuhA&Arid)t2QA{zLbzOyjoQ@Kq><9;k74` z$2|OTv2zZab8UO86$3FyDUYQD3X!xGpj72fRmZpq3q&^$9?S_B#n?o;mpA$>c^g9(=hv8O|{lD<_l8 zI%=@-#FS;+6yPZMl|HXb2X9LBrhR`}B(RZS1e3W|8Kx_6x94Raj0RYcd_w+}Y$1x# z;8%{obf(MH&bI5-dO6u@ZZ&8F`2oq~y2gMK@JZ=o8Uj9ist9wKF2bz=#DVq);PxeL z_jG{a=R$A8?)uEkLL`%n@0XYs8JA{%CTbOGwN)wNHs}rVdV)*;?2P1^Snwzu8Y1;` z($oGi2;7G<74Q-}yZvy{$YFU8S_oLNI+ETf`X?>s0fpE$7BIj!OO2+7;;e6i67yN_c#CW?q}B6-hxL<3L!Y$e? zlHF{j@&PV6Li^|%V%%b?xN4&^n_M(lgMBHNXK6Go19l94Z%k|-urat*%r#P3G|ohi zQ{|MM&5vsRUgmAkdB_sTJN)fj__^Y7NSztxA3TOGd0O$tRI=a#3K18 zTal4ws|Jk?5+f~mO_m6)`14INqL2)M*m!lS zPDuK72&fKj1=3~BN5x5;3E!?zOIR=r^x9@tSx-tQ#y@xg6zx0Q`ziah3y2Ng@b9Hg z;qwV)JotCwaNKEAIOUziK2_K1=$x;|+x{U;m>P+o_8fhnOyXekTqLoGkBwK4mx-=L zM~Aqhrw(^_m?+ss?`k~=H10YJq35mgDe7@XX(RRt?zZjnWiR==4qSn?%aQ!3_ze`~ z+j#&T6x1$EYQY`xjkqNgYgLr^R=rHVCB<4S2EKSJb@cp)yn)p<<2?MKpud{BL-h^| z6bjlpDoCg2v5{#W{^o5qv?H7odVh6T9_6WtgX)qI>%RU~fQeBlV$TFn4ek#If%<(( zQv9j^M{Uxd7ootaQ^JSn7AW25?NZddnY-8`IRb3=^-$Xve4NRBqm?D%EW*Yow+laX0`cfSF>Ddz+gZ%Y%(!D#du5bq#A3>*mCyBC7bk zBS^TTh(JtsUwu`4NOM#=O}O^0o1$f@9M8irS;)@?3iPLBc`CerLmK*E`A))Ms}!-r zSI5+p(%Ff#if2|Yz&l7G0ANlymh-%-=6lV3!YhOuGE`$88O{t3#~*t*h;yF7M&ycE z4CGo)FWEBgAuAsvvPXSRI#>VSnU|v*0MJ`r9Etn=8h!;~Pzr$8*j@{G{#jqYl6Xfq z{sx*hl>8c43jdyT?T(b({Gs$ay?=kKGFvI(MwKs19}6>cY-y?RuyJ~Br_Hf*KwNCB zC(tvJgQzYrm%KE6lySV}&iX$m8MqEu$`ZTST;{Ig(9+r9LzD*G)xR*>ubY+NU}HzZ z5-|$$N|S-pEDmI- z`uRy04L=wCOxgK@j|vE+KuXI_`Nj=)fDn-IW#hU2v=%allO`d?%K3F>f>I3fR+^+g zO=Ki(e1XB{8~I#K>&|DFiEa=rG-+`W&GnlWtL~^@Ok8a#5GOj;y3sIIWfU+N+hzPkhry*5)pkRAlILa|yCyF{MAXidKy zW+N#rur43e8&UHcj4$6{TL?n{*KOAgWD^Pf>3YeH*0f;AIU+WVmp#$^r%uCy9{zBA z?KH{xlHvkpISQ;We0pt&Kf%9$4F5g@KEIN`NgND3kocH7qtA5+X94UBcWXN} zbQ*=%H3$1~Bsb8CXx?u}ep-g>{}Wsw-;u+N*)v?>3wS_2I0Rh!rUZvIBlg1@o-}~O+&BU(7d8T4AM+&I~tJ5=t4l?;atx7)4mFe)E zYAB)YWgIzYYcJGcICF|}pi1^8+ak;mouM}Z}~CJa^kk_ABYpIgk?a5tQDvsAO=RM)v|($ zl=82PA~x6t(4^_|)ar@|HJ`yG65?`Y`Dc*oAzuV_MvRpPY*o?~I#YZ=%qe$r_3LE7 z)grudWfczeYIOoNgounNP43H&$iFA486oyT_+1x$p@=*=T<-u_J_aEC9OXz#JHZr> zBhXbY%eo~TB$s?e+2!4YL51VIn$$bPN&dON85ivXaW?b0P8aKtNtF5%`5A?%ti^*c0J zFC%LHJ0zgnulVt6nZvn$=?NzBhtwdfu|XRGYlZnCpc~kF=zsmX`nEbV{SPt?l`G?K0ix;^W&fn9x(Dvn;$$ZOoxw+||*Dg{)bj0&xUhb^p4oq2o43IjA z-)HF1ZngfpVA1(%%_g5xV`MQrCE>5`%4EewJ8|9Y4e{~7J&EazYUs>K-H<`agQ?mf z)U!)==TQQt5jB{XZA&`IHHsm6wGGDg@WBcLCqt=W)cfXAKH}c>%M7(j~}Jy?qx&25)6s_;cOCLuiO zKFvotICR&XnXpk_qKmNKo-5UpmPk>2i)b1Zri~;XR^Tq@z8IEV%6;^JSfkd@C7NN*qk%&tqeA zdS^-YNWbW4jrGb~Lz6MpE}Q+$me*P;7mcn%bVjR*-!t59FU)Cden#cy^Zjd$gx@Ol zLBlo1XU`~nstuf|dsB&JW{#;Bg<5lrn(Fraj0ozkKadSDsl8yp|FWHbU{s++FsJl% zP-M~~x2hT=#d^6_XXR6t!pOv6joSqvPw#-?>Wr~U`ZYhLM~Qq`lEO{>w5|jQDArwgJ$KMpvMkSVEdNj9P=13PcAXtd&zIOogg*kg zDsl>nU?Aj0g6c$ZeE$-Q`UEL&=dG`RWLTnvh&32j0#yjgf`s4388_CMVYA4z!SAs& zFa|_z0a~ENhZbG8rH##T9`&2U(d5H;pb@$6m-nV)FuEubU%DkVtH;=Ao+|Lccm*0< zBbJbg8yU{%ES#ZlRI23*12E8wrAqj!o6ipLj9`UGyCiBnJZc~EhP&-YR9Bh z`n{o-k|EH?myLj@2T*Np61omhSY<>n41@%Ft-6ll^MEg& zx)ad^432!KxVdrwDkz8+qE%3xuAqvbb+W=EQZYsR?VBE@S&!^j!bdAH0osLy>359Vqy9v!YXst6c`)oxMa zi!B)z8CiSnfgi>mqHD>>q&I?kg!9U@bs(h2AYRP`Wth3?2I^Y_;y5@giE7FUx3PYT zByes%cl!*EkmEUV;O7YOK3c9W?FJ7_%K|S9z*sVfQdCj%%GN?x2oUZ_vOTMdY7CQa z`B9n5*tNvLSY3&*jfW`_@$=TPM{Azvc}bRo5!c@#%@^ETKl}4mhss@i>km% z$$EHpn!j$*YQktW=$grsxF|^_<6G15RD~!YMf%6Zshegwhq~D}W$#AD$fG)8+fm0% z(E*b|1umc3ybDj8BP@$uW53E6j}Pzg5e92oTi+j9lAZ6entP<|Bf-Jh+~*U=B=y}V zoeRp8qj%$PbO%%awNI0h+6ee>q55L8`kH-Cfr(`IYJQ1%?P%ztQCBk%3ZiA*30A}K zy+O;IUejKxJuzDfJIP@`?c|IPntNiC4f-G62Tdvn4Qxz- zm_QQfQZK`pl};9R%~n$oG{n-oi)T>Gvbicjj3RVHF_=)YkgD&oqe9AplYKK`M6 z^wCMEib`%a`a-^5mRMYdv{SSHHyI0NvdPDZ6p-r`_HE^AGMhhZD>g83cwMe*avn^Z zgvq{8=jtq8?uKb18C$uIft62l&0#(QuLki#c>1m>T75$uwe^?u+4H=kOMt%ed%!F$*u#w+51<8ptg0;4`UNkP-8Fl9MPBh*F zpq{_Q22#EETEG$Pxae)z#$GSrW-j0+P=Nv0){ceq<5aKL zvJ|%UK0F-h4rLbc4i0nglr_#$(OyKWa}n1@2lI15Cc_ZneYHdN22Qsd=eeo-S!3f| z`Va#SmEe@BLru6%ff(2z#c`r(008bhZA-s6g#r7O>_PFN;(4V9FRm5&GQQre*<*sB z`%i_-2yEK>#1(_G6rNE~EbXHOXb*1K*32Fo%cU^==dr~seI=15d@%kZIz6lWuPEzp znWGlOxLm|i$5-=zFI6ZHmO)RASbe1b_1ncy944!&?biQWm~@}Afra%Uc!GVCv2p=N z60%1dO12+riE+c%gvo-~Z(u1}Eb9nToSLAaJPelpIq{l{1t&*mECk!fRb=*t^n<7D z(qbFN_JE_~CVAQ}v)<);5p_{FRQOXy259d&@x?xiO(O85t{SVZ(<~R!Au87$%AxrJ z@l>{bDDm3+oBHb`hThHA=errwCvpmVFPkI^NYC!P^nrIPg4#76hTHru&!4@&JA3JZ z%eIfdj}Ldz>rq-x*%O-R!0D%Wr_3E1I&z_sNj=#!DJ2x?d?ZsQUla=*h%=o#j1n_f zKP>I(=DofBTc-3R5#%7`RVW}0vbw#1DnvcwRJ8%V!*sw~`IV&hkx0;hB{9t<0|{jqu!{F#Y1Xh)i@@R zwF|tuIDonSMd40>&cR~)1k_}jml{BEd8{EeUw$QHSicE=3KR|~ZxnCo@duXksD`?d zZM-%C5!avF#u*t@38RLe&0(b{dFvjCD7jB;Uf*oot82-vj{GOMM>fVoF7$0?F@9QY z%Osq!Iz)%$%IfStUQe>C;?~g?TN3*mN>@Mr0iUJtafC>Bo___=wPb;q5ynsRiTj1U z;?lAo)^ZG*K7?HF8O?rF{XC^?gLZ5)>w)=cbE5c$$1z;kcJ|?x0Mz%Eg$t(i`tJ64 z*RW6EDCLI-W+S0yw>Bg$`(~!->%HUon=@!q1JD_#p1zl=Ge0bk?1qX;O}J`2t_%Ta zzp%TK@YsWQ3o4ydb!E}@v_dIiud&s{MQX6#fZ4Bpn=FHc2DMgyTkbk85lg!B3z?O+ z;evnoX;BtzG?S)i*&OoZ-Vgep`UQGi?%xIhYU;gm-skQTAbio4>=J~;<<4GQ8G@^o zxCL1nFkXS1(Tab^cA~Pu0ESPB+dpzv5zyqdTO!YpL9~*wT<(U>eE?3=*0JTQgA-^Wq3Qz&AU(Ec zY5nVY8cs{_UN4TN3@%!FnSKe=GzQ9wGsD_lGgHo!^-z(^yJr{w9)K^%(Uso119AJw zwWwiJI((xLYLoZ2*inWH-_p3@q50o02=WS~11DAor4YlRz)j^s=a$!v!}dj}E_APl zIKjkznR(CW%m>n~~9Li)?Xx&EGr+JK38s~CA5 z5AfzqKy0klsq5$G7v9Thbrh(q45b4?q6=Zb&ER0?6`nQ?dxrc`%j>|6p7ympcn9vP zj1P6*T)#S#L~ybSGsE%qa@DMx!O~R)$_kT@dv@|ImQ`d##>pHM z`iJbnz7qriplD>}hq?aDN$fY|tAK)f;*UQP_wWUxaY9QhwZ&jdqAY<(Mq#z-L5ru|8VsClN>rwPpC{NcBBQ8ENdg+a#h&VtL+ofz1M_em zQ$i^rhJN%v@Xx-lWi^E8iN5d0gJ-v(3gx!4r#v_U>{fwVk&WO(i`D-%c4QP~DdQ=L z?M#)E5Vv17q|tFa(tT0LYzS_-)?RTpuJuhNjcRJUfvZLr2Y3HWB3%M`)we6Thi7x{ zd$BlSIOlLqkE=b&zLC97pFI~OB~A21#6LA>mGnj|T`4peE<=dhcv(vP;+YBSDo$uL zjT42Fe*f$7lup@C%zMKM4a2o*j6oG{OO32^I<+H)WL#?D8oL#rkc{!(yS_^2KXNTL z2)h;nO$xHbsym-r+)fnzZi;p>(Fe1(dn(fhGfpJk0bS8|3?>g z+exOkWR1Yowui^-nj+#SQ57rKrFi+$zWjsVtQ_`@xDw*7Na*_F2>?9;;s!fH8u!Gu zEE;gC{?GpGfZ&@a=|S-94G1*Xm_$QAd{BgzSkjA` zyx6V6@YP@*wHL*1vIGYi75`h)(1^Wx_2(?O7$$JB!1od#|HZvy^#@o50{c6vf6W`9 zR>0~N4Aaou|GXy!MXRwBPQcMpj5>}7?}aMAxNJaeZu+J9{WWUBrxXH*PFHG3Ud5d- zGi2S`nW#tW`w|6f_c_c}t6;JQ;1wc)ZNBmTm+$Zjp<2C~-0HKOKQ?z9Rxt# zTD&B%?J&J<*K68v9>l&WGDqjAJ5yK6*WIc~p^4-vhZgqKmlFu?WXQzI07gGUjLD7` z;x%unhU;NJ=8O*PN>{Hv?SZ=o5aE`abZo=*rJEprS%uBhR>nbJoKg_9bdrx{ zEqu!HQSZ&-vDkB}awO zt*KOtwk@bBUJos?*CX|eS`IT0WQl3m0T^4zEr;c~f zmMgxY{9awc9W9MI-QxizwrK)l`J?sshSmy9I@868QST>%UVG2PfI8iCn)eez_zBZo71D@uRIO|jON{jf-l8>4@>b|h_$DSPM>U!!Q({TOB564|LlWWB`-<+o5bzk`cYZUG=N&8Y-`W^CrllGFc z@SDR;lZCUyS}=qa-FmgT6mp@=ZN)<11Uy3!5sjd$M0i7SNEgoKST@U@vM4WB=B8#; zqEE<#NM8S#Gb#DuME7Nr;^+h;SY*-I_cY6a_`4@)JF)Mcnid?Qs*NoC%fYSVGMDS( zB`E+>@7Q!76 zGC=cQM9EYvm(gog>d7L3-~9mZ0ScdrEnA=bpO>o&_Zd}4%Am~!3cx(#RvchC1~ugG zWu1ji398fJZxFW4n1zR+^6llBd>6H7tVx}l3A#`?-o-HD9P-pSALGK{cA zY|k%|BCpIZC5BuC&)M4DV~aobJ2DefCfx_AbxL|vG8sHUWe(zNCf;Kv2fC7O>8`& z;FPn731((h2zgieO4jkKCwUvug2L^Wo!}n5r@TVc&gXV4B+FISqUL5FUeNtZk?#w7 zL-0h(mvY`Rusu|EcAL~dd9X`}vwGQppS3!I47FM!n)&yw|v1MHbA*soatNo>0dYViqW z#aw4zOOTOGyI*nUGp4?RDiIBLN~Za^q1gf-CLy(1Ol=T7UyET?h{jKHTU~h2YqCdd zB3?sg{#xcKm7D#BYw|4#Z&?=7an0(_d+59ttOPLlOMnG9@ z@NU|TN@dqEDodZnroAqMbf)PI%ek;2A;wQx0V5N-MOG}yOLwqF}`JQaiwyB#GwKRZrl&aOI&FWI}&URVxjSIzbC&t%GvqwMUgi|w21~N*@ z?&EMY3$d^s0H2k1E7WF|v`oIm$fH~`V-8M;39R&VCU!jzFG2?i$d2cI8ZUdF?O7|5 zIZk^He#{w|SIQ{z&wCs+5#b&nHt?WS&bSICQ<-@!qDBFOu25%q8)$H1umR7HWP!SyDhL4lc-H6G+JkSAALm@VFj6#nJucVC?a zm;b@IO^hq@0HgOF5|lrcAT%U#=nFMiTLI{{P_#4Q^39R=iA9XH5DodUe^IH}O( zpKX&3k_@6ZP}w&2JC6PZY4l%LO( zpR)PD#>q;v46TOBN9eYPekN=Y4KfZ^-ZPN)I5ih^2@+Bay0ZQgW@LfW@BjlNmrSCy zyud&$ZAr6pM$|1ziHixH#nuaB8b8^NVpdB11DWQi1X+SJZfPj{aGP23N~Pz!F5Z}!K$_l*i_)~?=}&hs(|n);No{1S1LUQrlfVo$ru)wPA3Xt>r!ZHD zR|#TyIIj#Oe3)eY=&;-gVJm&LFe{r*x-^gtvPRJg#er&&SIoyR>Tnl??{<=>Nk66p z0J>zQn=ygBv$IFV_MfRA9HRixywMXRus)Rl5JgE?8Sg9I9GMfKnnIQEuC2iq2hg1< zO!;GCyFd}CuYf_IHTFB_Y?v}~>40lkZX(H}0d+>aWUz4{K zWnTYBbAWxAciT4#(0j@hm6$TaA|j97wSuyEU< ztsg^IRjQBobnld>3v05=m&mJ6Lske|(e`!UVm%J+(N7RHWLMH2ldX6!YP3Aonr;!i znr69Nm)r2g=6hPu)@u{P|NhnRk-2erW#js+ApV||(=AzAgvDy!zR`Lu>+yq;GUcGd z#ZhfJxjb@Yfx@ojON47Ai3V%~4-+9W?!CXi1vJ!JdHP#)Z?^-~+kpW$f)FTD2J2jT|uo` z;Ju@jN_l~kOHH((<&)6hNn9D@vJ`=y z6XUR^Qh%>5&u-gveL@FX4*cL4?tZ+tGbTv#oDdhY!DeCAwzGA`7kdBggbV@SvEv)D zyM(y4Y_4P%9z`rE!z7HKr?)<7_@WK#wsO~2D{AdFh4initS1>==Rwxxj{fJXorRE;n%ws&oL-khV4V2Cm)Qt(f9OM4@LD z?lj=YRlvdV!dyz?4{nu%gX@-6;J_36;4)V0AJC#}o}%4~BNAx?HUH-XG-tl!l`}Do z=OC+hWpJ&%7XGu;KVk-b&NWaa$n#-B{rkJt3YyXZz?C;q0B>5fcPiGEpSly^u&!40 z02rpYde^X3lj{KOO@38GDtYFYTrd1aC8|6I6lSQ{Y>j#>sptF1AeL9&{i&1 Iw0iRY0D0GU4*&oF diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/originator-fields-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/originator-fields-ft.png index c32cca8eae0835ef46e837343ef715bd579f9a78..59919a33b4511381332430ec4dc4ca846dacce78 100644 GIT binary patch literal 75513 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

Xpc@;CYw%vzPIPex^r4oF28XR#qY) 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

mb&-AsG3o*1#CJ5GI;~zJW$R;>{JEz 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%0D*9x)l_M@)ylLouN7_fbJPfsPoiw(@4Su^Mj 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 diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/originator-telemetry-ft-3.png b/ui-ngx/src/assets/help/images/rulenode/examples/originator-telemetry-ft-3.png deleted file mode 100644 index b0dc22cf8a7c5a9c81363550f96f5aac7cec6812..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 78213 zcmbrlbySpX*ET+kBMc=&gXGYif=DwUsdP%0Aks+J(A^>-AQFN!DBT?rf+9!`4Be$P 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 UBDcdQalpTa_Z6iJBn|!lFOh^s`2YX_ diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/originator-telemetry-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/originator-telemetry-ft.png index 688654f4ee12208b5861b3c392ee8c96358c9141..b50867efbb4c0fec19ea5dd79cc2484a507390bd 100644 GIT binary patch literal 114627 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

EMHkJk`anDm80uugTPEZEkBfmxn5@34hRBe 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 literal 69883 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 R)(!zb20F%n6yflp{{@=rF=zk) diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/related-device-attributes-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/related-device-attributes-ft.png index 2dc89a27baba86bf12032f0f5711baac89808da4..484520a4fbf3aa81f1396da5064145aa012dfe4d 100644 GIT binary patch literal 93697 zcmd42=UPo=7jDqarB16GHF3Nw3LPL`tX$y{eP| z0Rn^`Lf*Ka^ZWzn%X>a0xtZTRbIn{c*IH{9(RwT1dcWMtQ?$jELY z@7y9id9+0Jg^cVunY!{Tqkx>9rJKHn;Ai~@x48xTmP*^Zy1Ev`9fChlayG=rU&9H# z(V}}6A>{C}_o-m-QqQI*_%mzh7|z2(Z9a{Yrv2Yj9~~W(Xh%oJ(bW|_+lv=^MiF_o zx0g@U*`MiJr}14oy-Dhk?EU7(Gp-DyffNf~2X%fd*p)_UW%S0BQ>f|wnvj z1-xD6&sKtA=EPNM;!UY;U-_JotN!!%FZ;^1GGXd}tfdKFT5fw3e;>VPtdaHBehbVu z`umG)=aJEvhSn{e|C-N6I!$IWQ2u@XKKG%~wZC6l74`lb$t?LRn!mr_@ZB)}`}w~1 z|Ahu;o|1nDBkO_eOJqwY2y1jYL~|G;Z+K%)tfhj_qjuy1Z8DhT`p@@2J^C*mSqU4S zTvh2wUd~dSQ}V3**G2b}Xq>6Ta;Kbdz)#>D`1}@EKlMW;i?AnWlFQ<+yJx+9m37r0 z0us)9)-Vb~KSdyH-Q88@28ciPotgNq`?(qaUCx7?cDcHLn%&KL=v z2X;I=GkZ(@QLa_K%1vX<|C13exbz=}>$0@X&sjYU6ns#6SE8unw$|5ee7ws2!aZUQ z>QWs-b#3n$$JK>7;}Ew|n&+up8FIGZWQ_ev`tnq4XLmp#+&^J;LDY7m{0)eVY^-RM zgWxdj%-BO-sewau)m9JXEZ1ro+R4f%)^2$;#ngRkc0K=iIJ%b30DS%rd8rmFVCD|_ zjnBHa86FUKdkGcAwkXFDg`)3LB5JEeQjW7j*1Ef`pN_N0!~1s0pXZc+#NGj1r#rie32vP{Knq{&=6bwCt4V`M6WQ^_~-cO!1^MF64QPzE%T zfPcXH*hqp=*3qW=L%=F*RljjL`5XE=*_%oTUr)$VZQ(-F1uD+?aN1VWI_v1ZWrrc} zuniyeMRWQ+o>1#NTXxl;^QK@n*Zp151?!D+-210myQ7sY*lEHV3tJzP5k%24Tg{>-8L#>s_S_ayFxhyHy&eoa-Y5 z$Y-q#3R90EOKm44 z1V32wAlmO_tIhhJGDoZEV$a07-as9wA?AmYFRxgku96e0vPA#Dn zT+$0_bWN?}TxYg^h7ZjiN+`32{}oVzq%UtIrUYR9GiP}eEssK`Mlb@(!DbvpMB z0AXk>T%K|_bRnDI7)`yPsj#qdHD`|qG0mS$qL@cM!lW@-Lixd>%f zP_-d%;v^|NDStxiYP|*PiDi9;6Z7$t# z04x1rabpq}Z^qWv)$;Kak=-^!bR(=Ov48MrN!2=IwVQY(DZwb+yZE3!X|SKG?5Ngw zF$BA&maq7yFW!xOB*R_mxhQ%4x)Li=`+&fDpQC4 zRUoFrh&9InYu?tM$DUU*uf*X{e>f-0TA=X^7N*J10#cVXyeGcX+DtY=2I#{u-I=HKBh>LA~DY zE2sOF6bZy7=GGbq#VVvAKf$(!$8dTt*_yU~Fedl&(kv zIYcwS8z@|UA19YBdE8;Ja6cz0J~&ZxyCk~AWN>lgfC-B=;Sjmd(GIP$hBJQ&plP<#>O!lNr)Mb!H<-|+AG~due~Mz z34q*kbl4wmNr>&76?!|+ZZpEjVjS^(QS8bazh_-(APNawl<*3no9Svv3v+H~=nO&} z$R|rN*$0byeVW9Xx({6*UpeKQ0`d^uIuUC#fT=VSg%RKGGM|w@De{iv!d()AXnj3D zlNZ6#bhe!JcRSz0&^hp%*GuWqw2?_ zzuOgjmY5Q!<+QtJh0AS&c{b3}8U;_Xdd#{$iE=}9=kGrS;2z|8pLg9~+}{PoTWvUN zZe_m&LWTueG}bas!=N0t0?XSI(iH&u^yJe8Q!tMi(h(F+*E0pkHQf%AvZ=fA$-V5c zvGgPl%Xw3oAHTpj0`M=uwhrTBT$IwU^9I&m^<;!cK!ITGv?ue(4Z~!hEYA${dONr% z?=}*M(Spa)oAN(D9@v4pHXVML63FgQHr|jW z6v#?#u7uEN4?V@G4zNE(w}dV_VZ8&f~mDWvywZJ+ttN%}3kI{$6*{%(kL zcp0`rs!*^Fh*slTr??fb9EcgUuAK5{E_PB^LX|MZYel!p$k9WfzpiRO8M#o%+KC0{b`p^&S;R##ioh)7K3=_SsQd`eNtcCM|q> z1kas-9`(Tbh$$QkSc8aW8$x} zz79@6DosRJCZJ#=om_qSt|r66SK?W37M&Z@t^j(xBJ$CL92?^6-o}LSk`{9dT+yp) ztt)3Pd(%2PD$X8#5|bX~dm9DPkv;5rP9M zK^H1jbnc`$vRyo;X2a(1i5{k$$#z^%4_o)X;o znwWwF!B0geWLvM`hTfYy9MFb$*`k8kV~_pSJq2)+#$9Xk+NZ?KTqU3~`L=KP*6HVI zWzdL2ZA##9CupS*8!Vd9(G!J`dmt}i7ri&8O8n`_$Z|Zer6~*?mG1DDc?o7#xy4cV{33LEy|Ols^4XG{UH^)Q*>sPV6``O(T^TqIMmUD9bnxwyyX%HNgJYuM&BrjL7t(ofSY)83dGJVqC33$g`Tclzj> zV5N83U9|Ie>{2ls=}dL~`%n-Ai}6Zhw{vm*y9Y5n zTi9#x3HAFU&7xOdbN;}&EBvcgYFZ9gwlt|ES`*`}u;#VqYN-(SQ~)Oc;)Vvqdh8TD ztZiBFXsK}6!@Le!7$c@teiQTWysvrDoU9S)lUX*-sEJO`H<1g9q0WuvGyQ4A`3d8I zq`@b8iHc29N#}+efEdN@Oz|aYlL#D_<(REl+bs#E=|h*=Gv;h-B~xXkFyF_A%D&J? zb1NWSE79IzP`uglu&WlF8q+jC3n)JCFUfc(^-F)G_`d9Tk%pZQaj3=8V5{d*LTI|n zC6)QbZwdohFsBIb8+=M2L;vL}X)`Ep&!j>+wfc^YW63$SKrBC=Q4Xo$lYPEhCu&4C zW|`art__PJ!>6VDS2D1&e_UE^;J)(IMlE{1(p)NA3VH&%6ptaeA4gmYzAEI>1nOz| zZI&?(=XtR6FI(c!exK#~@CaEnW_2kbq#DeW5_FwQ@+7o1TGMgF)Ow_&B6L~i$!V&s zT+Nn0SEmBApQhY9-le_j=messg<3nijU`Isb-B2U5o_C-!p+hhvVDF;=Jy#)EsEH( zds|y{W1z~8iEyqlL`IXTq5==qO=b)FgLa*P z?m=oPV0PVNy8zVSEQ^94o$WKC`b|~zvp*V^O;x}*!+dKzz>8`63GE2hcc|UFalg6aTu6Ac|En@X;U2_D52@^w{7yi1as0;vU`#1 z5RNO?BmDMf2%1e3^#NjG@8s^DQ!$*0uEo+uk}rQ57G~>&JJ(ZO)J>p@!#saSSD75y zHLaLqtl){?kwx$1`vXtLwygzk%FJMwA^A>qewQ|)s?s>avC!&UCit%~h0qoR^7gP5 z-!*W=XeE#-hiiLRoo_g>NCKTy^@KTOmP^)N154xywnwJaB0V;wrNUMdcwThxIf?#I zJ$Ikyh5Yl+F6*1z*tZ&RpMaL`FEImXrH|PbmVf%Z38!n(Tc) zz|r7zB&@gSX7-2zzV}nh(cM2olk#p_kX+Tlrz)toUC4%u-ewx7T?UrpKVp_qM$yys zQ%^r23#`KW>%%`+2<5^8;UTo1V`(ZbMD|@k39Z7D73BklQ(YTh1-)pQL8?BmY|wn{ z%$$DE%BKgXs^0^IVIEzob&kkS2TbQ+k3LWGkAtZ≫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�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 HeDQw(lBJ`W literal 60303 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 MSn_H16HWL32FVo>_W%F@ diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/related-entity-data-ft-2.png b/ui-ngx/src/assets/help/images/rulenode/examples/related-entity-data-ft-2.png deleted file mode 100644 index 36c526928d66b75fb8e3407da6aeb572a183497a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76684 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

#W9?FkJR>v1tnDZ9DMNSfC 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 z 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 BWugE8 literal 59833 zcmeFZcTiN@6F&&!kR>CCfMk#?3X(HO63IDdB?rlIKqN`dSwJM`oQEVy$w5G1NRnXy zfg$hZy{GT_t>6B;wOh4S7nr)toYQ@}PoM73r|*O+y_Ckre1M6BgoG_CBdLOf1VR8m zv*@V69m(g63&0;_XBBC2q_QFMO(Y~LBw0x@HFtxZ3>0^wUb4^aU^h2=$nxHvK}&YH_nYp+&1x1{Dd1-rPG@nA*;J4@FeJkHho z-bY{S4V>49j*~?D7e)HAK!!9YWgeG^%I+vik-lR@V5Uct@DHK)=d}Av zg0fXKEbAD&e)PTfwD}aFXDobWeFGk#A;W%0DGdVygAQ?r9}l+0KNJ$u$-p!k4In7K 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

H@iD0tRt@+ZaPfDZBPm?zWrT2W>y$|IFMAE)!b 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

diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss index fe8111afa0..a91c57ed65 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.scss @@ -17,11 +17,6 @@ :host { .mat-mdc-card.settings-card { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; margin: 8px; @media #{$mat-gt-sm} { width: 60%; @@ -30,10 +25,9 @@ margin: 0; } .notification-form { - height: calc(100% - 48px); + height: 100%; min-height: min-content; max-height: min-content; - margin-bottom: 16px; } .notification-section { height: 100%; diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts index afcc833754..8ca3eea97a 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts @@ -25,7 +25,7 @@ import { ActivatedRoute } from '@angular/router'; import { deepClone, isDefinedAndNotNull } from '@core/utils'; import { NotificationDeliveryMethod, - NotificationDeliveryMethodTranslateMap, + NotificationDeliveryMethodTranslateMap, NotificationSettingsDeliveryMethod, NotificationUserSettings } from '@shared/models/notification.models'; import { NotificationService } from '@core/http/notification.service'; @@ -40,7 +40,7 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn notificationSettings: UntypedFormGroup; - notificationDeliveryMethods = [NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.SMS, NotificationDeliveryMethod.EMAIL]; + notificationDeliveryMethods = Object.values(NotificationSettingsDeliveryMethod); notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap; allowNotificationDeliveryMethods: Array; @@ -76,6 +76,10 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn if (settings.prefs) { preparedSettings = this.prepareNotificationSettings(settings.prefs); preparedSettings.forEach((setting) => { + setting.enabledDeliveryMethods = Object.assign( + setting.enabledDeliveryMethods, + this.notificationDeliveryMethods.reduce((a, v) => ({ ...a, [v]: true}), {}) + ); notificationSettingsControls.push(this.fb.control(setting, [Validators.required])); }); } @@ -105,7 +109,7 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn if (settings) { settings.forEach((setting) => { setting.enabled = true; - setting.enabledDeliveryMethods = this.notificationDeliveryMethods; + setting.enabledDeliveryMethods = this.notificationDeliveryMethods.reduce((a, v) => ({ ...a, [v]: true}), {}); notificationSettingsControls.push(this.fb.control(setting, [Validators.required])); }); } @@ -119,7 +123,7 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn getChecked = (method: NotificationDeliveryMethod = null): boolean => { const type = this.notificationSettings.get('prefs').value; if (isDefinedAndNotNull(method)) { - return isDefinedAndNotNull(type) && type.every(resource => resource.enabledDeliveryMethods.includes(method)); + return isDefinedAndNotNull(type) && type.every(resource => resource.enabledDeliveryMethods[method]); } return isDefinedAndNotNull(type) && type.every(resource => resource.enabled); }; @@ -133,7 +137,7 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn const type = this.notificationSettings.get('prefs').value; if (isDefinedAndNotNull(type)) { const checkedResource = isDefinedAndNotNull(deliveryMethod) ? - type.filter(resource => resource.enabledDeliveryMethods.includes(deliveryMethod)) : + type.filter(resource => resource.enabledDeliveryMethods[deliveryMethod]) : type.filter(resource => resource.enabled); return checkedResource.length !== 0 && checkedResource.length !== type.length; } @@ -143,13 +147,7 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn changeInstanceTypeCheckBox = (value: boolean, deliveryMethod: NotificationDeliveryMethod = null): void => { const type = deepClone(this.notificationSettings.get('prefs').value); if (isDefinedAndNotNull(deliveryMethod)) { - type.forEach(notificationType => { - if (value && !notificationType.enabledDeliveryMethods.includes(deliveryMethod)) { - notificationType.enabledDeliveryMethods.push(deliveryMethod); - } else if (!value && notificationType.enabledDeliveryMethods.includes(deliveryMethod)) { - notificationType.enabledDeliveryMethods.splice(notificationType.enabledDeliveryMethods.indexOf(deliveryMethod), 1); - } - }); + type.forEach(notificationType => notificationType.enabledDeliveryMethods[deliveryMethod] = value); } else { type.forEach(notificationType => notificationType.enabled = value); } diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 9ba1bca7c5..c6a3253f1a 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -596,6 +596,11 @@ export interface NotificationUserSettings { export interface NotificationUserSetting { enabled: boolean; - enabledDeliveryMethods: Array; + enabledDeliveryMethods: {[key: string]: boolean}; } +export enum NotificationSettingsDeliveryMethod { + WEB = 'WEB', + SMS = 'SMS', + EMAIL = 'EMAIL' +} From 93c27eab8f6d46c3b75c327cd12a0c79391f4566 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 17 Jul 2023 15:58:01 +0300 Subject: [PATCH 270/421] UI: Change check connectivity dialog title and fix state --- ...e-check-connectivity-dialog.component.html | 6 +++--- ...ice-check-connectivity-dialog.component.ts | 19 ++++++++++++++++--- .../device/devices-table-config.resolver.ts | 4 ++-- .../assets/locale/locale.constant-en_US.json | 1 + 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html index 75e8887da6..a0991570eb 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html @@ -16,7 +16,7 @@ --> -

device.connectivity.check-connectivity

+

{{ dialogTitle }}

+ (click)="close()">{{ closeButtonLabel | translate }}

7=_HYoP$BYVE!nEx=UAt%=LeWRShAmnms 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 Date: Mon, 17 Jul 2023 11:49:06 +0300 Subject: [PATCH 267/421] UI: Change units models --- ui-ngx/src/assets/locale/locale.constant-en_US.json | 3 +-- ui-ngx/src/assets/model/units.json | 9 ++------- 2 files changed, 3 insertions(+), 9 deletions(-) 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 c849b3379c..fd63a8f708 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3931,7 +3931,7 @@ "kelvin": "Kelvin", "rankine": "Rankine", "fahrenheit": "Fahrenheit", - "percentage": "Percentage", + "percent": "Percent", "meter-per-second": "Meter per Second", "kilometer-per-hour": "Kilometer per Hour", "foot-per-second": "Foot per Second", @@ -4099,7 +4099,6 @@ "millimole": "Millimole", "kilomole": "Kilomole", "mole-per-cubic-meter": "Mole per Cubic Meter", - "battery": "Battery", "rssi": "RSSI", "ppm": "Parts Per Million", "ppb": "Parts Per Billion", diff --git a/ui-ngx/src/assets/model/units.json b/ui-ngx/src/assets/model/units.json index ecbda65cca..720719b366 100644 --- a/ui-ngx/src/assets/model/units.json +++ b/ui-ngx/src/assets/model/units.json @@ -1106,9 +1106,9 @@ "tags": ["concentration","amount of substance","mole per cubic meter","mol/m³"] }, { - "name": "unit.battery", + "name": "unit.percent", "symbol": "%", - "tags": ["power source","state of charge (SoC)","battery","battery level","level","humidity","moisture", + "tags": ["power source","state of charge (SoC)","battery","battery level","level","humidity","moisture","percentage", "relative humidity","water content","soil moisture","irrigation","water in soil","soil water content","VWC", "Volumetric Water Content","Total Harmonic Distortion","THD","power quality","UV Transmittance","%"] }, @@ -1453,11 +1453,6 @@ "symbol": "richter", "tags": ["earthquake","seismic activity","richter"] }, - { - "name": "unit.percentage", - "symbol": "%", - "tags": ["percentage"] - }, { "name": "unit.second", "symbol": "s", From df9ec02bbc2d97ec8616b623956ebdcaf57fd70c Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 17 Jul 2023 12:30:52 +0300 Subject: [PATCH 268/421] UI: Optimize rxjs observable in unit selector --- .../shared/components/unit-input.component.ts | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/ui-ngx/src/app/shared/components/unit-input.component.ts b/ui-ngx/src/app/shared/components/unit-input.component.ts index 8700151c69..01a5db32d0 100644 --- a/ui-ngx/src/app/shared/components/unit-input.component.ts +++ b/ui-ngx/src/app/shared/components/unit-input.component.ts @@ -16,9 +16,9 @@ import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { ControlValueAccessor, FormBuilder, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { EMPTY, Observable, of, ReplaySubject, switchMap } from 'rxjs'; +import { Observable, of, shareReplay, switchMap } from 'rxjs'; import { searchUnits, Unit, unitBySymbol } from '@shared/models/unit.models'; -import { map, mergeMap, share, startWith, tap } from 'rxjs/operators'; +import { map, mergeMap, tap } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; import { ResourcesService } from '@core/services/resources.service'; @@ -75,17 +75,16 @@ export class UnitInputComponent implements ControlValueAccessor, OnInit { this.updateView(value); }), map(value => (value as Unit)?.symbol ? (value as Unit).symbol : (value ? value as string : '')), - mergeMap(symbol => this.fetchUnits(symbol) ) + mergeMap(symbol => this.fetchUnits(symbol)) ); } writeValue(symbol?: string): void { this.searchText = ''; this.modelValue = symbol; - EMPTY.pipe( - startWith(''), - switchMap(() => symbol - ? this.unitsConstant().pipe(map(units => unitBySymbol(units, symbol) ?? symbol)) + of(symbol).pipe( + switchMap(value => value + ? this.unitsConstant().pipe(map(units => unitBySymbol(units, value) ?? value)) : of(null)) ).subscribe(result => { this.unitsFormControl.patchValue(result, {emitEvent: false}); @@ -158,12 +157,7 @@ export class UnitInputComponent implements ControlValueAccessor, OnInit { name: this.translate.instant(u.name), tags: u.tags }))), - share({ - connector: () => new ReplaySubject(1), - resetOnError: false, - resetOnComplete: false, - resetOnRefCountZero: false - }) + shareReplay(1) ); } return this.fetchUnits$; From 23880ad07783177516644222d16c391b01744cf2 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 17 Jul 2023 12:40:15 +0300 Subject: [PATCH 269/421] UI: Refactoring --- .../notification-setting-form.component.ts | 25 ++++++++++--------- .../notification-settings.component.html | 18 ++++++------- .../notification-settings.component.scss | 8 +----- .../notification-settings.component.ts | 22 ++++++++-------- .../app/shared/models/notification.models.ts | 7 +++++- 5 files changed, 39 insertions(+), 41 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts index 9e8df2e107..0a96e1ed6a 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.ts @@ -20,7 +20,7 @@ import { UtilsService } from '@core/services/utils.service'; import { isDefinedAndNotNull } from '@core/utils'; import { Subscription } from 'rxjs'; import { - NotificationDeliveryMethod, + NotificationDeliveryMethod, NotificationSettingsDeliveryMethod, NotificationTemplateTypeTranslateMap, NotificationUserSetting } from '@shared/models/notification.models'; @@ -47,8 +47,8 @@ export class NotificationSettingFormComponent implements ControlValueAccessor, O notificationSettingsFormGroup: UntypedFormGroup; - notificationDeliveryMethod = NotificationDeliveryMethod; - notificationDeliveryMethodMap = [NotificationDeliveryMethod.WEB, NotificationDeliveryMethod.SMS, NotificationDeliveryMethod.EMAIL]; + notificationDeliveryMethod = NotificationSettingsDeliveryMethod; + notificationDeliveryMethodMap = Object.values(NotificationSettingsDeliveryMethod); notificationTemplateTypeTranslateMap = NotificationTemplateTypeTranslateMap; private propagateChange = null; @@ -67,11 +67,17 @@ export class NotificationSettingFormComponent implements ControlValueAccessor, O } ngOnInit() { + const deliveryMethod = {}; + this.notificationDeliveryMethodMap.forEach(value => { + deliveryMethod[value] = true; + }); this.notificationSettingsFormGroup = this.fb.group( { name: [''], enabled: [true], - enabledDeliveryMethods: [] + enabledDeliveryMethods: this.fb.group({ + ...deliveryMethod + }) }); this.valueChange$ = this.notificationSettingsFormGroup.valueChanges.subscribe(() => { this.updateModel(); @@ -99,17 +105,12 @@ export class NotificationSettingFormComponent implements ControlValueAccessor, O } getChecked(deliveryMethod: NotificationDeliveryMethod): boolean { - return this.notificationSettingsFormGroup.get('enabledDeliveryMethods').value.includes(deliveryMethod); + return this.notificationSettingsFormGroup.get('enabledDeliveryMethods').get(deliveryMethod).value; } toggleDeliviryMethod(deliveryMethod: NotificationDeliveryMethod) { - const enabledDeliveryMethods = this.notificationSettingsFormGroup.get('enabledDeliveryMethods').value; - if (enabledDeliveryMethods.includes(deliveryMethod)) { - enabledDeliveryMethods.splice(enabledDeliveryMethods.indexOf(deliveryMethod), 1); - } else { - enabledDeliveryMethods.push(deliveryMethod); - } - this.notificationSettingsFormGroup.get('enabledDeliveryMethods').patchValue(enabledDeliveryMethods); + this.notificationSettingsFormGroup.get('enabledDeliveryMethods').get(deliveryMethod) + .patchValue(!this.notificationSettingsFormGroup.get('enabledDeliveryMethods').get(deliveryMethod).value); } writeValue(value: NotificationUserSetting): void { diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html index a3de925dd7..8f7a421a82 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html @@ -16,7 +16,7 @@ -->

diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts index 9e1639740e..8a427512aa 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts @@ -42,10 +42,11 @@ import { } from '@shared/models/device.models'; import { UserSettingsService } from '@core/http/user-settings.service'; import { ActionPreferencesUpdateUserSettings } from '@core/auth/auth.actions'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; export interface DeviceCheckConnectivityDialogData { deviceId: EntityId; - showDontShowAgain: boolean; + afterAdd: boolean; } @Component({ selector: 'tb-device-check-connectivity-dialog', @@ -70,7 +71,9 @@ export class DeviceCheckConnectivityDialogComponent extends DeviceTransportType = DeviceTransportType; deviceTransportTypeTranslationMap = deviceTransportTypeTranslationMap; - showDontShowAgain = this.data.showDontShowAgain; + showDontShowAgain: boolean; + dialogTitle: string; + closeButtonLabel: string; notShowAgain = false; @@ -90,6 +93,16 @@ export class DeviceCheckConnectivityDialogComponent extends private userSettingsService: UserSettingsService, private zone: NgZone) { super(store, router, dialogRef); + + if (this.data.afterAdd) { + this.dialogTitle = 'device.connectivity.device-created-check-connectivity'; + this.closeButtonLabel = 'action.skip'; + this.showDontShowAgain = true; + } else { + this.dialogTitle = 'device.connectivity.check-connectivity'; + this.closeButtonLabel = 'action.close'; + this.showDontShowAgain = false; + } } ngOnInit() { @@ -156,7 +169,7 @@ export class DeviceCheckConnectivityDialogComponent extends (data) => { this.latestTelemetry = data.reduce>((accumulator, item) => { if (item.key === 'active') { - this.status = item.value; + this.status = coerceBooleanProperty(item.value); } else if (item.lastUpdateTs > this.currentTime) { accumulator.push(item); } diff --git a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts index 1c81d3da9b..6682e87551 100644 --- a/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/device/devices-table-config.resolver.ts @@ -720,7 +720,7 @@ export class DevicesTableConfigResolver implements Resolve Date: Mon, 17 Jul 2023 16:28:17 +0300 Subject: [PATCH 271/421] UI: Refactoring tables --- .../home/components/entity/entities-table.component.html | 4 ++-- .../components/widget/lib/alarms-table-widget.component.html | 4 ++-- .../components/widget/lib/alarms-table-widget.component.ts | 4 ++-- .../widget/lib/entities-table-widget.component.html | 4 ++-- .../components/widget/lib/entities-table-widget.component.ts | 4 ++-- .../alarm/alarms-table-widget-settings.component.html | 4 ++-- .../settings/alarm/alarms-table-widget-settings.component.ts | 4 ++-- .../cards/entities-table-widget-settings.component.html | 4 ++-- .../cards/entities-table-widget-settings.component.ts | 4 ++-- .../cards/timeseries-table-widget-settings.component.html | 4 ++-- .../cards/timeseries-table-widget-settings.component.ts | 4 ++-- .../modules/home/components/widget/lib/table-widget.models.ts | 2 +- .../widget/lib/timeseries-table-widget.component.html | 4 ++-- .../widget/lib/timeseries-table-widget.component.ts | 4 ++-- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index 65f4bed2ae..3b539cdba5 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -218,7 +218,7 @@ -
+
-
+
-
+
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts index 6bd7d62c12..223cf93e77 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts @@ -47,7 +47,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent enableFilter: true, enableStickyHeader: true, enableStickyAction: true, - collapseCellActions: true, + showCellActionsMenu: true, reserveSpaceForHiddenAction: 'true', displayDetails: true, allowAcknowledgment: true, @@ -70,7 +70,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent enableFilter: [settings.enableFilter, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], - collapseCellActions: [settings.collapseCellActions, []], + showCellActionsMenu: [settings.showCellActionsMenu, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], displayDetails: [settings.displayDetails, []], allowAcknowledgment: [settings.allowAcknowledgment, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html index 818b18e6ad..f8867b9f6a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html @@ -66,8 +66,8 @@ {{ 'widgets.table.enable-sticky-action' | translate }} - - {{ 'widgets.table.collapse-cell-actions-mobile' | translate }} + + {{ 'widgets.table.show-cell-actions-menu-mobile' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts index f73a86069e..402d6bba4f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts @@ -45,7 +45,7 @@ export class EntitiesTableWidgetSettingsComponent extends WidgetSettingsComponen enableSelectColumnDisplay: true, enableStickyHeader: true, enableStickyAction: true, - collapseCellActions: true, + showCellActionsMenu: true, reserveSpaceForHiddenAction: 'true', displayEntityName: true, entityNameColumnTitle: '', @@ -67,7 +67,7 @@ export class EntitiesTableWidgetSettingsComponent extends WidgetSettingsComponen enableSelectColumnDisplay: [settings.enableSelectColumnDisplay, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], - collapseCellActions: [settings.collapseCellActions, []], + showCellActionsMenu: [settings.showCellActionsMenu, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], displayEntityName: [settings.displayEntityName, []], entityNameColumnTitle: [settings.entityNameColumnTitle, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index bb286c83a7..170d460f92 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -39,8 +39,8 @@ {{ 'widgets.table.enable-sticky-action' | translate }} - - {{ 'widgets.table.collapse-cell-actions-mobile' | translate }} + + {{ 'widgets.table.show-cell-actions-menu-mobile' | translate }} widgets.table.hidden-cell-button-display-mode diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts index edec3990e5..eaa86f6503 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.ts @@ -44,7 +44,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon enableSelectColumnDisplay: true, enableStickyHeader: true, enableStickyAction: true, - collapseCellActions: true, + showCellActionsMenu: true, reserveSpaceForHiddenAction: 'true', showTimestamp: true, showMilliseconds: false, @@ -64,7 +64,7 @@ export class TimeseriesTableWidgetSettingsComponent extends WidgetSettingsCompon enableSelectColumnDisplay: [settings.enableSelectColumnDisplay, []], enableStickyHeader: [settings.enableStickyHeader, []], enableStickyAction: [settings.enableStickyAction, []], - collapseCellActions: [settings.collapseCellActions, []], + showCellActionsMenu: [settings.showCellActionsMenu, []], reserveSpaceForHiddenAction: [settings.reserveSpaceForHiddenAction, []], showTimestamp: [settings.showTimestamp, []], showMilliseconds: [settings.showMilliseconds, []], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts index 9de4601e02..be447d1dde 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/table-widget.models.ts @@ -33,7 +33,7 @@ export interface TableWidgetSettings { enableSearch: boolean; enableSelectColumnDisplay: boolean; enableStickyAction: boolean; - collapseCellActions: boolean; + showCellActionsMenu: boolean; enableStickyHeader: boolean; displayPagination: boolean; defaultPageSize: number; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html index 633b1c7455..655c23bfcf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html @@ -67,7 +67,7 @@ -
+
-
+
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[ie,le,se],this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([D.required]),this.createAlarmConfigForm.get("severity").setValidators([D.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.createAlarmConfigForm.get("scriptLang").value,t=e===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",n=e===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",r=this.createAlarmConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.createAlarmConfigForm.get(t).setValue(e)}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:et,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[D.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([D.required,D.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([D.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,D.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,D.required]})}}e("DeviceProfileConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ot extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d,this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[D.required,D.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[D.required,D.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(){const e=this.generatorConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",r=this.generatorConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.generatorConfigForm.get(t).setValue(e)}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var at;e("GeneratorConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ot,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:Y.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(at||(at={}));const it=new Map([[at.CUSTOMER,"tb.rulenode.originator-customer"],[at.TENANT,"tb.rulenode.originator-tenant"],[at.RELATED,"tb.rulenode.originator-related"],[at.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[at.ENTITY,"tb.rulenode.originator-entity"]]);var lt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(lt||(lt={}));const st=new Map([[lt.CIRCLE,"tb.rulenode.perimeter-circle"],[lt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var mt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(mt||(mt={}));const ut=new Map([[mt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[mt.SECONDS,"tb.rulenode.time-unit-seconds"],[mt.MINUTES,"tb.rulenode.time-unit-minutes"],[mt.HOURS,"tb.rulenode.time-unit-hours"],[mt.DAYS,"tb.rulenode.time-unit-days"]]);var pt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(pt||(pt={}));const dt=new Map([[pt.METER,"tb.rulenode.range-unit-meter"],[pt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[pt.FOOT,"tb.rulenode.range-unit-foot"],[pt.MILE,"tb.rulenode.range-unit-mile"],[pt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var ct;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(ct||(ct={}));const ft=new Map([[ct.ID,"tb.rulenode.entity-details-id"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var gt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(gt||(gt={}));const yt=new Map([[gt.FIRST,"tb.rulenode.first"],[gt.LAST,"tb.rulenode.last"],[gt.ALL,"tb.rulenode.all"]]),xt=new Map([[gt.FIRST,"tb.rulenode.first-mode-hint"],[gt.LAST,"tb.rulenode.last-mode-hint"],[gt.ALL,"tb.rulenode.all-mode-hint"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const Ct=new Map([[ht.ATTRIBUTES,"tb.rulenode.attributes"],[ht.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[ht.FIELDS,"tb.rulenode.fields"]]),vt=new Map([[ht.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[ht.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[ht.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),Ft=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var Lt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(Lt||(Lt={}));const kt=new Map([[Lt.STANDARD,"tb.rulenode.sqs-queue-standard"],[Lt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Tt=["anonymous","basic","cert.PEM"],It=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Nt=["sas","cert.PEM"],St=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var qt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(qt||(qt={}));const Mt=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],At=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Gt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Gt||(Gt={}));const Et=new Map([[Gt.CUSTOM,{value:Gt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Gt.ADD,{value:Gt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Gt.SUB,{value:Gt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Gt.MULT,{value:Gt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Gt.DIV,{value:Gt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Gt.SIN,{value:Gt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.SINH,{value:Gt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Gt.COS,{value:Gt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.COSH,{value:Gt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Gt.TAN,{value:Gt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Gt.TANH,{value:Gt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ACOS,{value:Gt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Gt.ASIN,{value:Gt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN,{value:Gt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN2,{value:Gt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Gt.EXP,{value:Gt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Gt.EXPM1,{value:Gt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Gt.SQRT,{value:Gt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Gt.CBRT,{value:Gt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Gt.GET_EXP,{value:Gt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Gt.HYPOT,{value:Gt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Gt.LOG,{value:Gt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG10,{value:Gt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG1P,{value:Gt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Gt.CEIL,{value:Gt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR,{value:Gt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR_DIV,{value:Gt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Gt.FLOOR_MOD,{value:Gt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Gt.ABS,{value:Gt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Gt.MIN,{value:Gt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Gt.MAX,{value:Gt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Gt.POW,{value:Gt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Gt.SIGNUM,{value:Gt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Gt.RAD,{value:Gt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Gt.DEG,{value:Gt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Dt,Vt,wt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Dt||(Dt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Vt||(Vt={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(wt||(wt={}));const Pt=new Map([[wt.DATA,"tb.rulenode.message"],[wt.METADATA,"tb.rulenode.metadata"]]),Rt=new Map([[Dt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Dt.TIME_SERIES,"tb.rulenode.time-series-type"],[Dt.CONSTANT,"tb.rulenode.constant-type"],[Dt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Dt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),Ot=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Ht,Kt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Ht||(Ht={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Kt||(Kt={}));const Bt=new Map([[Ht.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Ht.SERVER_SCOPE,"tb.rulenode.server-scope"],[Ht.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ut extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt,this.timeUnits=Object.keys(mt),this.timeUnitsTranslationMap=ut}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[D.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[D.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoActionConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",Ut),Ut.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ut.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ut,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ut,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zt extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.logConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",r=this.logConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.logConfigForm.get(t).setValue(e)}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class _t extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[D.required,D.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[D.required]]})}}e("MsgCountConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_t,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([D.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([D.required,D.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $t extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]]})}}e("PushToCloudConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]]})}}e("PushToEdgeConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[D.required,D.min(0)]]})}}e("RpcRequestConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[D.required]],value:["",[D.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigOldComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:w,useExisting:a((()=>Wt)),multi:!0},{provide:P,useExisting:a((()=>Wt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:w,useExisting:a((()=>Wt)),multi:!0},{provide:P,useExisting:a((()=>Wt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Xt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[D.required,D.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[D.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Zt extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[D.required,D.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zt,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class en extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[D.required,D.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:en,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[ie,le,se]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],keys:[e?e.keys:null,[D.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class nn extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=Et,this.ArgumentType=Dt,this.attributeScopeMap=Bt,this.argumentTypeResultMap=Rt,this.arguments=Object.values(Dt),this.attributeScope=Object.values(Ht),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),n=this.createArgumentControl(null,t.length);t.push(n,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Gt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([D.minLength(this.minArgs),D.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!1}),n.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Dt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Dt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Ot[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:w,useExisting:a((()=>nn)),multi:!0},{provide:P,useExisting:a((()=>nn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"],dependencies:[{kind:"directive",type:H.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:xe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:xe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:be.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:be.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:be.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:w,useExisting:a((()=>nn)),multi:!0},{provide:P,useExisting:a((()=>nn)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class rn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...Et.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(he((e=>{let t;t="string"==typeof e&&Gt[e]?Gt[e]:null,this.updateView(t)})),Ce((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=Et.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rn,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:w,useExisting:a((()=>rn)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:w,useExisting:a((()=>rn)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class on extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Gt,this.ArgumentTypeResult=Vt,this.argumentTypeResultMap=Rt,this.attributeScopeMap=Bt,this.argumentsResult=Object.values(Vt),this.attributeScopeResult=Object.values(Kt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[D.required]],arguments:[e?e.arguments:null,[D.required]],customFunction:[e?e.customFunction:"",[D.required]],result:this.fb.group({type:[e?e.result.type:null,[D.required]],attributeScope:[e?e.result.attributeScope:null,[D.required]],key:[e?e.result.key:"",[D.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result.type").value;t===Gt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Vt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:on,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:nn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:rn,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class an{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[D.required,D.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(he((e=>{this.updateView(e)})),Ce((e=>e||"")),ve((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,Ne(this.messageTypes).pipe(Ce((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:an,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:w,useExisting:a((()=>an)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:w,useExisting:a((()=>an)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}]}});class ln extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new Se,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=gt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=yt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[Z(e?.interval)?e.interval:null,[D.required,D.min(1)]],strategy:[Z(e?.strategy)?e.strategy:null,[D.required]],outMsgType:[Z(e?.outMsgType)?e.outMsgType:null,[D.required]],queueName:[Z(e?.queueName)?e.queueName:null,[D.required]],maxPendingMsgs:[Z(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e3)]],maxRetries:[Z(e?.maxRetries)?e.maxRetries:null,[D.required,D.min(0),D.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ln,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Y.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:qe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:qe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:qe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:qe.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:an,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class sn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sn,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:w,useExisting:a((()=>sn)),multi:!0},{provide:P,useExisting:a((()=>sn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),Ae([h()],sn.prototype,"disabled",void 0),Ae([h()],sn.prototype,"uniqueKeyValuePairValidator",void 0),Ae([h()],sn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:w,useExisting:a((()=>sn)),multi:!0},{provide:P,useExisting:a((()=>sn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class mn{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new Se}ngOnInit(){this.slideToggleControlGroup=this.fb.group({slideToggleControl:[null,[]]}),this.slideToggleControlGroup.get("slideToggleControl").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.slideToggleControlGroup.get("slideToggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.slideToggleControlGroup.disable({emitEvent:!1}):this.slideToggleControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SlideToggleComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mn,selector:"tb-slide-toggle",inputs:{slideToggleName:"slideToggleName",slideToggleTooltip:"slideToggleTooltip"},providers:[{provide:w,useExisting:a((()=>mn)),multi:!0}],ngImport:t,template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"],dependencies:[{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Ve.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-slide-toggle",providers:[{provide:w,useExisting:a((()=>mn)),multi:!0}],template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{slideToggleName:[{type:i}],slideToggleTooltip:[{type:i}]}});class un extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],relationType:[null],deviceTypes:[null,[D.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:un,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:w,useExisting:a((()=>un)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["label","required","disabled","entityType"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:w,useExisting:a((()=>un)),multi:!0}],template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class pn{constructor(){this.required=!1}}e("FieldsetComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,deps:[],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pn,selector:"tb-fieldset-component",inputs:{label:"label",required:"required"},ngImport:t,template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]}]}),Ae([h()],pn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-fieldset-component",template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],propDecorators:{label:[{type:i}],required:[{type:i}]}});class dn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:w,useExisting:a((()=>dn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:w,useExisting:a((()=>dn)),multi:!0}],template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class cn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[ie,le,se],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(C))this.messageTypesList.push({name:v.get(C[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Le(""),Ce((e=>e||"")),ve((e=>this.fetchMessageTypes(e))),ke())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Ne(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,deps:[{token:G.Store},{token:j.TranslateService},{token:F.TruncatePipe},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:w,useExisting:a((()=>cn)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n \n \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:w,useExisting:a((()=>cn)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n \n \n \n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:F.TruncatePipe},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=Tt,this.credentialsTypeTranslationsMap=It,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[D.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){Z(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([D.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[D.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(D.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:w,useExisting:a((()=>fn)),multi:!0},{provide:P,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:H.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:qe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:qe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:qe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:qe.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:qe.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:w,useExisting:a((()=>fn)),multi:!0},{provide:P,useExisting:a((()=>fn)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class gn{constructor(e,t,n){this.store=e,this.fb=t,this.translate=n,this.destroy$=new Se,this.selectOptions=[];for(const e of Pt.keys())this.selectOptions.push({value:e,name:this.translate.instant(Pt.get(e))})}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.chipControlGroup.disable({emitEvent:!1}):this.chipControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:w,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:w,useExisting:a((()=>gn)),multi:!0}],template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]},propDecorators:{labelText:[{type:i}]}});class yn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Se,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.updateModel()}))}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value){const n=this.selectOptions.find((t=>t.value===e.key));n&&t.push(n)}const n=[];for(const r of this.selectOptions)Z(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[D.required]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.controls[e.length-1])}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Fe(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,deps:[{token:G.Store},{token:j.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:w,useExisting:a((()=>yn)),multi:!0},{provide:P,useExisting:a((()=>yn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:ye.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),Ae([h()],yn.prototype,"disabled",void 0),Ae([h()],yn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:w,useExisting:a((()=>yn)),multi:!0},{provide:P,useExisting:a((()=>yn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class xn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=ce(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigOldComponent",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:w,useExisting:a((()=>xn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:w,useExisting:a((()=>xn)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class bn{constructor(e,t,n){this.store=e,this.translate=t,this.fb=n,this.destroy$=new Se,this.separatorKeysCodes=[ie,le,se]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]}),this.attributeControlGroup.valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.attributeControlGroup.patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}removeKey(e,t){const n=this.attributeControlGroup.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.attributeControlGroup.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.attributeControlGroup.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.attributeControlGroup.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}clearChipGrid(e){this.attributeControlGroup.get(e).patchValue([],{emitEvent:!0})}}e("SelectAttributesComponent",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:bn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:w,useExisting:a((()=>bn)),multi:!0}],ngImport:t,template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:w,useExisting:a((()=>bn)),multi:!0}],template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class hn{}e("RulenodeCoreConfigCommonModule",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),hn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:hn,declarations:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn],imports:[K,L,Me],exports:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn]}),hn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,imports:[K,L,Me]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,decorators:[{type:l,args:[{declarations:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn],imports:[K,L,Me],exports:[sn,un,dn,cn,fn,Je,nn,rn,an,Wt,gn,mn,yn,pn,xn,bn]}]}]});class Cn{}e("RuleNodeCoreConfigActionModule",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Cn,declarations:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln],imports:[K,L,Me,hn],exports:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln]}),Cn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,imports:[K,L,Me,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,decorators:[{type:l,args:[{declarations:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln],imports:[K,L,Me,hn],exports:[tn,We,Zt,Yt,zt,Ye,Ze,et,tt,jt,nt,ot,Ut,_t,Jt,Xt,en,Xe,rt,Qt,$t,on,ln]}]}]});class vn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[ie,le,se]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[D.min(0),D.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:Z(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:Z(e?.outputValueKey)?e.outputValueKey:null,useCache:!Z(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!Z(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:Z(e?.periodValueKey)?e.periodValueKey:null,round:Z(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!Z(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return ee(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([D.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:vn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"],dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of Ct.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ct.get(e))})}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,ee(e)}toggleChange(e){this.customerAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=Z(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:Z(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=Z(e?.attrMapping)?e.attrMapping:Z(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:sn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[D.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return te(e)&&(e.attributesControl={clientAttributeNames:Z(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:Z(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:Z(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:Z(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!Z(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:Z(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!Z(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ln,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:un,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.entityDetailsTranslationsMap=ft,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(ct))this.entityDetailsList.push(ct[e]);this.detailsFormControl=new R(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(Le(""),Ce((e=>e||"")),ve((e=>this.fetchEntityDetails(e))),ke())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],t=Z(e?.addToMetadata)?e.addToMetadata?wt.METADATA:wt.DATA:e?.fetchTo?e.fetchTo:wt.DATA,{detailsList:Z(e?.detailsList)?e.detailsList:null,fetchTo:t}}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[D.required]],fetchTo:[e.fetchTo,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(ft.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(this.entityDetailsList.filter((t=>this.translate.instant(ft.get(ct[t])).toUpperCase().includes(e))))}return Ne(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clearChipGrid(){this.detailsList=[],this.entityDetailsConfigForm.get("detailsList").patchValue([],{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kn,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]},propDecorators:{detailsInput:[{type:o,args:["detailsInput",{static:!1}]}]}});class Tn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[ie,le,se],this.aggregationTypes=k,this.aggregations=Object.keys(k),this.aggregationTypesTranslations=T,this.fetchMode=gt,this.samplingOrders=Object.keys(bt),this.samplingOrdersTranslate=Ft,this.timeUnits=Object.values(mt),this.timeUnitsTranslationMap=ut,this.deduplicationStrategiesHintTranslations=xt,this.headerOptions=[],this.timeUnitMap={[mt.MILLISECONDS]:1,[mt.SECONDS]:1e3,[mt.MINUTES]:6e4,[mt.HOURS]:36e5,[mt.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null;for(const e of yt.keys())this.headerOptions.push({value:e,name:this.translate.instant(yt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[]],aggregation:[e.aggregation,[D.required]],fetchMode:[e.fetchMode,[D.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}toggleChange(e){this.getTelemetryFromDatabaseConfigForm.get("fetchMode").patchValue(e,{emitEvent:!0})}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,delete e.interval,ee(e)}prepareInputConfig(e){return te(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:Z(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:Z(e?.aggregation)?e.aggregation:k.NONE,fetchMode:Z(e?.fetchMode)?e.fetchMode:gt.FIRST,orderBy:Z(e?.orderBy)?e.orderBy:bt.ASC,limit:Z(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!Z(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:Z(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:Z(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:mt.MINUTES,endInterval:Z(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:Z(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:mt.MINUTES},startIntervalPattern:Z(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:Z(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===gt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([D.required,D.min(2),D.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}}e("GetTelemetryFromDatabaseConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tn,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:oe.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ge.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class In extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return te(e)&&(e.attributesControl={clientAttributeNames:Z(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:Z(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:Z(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:Z(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!Z(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA,tellFailureIfAbsent:!!Z(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:Z(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,deps:[{token:G.Store},{token:j.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:In,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.FormBuilder}]}});class Nn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of Object.keys(I))this.originatorFields.push({value:I[e].value,name:this.translate.instant(I[e].name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return ee(e)}prepareInputConfig(e){return{dataMapping:Z(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:Z(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[D.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:mn,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class Sn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=ht,this.msgMetadataLabelTranslations=vt,this.originatorFields=[],this.fetchToData=[],this.destroy$=new Se,this.defaultKvMap={serialNumber:"sn"},this.defaultSvMap={[I.name.value]:`relatedEntity${this.translate.instant(I.name.name)}`},this.dataToFetchPrevValue="";for(const e of Object.keys(I))this.originatorFields.push({value:I[e].value,name:this.translate.instant(I[e].name)});for(const e of Ct.keys())this.fetchToData.push({value:e,name:this.translate.instant(Ct.get(e))})}toggleChange(e){this.relatedAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,ee(e)}prepareInputConfig(e){let t;return Z(e?.telemetry)?this.dataToFetchPrevValue=e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:this.dataToFetchPrevValue=Z(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,t=Z(e?.attrMapping)?e.attrMapping:Z(e?.dataMapping)?e.dataMapping:null,{relationsQuery:Z(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:this.dataToFetchPrevValue,dataMapping:t,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[D.required]],dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Fe(this.destroy$)).subscribe((e=>{e===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultSvMap,{emitEvent:!1}),e!==ht.FIELDS&&this.dataToFetchPrevValue===ht.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultKvMap,{emitEvent:!1}),this.dataToFetchPrevValue=e}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sn,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:sn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class qn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of Ct.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(Ct.get(e))})}configForm(){return this.tenantAttributesConfigForm}toggleChange(e){this.tenantAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=Z(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:Z(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=Z(e?.attrMapping)?e.attrMapping:Z(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,deps:[{token:G.Store},{token:E.FormBuilder},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qn,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Oe.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","options","name","useSelectOnMdLg","ignoreMdLgSize","appearance"],outputs:["valueChange"]},{kind:"component",type:sn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:pn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:j.TranslateService}]}});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:Z(e?.fetchTo)?e.fetchTo:wt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class An{}e("RulenodeCoreConfigEnrichmentModule",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,deps:[],target:t.ɵɵFactoryTarget.NgModule}),An.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:An,declarations:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn],imports:[K,L,hn],exports:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn]}),An.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,decorators:[{type:l,args:[{declarations:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn],imports:[K,L,hn],exports:[Fn,kn,Ln,In,Nn,Tn,Sn,qn,vn,Mn]}]}]});class Gn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Nt,this.azureIotHubCredentialsTypeTranslationsMap=St}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[D.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[D.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([D.required]);break;case"cert.PEM":t.get("privateKey").setValidators([D.required]),t.get("privateKeyFileName").setValidators([D.required]),t.get("cert").setValidators([D.required]),t.get("certFileName").setValidators([D.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Gn,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:H.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:H.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:qe.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:qe.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:qe.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:qe.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:qe.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=Mt,this.ToByteStandartCharsetTypeTranslationMap=At}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[D.required]],retries:[e?e.retries:null,[D.min(0)]],batchSize:[e?e.batchSize:null,[D.min(0)]],linger:[e?e.linger:null,[D.min(0)]],bufferMemory:[e?e.bufferMemory:null,[D.min(0)]],acks:[e?e.acks:null,[D.required]],keySerializer:[e?e.keySerializer:null,[D.required]],valueSerializer:[e?e.valueSerializer:null,[D.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([D.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:En,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&ne(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{ne(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Vn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=N,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[D.required]],targets:[e?e.targets:[],[D.required]]})}}e("NotificationConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vn,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:He.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ke.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class wn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[D.required]],topicName:[e?e.topicName:null,[D.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[D.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[D.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[D.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[D.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Rn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(qt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[D.required]],requestMethod:[e?e.requestMethod:null,[D.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[D.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[D.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[D.required,D.min(1),D.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([D.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([D.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rn,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,n=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([D.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([D.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([D.required,D.min(1),D.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([D.required,D.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[D.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[D.required,D.min(1),D.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:On,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Be.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:z.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Re.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[D.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[D.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([D.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Hn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ue.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Kn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(S),this.slackChanelTypesTranslateMap=q}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[D.required]],conversationType:[e?e.conversationType:null,[D.required]],conversation:[e?e.conversation:null,[D.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([D.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kn,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:_e.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Bn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[D.required]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SnsConfigComponent",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bn,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Un extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=Lt,this.sqsQueueTypes=Object.keys(Lt),this.sqsQueueTypeTranslationsMap=kt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[D.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[D.required]],delaySeconds:[e?e.delaySeconds:null,[D.min(0),D.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SqsConfigComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Un,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zn{}e("RulenodeCoreConfigExternalModule",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:zn,declarations:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn],imports:[K,L,Me,hn],exports:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn]}),zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,imports:[K,L,Me,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,decorators:[{type:l,args:[{declarations:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn],imports:[K,L,Me,hn],exports:[Bn,Un,wn,En,Dn,Vn,Pn,Rn,On,Gn,Hn,Kn]}]}]});class _n extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.alarmStatusTranslationsMap=M,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(A))this.alarmStatusList.push(A[e]);this.statusFormControl=new O(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(Le(""),Ce((e=>e||"")),ve((e=>this.fetchAlarmStatus(e))),ke())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[D.required]]})}displayStatus(e){return e?this.translate.instant(M.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Ne(t.filter((t=>this.translate.instant(M.get(A[t])).toUpperCase().includes(e))))}return Ne(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const n=t.indexOf(e);n>=0&&(t.splice(n,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,deps:[{token:G.Store},{token:j.TranslateService},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_n,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:fe.TbErrorComponent,selector:"tb-error",inputs:["error"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:j.TranslateService},{type:E.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:o,args:["alarmStatusInput",{static:!1}]}]}});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ie,le,se]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[D.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[D.required]:[]],relationType:[e?e.relationType:null,[D.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:je.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoFilterConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[D.required]]})}}e("MessageTypeConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jn,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:cn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.TENANT,x.CUSTOMER,x.USER,x.DASHBOARD,x.RULE_CHAIN,x.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[D.required]]})}}e("OriginatorTypeConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:$e.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["label","floatLabel","required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Xn extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.switchConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",r=this.switchConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.switchConfigForm.get(t).setValue(e)}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Zn{}e("RuleNodeCoreConfigFilterModule",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Zn,declarations:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n],imports:[K,L,hn],exports:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n]}),Zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,decorators:[{type:l,args:[{declarations:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n],imports:[K,L,hn],exports:[jn,$n,Qn,Jn,Yn,Wn,Xn,_n]}]}]});class er extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=at,this.originatorSources=Object.keys(at),this.originatorSourceTranslationMap=it,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===at.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([D.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===at.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([D.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),er.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:er,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:pe.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:_.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tr extends s{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=W(this.store).tbelEnabled,this.scriptLanguage=d}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[D.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(){const e=this.scriptConfigForm.get("scriptLang").value,t=e===d.JS?"jsScript":"tbelScript",n=e===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",r=this.scriptConfigForm.get(t).value;this.nodeScriptTestService.testNodeScript(r,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,n,e).subscribe((e=>{e&&this.scriptConfigForm.get(t).setValue(e)}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:X.NodeScriptTestService},{token:j.TranslateService}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:oe.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ae.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:X.NodeScriptTestService},{type:j.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class nr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[D.required]],toTemplate:[e?e.toTemplate:null,[D.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[D.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[D.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(Le([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(D.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:J.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:j.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ie,le,se]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[D.required]]})}}e("RenameKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Wt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[D.required]]})}}e("NodeJsonPathConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatLabel,selector:"mat-label"},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[ie,le,se]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:H.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:H.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:me.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:z.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:z.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:z.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"},{kind:"pipe",type:Je,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class lr{}e("RulenodeCoreConfigTransformModule",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),lr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:lr,declarations:[er,tr,nr,rr,or,ar,ir],imports:[K,L,hn],exports:[er,tr,nr,rr,or,ar,ir]}),lr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:l,args:[{declarations:[er,tr,nr,rr,or,ar,ir],imports:[K,L,hn],exports:[er,tr,nr,rr,or,ar,ir]}]}]});class sr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=x}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[D.required]]})}}e("RuleChainInputComponent",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:je.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class mr extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:j.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ur{}e("RuleNodeCoreConfigFlowModule",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[],target:t.ɵɵFactoryTarget.NgModule}),ur.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:ur,declarations:[sr,mr],imports:[K,L,hn],exports:[sr,mr]}),ur.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,imports:[K,L,hn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:l,args:[{declarations:[sr,mr],imports:[K,L,hn],exports:[sr,mr]}]}]});class pr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. If you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required!","limit-range":"Limit should be in a range from 2 to 1000!","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647!","start-interval-value-required":"Start interval value is required!","end-interval-value-required":"End interval value is required!",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","add-timeseries-key":"Add timeseries key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Max relation level should be greater than 0 or unspecified!","relation-type":"Relation type","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required!","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required!","target-key":"Target key","target-key-required":"Target key is required!","attr-mapping-required":"At least one mapping entry should be specified!","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","source-field":"Source field","source-field-required":"Source field is required!","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required!","end-interval-required":"Interval end is required!","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","entity-details-list-empty":"No entity details selected!","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required!","output-value-key":"Output value key","output-value-key-required":"Output value key is required!","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15!","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-cashing":"Use cashing","use-cashing-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required!","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","attributes-mapping":"Attributes mapping*","latest-telemetry-mapping":"Latest telemetry mapping*","add-mapped-attribute-to":"Add mapped attributes to:","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to:","add-mapped-fields-to":"Add mapped fields to:","add-selected-details-to":"Add selected details to:","clear-selected-details":"Clear selected details","clear-selected-keys":"Clear selected keys","fetch-credentials-to":"Fetch credentials to:","add-originator-attributes-to":"Add originator attributes to:","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell Failure","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to:",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output message metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end")!',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch:","mapping-of-customers":"Mapping of customer's:",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to:","device-profiles":"Device profiles","mapping-of-tenant":"Mapping of tenant's:","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[{token:j.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:pr,declarations:[Qe],imports:[K,L],exports:[Cn,Zn,An,zn,lr,ur,Qe]}),pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,imports:[K,L,Cn,Zn,An,zn,lr,ur]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:l,args:[{declarations:[Qe],imports:[K,L],exports:[Cn,Zn,An,zn,lr,ur,Qe]}]}],ctorParameters:function(){return[{type:j.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/platform-browser","@angular/material/select","@angular/material/core","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/icon","@angular/material/chips","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/material/tooltip","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","rxjs","@angular/material/expansion","@home/components/public-api","tslib","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@angular/material/slide-toggle","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@shared/components/toggle-header.component","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,C,v,F,L,k,T,I,N,S,q,M,A,G,E,D,V,w,P,R,O,H,K,B,U,z,_,j,$,Q,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,Ce,ve,Fe,Le,ke,Te,Ie,Ne,Se,qe,Me,Ae,Ge,Ee,De,Ve,we,Pe,Re,Oe,He,Ke,Be,Ue,ze,_e,je,$e,Qe;return{setters:[function(e){t=e,n=e.Component,r=e.Pipe,o=e.EventEmitter,a=e.ViewChild,i=e.forwardRef,l=e.Input,s=e.NgModule},function(e){m=e.RuleNodeConfigurationComponent,u=e.AttributeScope,p=e.telemetryTypeTranslations,d=e.ServiceType,c=e.ScriptLanguage,f=e.AlarmSeverity,g=e.alarmSeverityTranslations,y=e.EntitySearchDirection,x=e.entitySearchDirectionTranslations,b=e.EntityType,h=e.PageComponent,C=e.coerceBoolean,v=e.MessageType,F=e.messageTypeNames,L=e,k=e.SharedModule,T=e.AggregationType,I=e.aggregationTranslations,N=e.entityFields,S=e.NotificationType,q=e.SlackChanelType,M=e.SlackChanelTypesTranslateMap,A=e.alarmStatusTranslations,G=e.AlarmStatus},function(e){E=e},function(e){D=e,V=e.Validators,w=e.NgControl,P=e.NG_VALUE_ACCESSOR,R=e.NG_VALIDATORS,O=e.FormControl,H=e.UntypedFormControl},function(e){K=e,B=e.CommonModule},function(e){U=e},function(e){z=e},function(e){_=e},function(e){j=e},function(e){$=e},function(e){Q=e},function(e){J=e},function(e){Y=e},function(e){W=e},function(e){X=e.getCurrentAuthState,Z=e,ee=e.isDefinedAndNotNull,te=e.deepTrim,ne=e.isObject,re=e.isNotEmptyStr},function(e){oe=e},function(e){ae=e},function(e){ie=e},function(e){le=e.ENTER,se=e.COMMA,me=e.SEMICOLON},function(e){ue=e},function(e){pe=e},function(e){de=e},function(e){ce=e},function(e){fe=e.coerceBooleanProperty},function(e){ge=e},function(e){ye=e},function(e){xe=e},function(e){be=e},function(e){he=e},function(e){Ce=e.tap,ve=e.map,Fe=e.mergeMap,Le=e.takeUntil,ke=e.startWith,Te=e.share},function(e){Ie=e},function(e){Ne=e},function(e){Se=e.of,qe=e.Subject},function(e){Me=e},function(e){Ae=e.HomeComponentsModule},function(e){Ge=e.__decorate},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){we=e},function(e){Pe=e},function(e){Re=e},function(e){Oe=e},function(e){He=e},function(e){Ke=e},function(e){Be=e},function(e){Ue=e},function(e){ze=e},function(e){_e=e},function(e){je=e},function(e){$e=e},function(e){Qe=e}],execute:function(){class Je extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Je,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Ye{constructor(e){this.sanitizer=e}transform(e){return this.sanitizer.bypassSecurityTrustHtml(e)}}e("SafeHtmlPipe",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,deps:[{token:Q.DomSanitizer}],target:t.ɵɵFactoryTarget.Pipe}),Ye.ɵpipe=t.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Ye,name:"safeHtml"}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,decorators:[{type:r,args:[{name:"safeHtml"}]}],ctorParameters:function(){return[{type:Q.DomSanitizer}]}});class We extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.assignCustomerConfigForm}onConfigurationSet(e){this.assignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[V.required,V.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[V.required,V.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:We,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,decorators:[{type:n,args:[{selector:"tb-action-node-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.create-customer-if-not-exists\' | translate }}\n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Xe extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=u,this.attributeScopes=Object.keys(u),this.telemetryTypeTranslationsMap=p}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[V.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==u.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===u.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xe,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-attributes-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-hint
\n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
tb.rulenode.send-attributes-updated-notification-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Ze extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=d.TB_RULE_ENGINE}configForm(){return this.checkPointConfigForm}onConfigurationSet(e){this.checkPointConfigForm=this.fb.group({queueName:[e?e.queueName:null,[V.required]]})}}e("CheckPointConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ze,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:W.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class et extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[V.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===c.JS?[V.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===c.TBEL?[V.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.clearAlarmConfigForm.get("scriptLang").value,n=t===c.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===c.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",o=this.clearAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.clearAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:et,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class tt extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.alarmSeverities=Object.keys(f),this.alarmSeverityTranslationMap=g,this.separatorKeysCodes=[le,se,me],this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],dynamicSeverity:!1}),this.createAlarmConfigForm.get("dynamicSeverity").valueChanges.subscribe((e=>{e?this.createAlarmConfigForm.get("severity").patchValue("",{emitEvent:!1}):this.createAlarmConfigForm.get("severity").patchValue(this.alarmSeverities[0],{emitEvent:!1})}))}validatorTriggers(){return["useMessageAlarmData","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([V.required]),this.createAlarmConfigForm.get("severity").setValidators([V.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==c.TBEL||this.tbelEnabled||(r=c.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===c.JS?[V.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===c.TBEL?[V.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.createAlarmConfigForm.get("scriptLang").value,n=t===c.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===c.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",o=this.createAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.createAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.createAlarmConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.createAlarmConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tt,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\n \n \n tb.rulenode.alarm-severity\n \n \n {{ alarmSeverityTranslationMap.get(severity) | translate }}\n \n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n tb.rulenode.alarm-severity-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.propagate\' | translate }}\n \n
\n \n tb.rulenode.relation-types-list\n \n \n {{key}}\n close\n \n \n \n tb.rulenode.relation-types-list-hint\n \n
\n \n {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class nt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.entityType=b}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[V.required]],entityType:[e?e.entityType:null,[V.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[V.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[V.required,V.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([V.required,V.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==b.DEVICE&&t!==b.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([V.required,V.pattern(/.*\S.*/)]),this.createRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e}),this.createRelationConfigForm.get("entityTypePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e.entityTypePattern=e.entityTypePattern?e.entityTypePattern.trim():null,e}}e("CreateRelationConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,decorators:[{type:n,args:[{selector:"tb-action-node-create-relation-config",template:'
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.create-entity-if-not-exists\' | translate }}\n \n
tb.rulenode.create-entity-if-not-exists-hint
\n
\n \n {{ \'tb.rulenode.remove-current-relations\' | translate }}\n \n
tb.rulenode.remove-current-relations-hint
\n \n {{ \'tb.rulenode.change-originator-to-related-entity\' | translate }}\n \n
tb.rulenode.change-originator-to-related-entity-hint
\n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class rt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.entityType=b}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[V.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[V.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[V.required,V.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([V.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([V.required,V.pattern(/.*\S.*/)]):this.deleteRelationConfigForm.get("entityNamePattern").setValidators([]),this.deleteRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:!1}),this.deleteRelationConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}prepareOutputConfig(e){return e.entityNamePattern=e.entityNamePattern?e.entityNamePattern.trim():null,e}}e("DeleteRelationConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,decorators:[{type:n,args:[{selector:"tb-action-node-delete-relation-config",template:'
\n \n {{ \'tb.rulenode.delete-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.delete-relation-hint
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.entity-cache-expiration\n \n \n {{ \'tb.rulenode.entity-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.entity-cache-expiration-range\' | translate }}\n \n tb.rulenode.entity-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ot extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.deviceProfile}onConfigurationSet(e){this.deviceProfile=this.fb.group({persistAlarmRulesState:[!!e&&e.persistAlarmRulesState,V.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,V.required]})}}e("DeviceProfileConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ot,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,decorators:[{type:n,args:[{selector:"tb-device-profile-config",template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class at extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-generator-function",this.serviceType=d.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[V.required,V.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[V.required,V.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS),e.originatorId&&e.originatorType?e.originator={id:e.originatorId,entityType:e.originatorType}:e.originator=null,delete e.originatorId,delete e.originatorType),e}prepareOutputConfig(e){return e.originator?(e.originatorId=e.originator.id,e.originatorType=e.originator.entityType):(e.originatorId=null,e.originatorType=null),delete e.originator,e}testScript(e){const t=this.generatorConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",o=this.generatorConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.generatorConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}var it;e("GeneratorConfigComponent",at),at.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:at,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),at.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:at,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ce.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:W.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:at,decorators:[{type:n,args:[{selector:"tb-action-node-generator-config",template:'
\n \n tb.rulenode.message-count\n \n \n {{ \'tb.rulenode.message-count-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-message-count-message\' | translate }}\n \n \n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-seconds-message\' | translate }}\n \n \n
\n \n \n \n
\n\n \n \n\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(it||(it={}));const lt=new Map([[it.CUSTOMER,"tb.rulenode.originator-customer"],[it.TENANT,"tb.rulenode.originator-tenant"],[it.RELATED,"tb.rulenode.originator-related"],[it.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[it.ENTITY,"tb.rulenode.originator-entity"]]);var st;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(st||(st={}));const mt=new Map([[st.CIRCLE,"tb.rulenode.perimeter-circle"],[st.POLYGON,"tb.rulenode.perimeter-polygon"]]);var ut;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(ut||(ut={}));const pt=new Map([[ut.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[ut.SECONDS,"tb.rulenode.time-unit-seconds"],[ut.MINUTES,"tb.rulenode.time-unit-minutes"],[ut.HOURS,"tb.rulenode.time-unit-hours"],[ut.DAYS,"tb.rulenode.time-unit-days"]]);var dt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(dt||(dt={}));const ct=new Map([[dt.METER,"tb.rulenode.range-unit-meter"],[dt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[dt.FOOT,"tb.rulenode.range-unit-foot"],[dt.MILE,"tb.rulenode.range-unit-mile"],[dt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var ft;!function(e){e.ID="ID",e.TITLE="TITLE",e.COUNTRY="COUNTRY",e.STATE="STATE",e.CITY="CITY",e.ZIP="ZIP",e.ADDRESS="ADDRESS",e.ADDRESS2="ADDRESS2",e.PHONE="PHONE",e.EMAIL="EMAIL",e.ADDITIONAL_INFO="ADDITIONAL_INFO"}(ft||(ft={}));const gt=new Map([[ft.ID,"tb.rulenode.entity-details-id"],[ft.TITLE,"tb.rulenode.entity-details-title"],[ft.COUNTRY,"tb.rulenode.entity-details-country"],[ft.STATE,"tb.rulenode.entity-details-state"],[ft.CITY,"tb.rulenode.entity-details-city"],[ft.ZIP,"tb.rulenode.entity-details-zip"],[ft.ADDRESS,"tb.rulenode.entity-details-address"],[ft.ADDRESS2,"tb.rulenode.entity-details-address2"],[ft.PHONE,"tb.rulenode.entity-details-phone"],[ft.EMAIL,"tb.rulenode.entity-details-email"],[ft.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var yt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(yt||(yt={}));const xt=new Map([[yt.FIRST,"tb.rulenode.first"],[yt.LAST,"tb.rulenode.last"],[yt.ALL,"tb.rulenode.all"]]),bt=new Map([[yt.FIRST,"tb.rulenode.first-mode-hint"],[yt.LAST,"tb.rulenode.last-mode-hint"],[yt.ALL,"tb.rulenode.all-mode-hint"]]);var ht,Ct;!function(e){e.ASC="ASC",e.DESC="DESC"}(ht||(ht={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(Ct||(Ct={}));const vt=new Map([[Ct.ATTRIBUTES,"tb.rulenode.attributes"],[Ct.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[Ct.FIELDS,"tb.rulenode.fields"]]),Ft=new Map([[Ct.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[Ct.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[Ct.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),Lt=new Map([[ht.ASC,"tb.rulenode.ascending"],[ht.DESC,"tb.rulenode.descending"]]);var kt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(kt||(kt={}));const Tt=new Map([[kt.STANDARD,"tb.rulenode.sqs-queue-standard"],[kt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),It=["anonymous","basic","cert.PEM"],Nt=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),St=["sas","cert.PEM"],qt=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var Mt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(Mt||(Mt={}));const At=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Gt=new Map([["US-ASCII","tb.rulenode.charset-us-ascii"],["ISO-8859-1","tb.rulenode.charset-iso-8859-1"],["UTF-8","tb.rulenode.charset-utf-8"],["UTF-16BE","tb.rulenode.charset-utf-16be"],["UTF-16LE","tb.rulenode.charset-utf-16le"],["UTF-16","tb.rulenode.charset-utf-16"]]);var Et;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Et||(Et={}));const Dt=new Map([[Et.CUSTOM,{value:Et.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Et.ADD,{value:Et.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Et.SUB,{value:Et.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Et.MULT,{value:Et.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Et.DIV,{value:Et.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Et.SIN,{value:Et.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Et.SINH,{value:Et.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Et.COS,{value:Et.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Et.COSH,{value:Et.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Et.TAN,{value:Et.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Et.TANH,{value:Et.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Et.ACOS,{value:Et.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Et.ASIN,{value:Et.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Et.ATAN,{value:Et.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Et.ATAN2,{value:Et.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Et.EXP,{value:Et.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Et.EXPM1,{value:Et.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Et.SQRT,{value:Et.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Et.CBRT,{value:Et.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Et.GET_EXP,{value:Et.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Et.HYPOT,{value:Et.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Et.LOG,{value:Et.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Et.LOG10,{value:Et.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Et.LOG1P,{value:Et.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Et.CEIL,{value:Et.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Et.FLOOR,{value:Et.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Et.FLOOR_DIV,{value:Et.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Et.FLOOR_MOD,{value:Et.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Et.ABS,{value:Et.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Et.MIN,{value:Et.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Et.MAX,{value:Et.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Et.POW,{value:Et.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Et.SIGNUM,{value:Et.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Et.RAD,{value:Et.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Et.DEG,{value:Et.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Vt,wt,Pt;!function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(Vt||(Vt={})),function(e){e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA"}(wt||(wt={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Pt||(Pt={}));const Rt=new Map([[Pt.DATA,"tb.rulenode.message"],[Pt.METADATA,"tb.rulenode.metadata"]]),Ot=new Map([[Vt.ATTRIBUTE,"tb.rulenode.attribute-type"],[Vt.TIME_SERIES,"tb.rulenode.time-series-type"],[Vt.CONSTANT,"tb.rulenode.constant-type"],[Vt.MESSAGE_BODY,"tb.rulenode.message-body-type"],[Vt.MESSAGE_METADATA,"tb.rulenode.message-metadata-type"]]),Ht=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Kt,Bt;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Kt||(Kt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Bt||(Bt={}));const Ut=new Map([[Kt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Kt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Kt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class zt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=st,this.perimeterTypes=Object.keys(st),this.perimeterTypeTranslationMap=mt,this.rangeUnits=Object.keys(dt),this.rangeUnitTranslationMap=ct,this.timeUnits=Object.keys(ut),this.timeUnitsTranslationMap=pt}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[V.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[V.required]],perimeterType:[e?e.perimeterType:null,[V.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]],minInsideDuration:[e?e.minInsideDuration:null,[V.required,V.min(1),V.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[V.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[V.required,V.min(1),V.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[V.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([V.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==st.CIRCLE?(this.geoActionConfigForm.get("centerLatitude").setValidators([]),this.geoActionConfigForm.get("centerLongitude").setValidators([]),this.geoActionConfigForm.get("range").setValidators([]),this.geoActionConfigForm.get("rangeUnit").setValidators([])):(this.geoActionConfigForm.get("centerLatitude").setValidators([V.required,V.min(-90),V.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([V.required,V.min(-180),V.max(180)]),this.geoActionConfigForm.get("range").setValidators([V.required,V.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([V.required])),t||n!==st.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([V.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoActionConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoActionConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.min-inside-duration\n \n \n {{ \'tb.rulenode.min-inside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-inside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n tb.rulenode.min-outside-duration\n \n \n {{ \'tb.rulenode.min-outside-duration-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n tb.rulenode.min-outside-duration-time-unit\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class _t extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-to-string-function"}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.logConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",o=this.logConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.logConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.logConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",_t),_t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),_t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_t,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_t,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class jt extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgCountConfigForm}onConfigurationSet(e){this.msgCountConfigForm=this.fb.group({interval:[e?e.interval:null,[V.required,V.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[V.required]]})}}e("MsgCountConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:n,args:[{selector:"tb-action-node-msg-count-config",template:'
\n \n tb.rulenode.interval-seconds\n \n \n {{ \'tb.rulenode.interval-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-interval-seconds-message\' | translate }}\n \n \n \n tb.rulenode.output-timeseries-key-prefix\n \n \n {{ \'tb.rulenode.output-timeseries-key-prefix-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class $t extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.msgDelayConfigForm}onConfigurationSet(e){this.msgDelayConfigForm=this.fb.group({useMetadataPeriodInSecondsPatterns:[!!e&&e.useMetadataPeriodInSecondsPatterns,[]],periodInSeconds:[e?e.periodInSeconds:null,[]],periodInSecondsPattern:[e?e.periodInSecondsPattern:null,[]],maxPendingMsgs:[e?e.maxPendingMsgs:null,[V.required,V.min(1),V.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([V.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([V.required,V.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:n,args:[{selector:"tb-action-node-msg-delay-config",template:'
\n \n {{ \'tb.rulenode.use-metadata-period-in-seconds-patterns\' | translate }}\n \n
tb.rulenode.use-metadata-period-in-seconds-patterns-hint
\n \n tb.rulenode.period-seconds\n \n \n {{ \'tb.rulenode.period-seconds-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-period-0-seconds-message\' | translate }}\n \n \n \n \n tb.rulenode.period-in-seconds-pattern\n \n \n {{ \'tb.rulenode.period-in-seconds-pattern-required\' | translate }}\n \n \n \n \n \n tb.rulenode.max-pending-messages\n \n \n {{ \'tb.rulenode.max-pending-messages-required\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n {{ \'tb.rulenode.max-pending-messages-range\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Qt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(u),this.telemetryTypeTranslationsMap=p}configForm(){return this.pushToCloudConfigForm}onConfigurationSet(e){this.pushToCloudConfigForm=this.fb.group({scope:[e?e.scope:null,[V.required]]})}}e("PushToCloudConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-cloud-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Jt extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopes=Object.keys(u),this.telemetryTypeTranslationsMap=p}configForm(){return this.pushToEdgeConfigForm}onConfigurationSet(e){this.pushToEdgeConfigForm=this.fb.group({scope:[e?e.scope:null,[V.required]]})}}e("PushToEdgeConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:n,args:[{selector:"tb-action-node-push-to-edge-config",template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Yt extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcReplyConfigForm}onConfigurationSet(e){this.rpcReplyConfigForm=this.fb.group({requestIdMetaDataAttribute:[e?e.requestIdMetaDataAttribute:null,[]]})}}e("RpcReplyConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Wt extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.rpcRequestConfigForm}onConfigurationSet(e){this.rpcRequestConfigForm=this.fb.group({timeoutInSeconds:[e?e.timeoutInSeconds:null,[V.required,V.min(0)]]})}}e("RpcRequestConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-request-config",template:'
\n \n tb.rulenode.timeout-sec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-message\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Xt extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(w),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[V.required]],value:[e[n],[V.required]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[V.required]],value:["",[V.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigOldComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:P,useExisting:i((()=>Xt)),multi:!0},{provide:R,useExisting:i((()=>Xt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:xe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:P,useExisting:i((()=>Xt)),multi:!0},{provide:R,useExisting:i((()=>Xt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \n \n \n
\n
\n
\n \n
\n \n
\n
\n',styles:[":host .tb-kv-map-config{margin-bottom:16px}:host .tb-kv-map-config .header{padding-left:5px;padding-right:5px;padding-bottom:5px}:host .tb-kv-map-config .header .cell{padding-left:5px;padding-right:5px;color:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.UntypedFormBuilder}]},propDecorators:{disabled:[{type:l}],uniqueKeyValuePairValidator:[{type:l}],requiredText:[{type:l}],keyText:[{type:l}],keyRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],required:[{type:l}]}});class Zt extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.saveToCustomTableConfigForm}onConfigurationSet(e){this.saveToCustomTableConfigForm=this.fb.group({tableName:[e?e.tableName:null,[V.required,V.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[V.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:n,args:[{selector:"tb-action-node-custom-table-config",template:'
\n \n tb.rulenode.custom-table-name\n \n \n {{ \'tb.rulenode.custom-table-name-required\' | translate }}\n \n tb.rulenode.custom-table-hint\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class en extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.timeseriesConfigForm}onConfigurationSet(e){this.timeseriesConfigForm=this.fb.group({defaultTTL:[e?e.defaultTTL:null,[V.required,V.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:en,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,decorators:[{type:n,args:[{selector:"tb-action-node-timeseries-config",template:'
\n \n tb.rulenode.default-ttl\n \n \n {{ \'tb.rulenode.default-ttl-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-default-ttl-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class tn extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.unassignCustomerConfigForm}onConfigurationSet(e){this.unassignCustomerConfigForm=this.fb.group({customerNamePattern:[e?e.customerNamePattern:null,[V.required,V.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[V.required,V.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tn,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,decorators:[{type:n,args:[{selector:"tb-action-node-un-assign-to-customer-config",template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.customer-cache-expiration\n \n \n {{ \'tb.rulenode.customer-cache-expiration-required\' | translate }}\n \n \n {{ \'tb.rulenode.customer-cache-expiration-range\' | translate }}\n \n tb.rulenode.customer-cache-expiration-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class nn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=u,this.attributeScopes=Object.keys(u),this.telemetryTypeTranslationsMap=p,this.separatorKeysCodes=[le,se,me]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[V.required]],keys:[e?e.keys:null,[V.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==u.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:a,args:["attributeChipList"]}]}});class rn extends h{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=Dt,this.ArgumentType=Vt,this.attributeScopeMap=Ut,this.argumentTypeResultMap=Ot,this.arguments=Object.values(Vt),this.attributeScope=Object.values(Kt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(w),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),n=this.createArgumentControl(null,t.length);t.push(n,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Et.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([V.minLength(this.minArgs),V.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!1}),n.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Vt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Vt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Ht[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:P,useExisting:i((()=>rn)),multi:!0},{provide:R,useExisting:i((()=>rn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"],dependencies:[{kind:"directive",type:K.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:be.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:be.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:he.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:he.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:he.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:xe.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:P,useExisting:i((()=>rn)),multi:!0},{provide:R,useExisting:i((()=>rn)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n
\n \n tb.rulenode.argument-type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.argument-type-field-input-required\n \n \n \n tb.rulenode.argument-key-field-input\n \n help\n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n
\n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.FormBuilder}]},propDecorators:{disabled:[{type:l}],function:[{type:l}]}});class on extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...Dt.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(Ce((e=>{let t;t="string"==typeof e&&Et[e]?Et[e]:null,this.updateView(t)})),ve((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=Dt.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:on,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:P,useExisting:i((()=>on)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:Ne.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:P,useExisting:i((()=>on)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.UntypedFormBuilder}]},propDecorators:{required:[{type:l}],disabled:[{type:l}],operationInput:[{type:a,args:["operationInput",{static:!0}]}]}});class an extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Et,this.ArgumentTypeResult=wt,this.argumentTypeResultMap=Ot,this.attributeScopeMap=Ut,this.argumentsResult=Object.values(wt),this.attributeScopeResult=Object.values(Bt)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[V.required]],arguments:[e?e.arguments:null,[V.required]],customFunction:[e?e.customFunction:"",[V.required]],result:this.fb.group({type:[e?e.result.type:null,[V.required]],attributeScope:[e?e.result.attributeScope:null,[V.required]],key:[e?e.result.key:"",[V.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result.type").value;t===Et.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===wt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:an,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:D.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:rn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:on,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n \n \n
\n
\n tb.rulenode.result-title\n
\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(argument) | translate }}\n \n \n \n tb.rulenode.type-field-input-required\n \n \n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n
\n \n {{\'tb.rulenode.add-to-body-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ln{constructor(e,t){this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[V.required,V.maxLength(255)]]})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(Ce((e=>{this.updateView(e)})),ve((e=>e||"")),Fe((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,Se(this.messageTypes).pipe(ve((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}}e("OutputMessageTypeAutocompleteComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ln,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing"},providers:[{provide:P,useExisting:i((()=>ln)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],ngImport:t,template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:P,useExisting:i((()=>ln)),multi:!0}],template:'\n \n \n \n \n {{msgType}}\n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]},propDecorators:{messageTypeInput:[{type:a,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:l}],subscriptSizing:[{type:l}]}});class sn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.destroy$=new qe,this.serviceType=d.TB_RULE_ENGINE,this.deduplicationStrategie=yt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=xt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[ee(e?.interval)?e.interval:null,[V.required,V.min(1)]],strategy:[ee(e?.strategy)?e.strategy:null,[V.required]],outMsgType:[ee(e?.outMsgType)?e.outMsgType:null,[V.required]],queueName:[ee(e?.queueName)?e.queueName:null,[V.required]],maxPendingMsgs:[ee(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[V.required,V.min(1),V.max(1e3)]],maxRetries:[ee(e?.maxRetries)?e.maxRetries:null,[V.required,V.min(0),V.max(100)]]}),this.deduplicationConfigForm.get("strategy").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.enableControl(e)}))}updateValidators(e){this.enableControl(this.deduplicationConfigForm.get("strategy").value)}validatorTriggers(){return["strategy"]}enableControl(e){e===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("DeduplicationConfigComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:W.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Me.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Me.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Me.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Me.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class mn extends h{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(w),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.kvListFormGroup=this.fb.group({}),this.kvListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.kvListFormGroup.get("keyVals")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.kvListFormGroup.disable({emitEvent:!1}):this.kvListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.kvListFormGroup.setControl("keyVals",this.fb.array(t)),this.valueChangeSubscription=this.kvListFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))}removeKeyVal(e){this.kvListFormGroup.get("keyVals").removeAt(e)}addKeyVal(){this.kvListFormGroup.get("keyVals").push(this.fb.group({key:["",[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}updateModel(){const e=this.kvListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.kvListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("KvMapConfigComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mn,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:i((()=>mn)),multi:!0},{provide:R,useExisting:i((()=>mn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:xe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),Ge([C()],mn.prototype,"disabled",void 0),Ge([C()],mn.prototype,"uniqueKeyValuePairValidator",void 0),Ge([C()],mn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:P,useExisting:i((()=>mn)),multi:!0},{provide:R,useExisting:i((()=>mn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ keyText }}\n \n \n {{ keyRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n
\n
\n \n \n \n
\n \n
\n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-kv-map-config{margin-bottom:12px}:host ::ng-deep .tb-kv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-kv-map-config .body{margin-top:7px;max-height:363px;overflow:auto}:host ::ng-deep .tb-kv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-kv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-kv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.FormBuilder}]},propDecorators:{disabled:[{type:l}],uniqueKeyValuePairValidator:[{type:l}],labelText:[{type:l}],requiredText:[{type:l}],keyText:[{type:l}],keyRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],popupHelpLink:[{type:l}],required:[{type:l}]}});class un{constructor(e,t){this.store=e,this.fb=t,this.destroy$=new qe}ngOnInit(){this.slideToggleControlGroup=this.fb.group({slideToggleControl:[null,[]]}),this.slideToggleControlGroup.get("slideToggleControl").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.slideToggleControlGroup.get("slideToggleControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.slideToggleControlGroup.disable({emitEvent:!1}):this.slideToggleControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SlideToggleComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:un,selector:"tb-slide-toggle",inputs:{slideToggleName:"slideToggleName",slideToggleTooltip:"slideToggleTooltip"},providers:[{provide:P,useExisting:i((()=>un)),multi:!0}],ngImport:t,template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"],dependencies:[{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:we.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-slide-toggle",providers:[{provide:P,useExisting:i((()=>un)),multi:!0}],template:'
\n \n {{ slideToggleName }}\n \n info\n
\n',styles:[":host ::ng-deep .slide-toggle-container{align-items:center}:host ::ng-deep .slide-toggle-container .slide-toggle{margin-right:8px}:host ::ng-deep .slide-toggle-container .slide-toggle label{padding-left:12px}:host ::ng-deep .slide-toggle-container .tooltip-icon{width:18px;height:18px;line-height:18px;font-size:18px;color:#e0e0e0}:host ::ng-deep .slide-toggle-container .tooltip-icon:hover{color:#9e9e9e}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]},propDecorators:{slideToggleName:[{type:l}],slideToggleTooltip:[{type:l}]}});class pn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.entityType=b,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[V.required]],maxLevel:[null,[V.min(1)]],relationType:[null],deviceTypes:[null,[V.required]]}),this.deviceRelationsQueryFormGroup.valueChanges.subscribe((e=>{this.deviceRelationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.deviceRelationsQueryFormGroup.disable({emitEvent:!1}):this.deviceRelationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.deviceRelationsQueryFormGroup.reset(e,{emitEvent:!1})}}e("DeviceRelationsQueryConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pn,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:i((()=>pn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:De.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["label","required","disabled","entityType"]},{kind:"component",type:Ve.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:P,useExisting:i((()=>pn)),multi:!0}],template:'
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n',styles:[":host .relation-level{margin-bottom:16px}:host .last-level-slide-toggle{margin:8px 0 24px}:host .relation-type-autocomplete{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class dn{constructor(){this.required=!1}}e("FieldsetComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,deps:[],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dn,selector:"tb-fieldset-component",inputs:{label:"label",required:"required"},ngImport:t,template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]}]}),Ge([C()],dn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-fieldset-component",template:'
\n {{ label }}{{ required ? \'*\' : \'\' }}\n
\n \n
\n
\n',styles:[".fields-group{padding:0 16px;margin:0;border:1px solid #E0E0E0;border-radius:4px}.fields-group .fieldset-content{align-items:center}.fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}.fields-group legend{color:#757575;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.fields-group legend+*{display:block}.fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],propDecorators:{label:[{type:l}],required:[{type:l}]}});class cn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[V.required]],maxLevel:[null,[V.min(1)]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:i((()=>cn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:P,useExisting:i((()=>cn)),multi:!0}],template:'
\n \n
\n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n \n \n
\n \n
\n
\n
\n',styles:[":host .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host .last-level-slide-toggle{margin-bottom:18px;display:inline-block}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class fn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.message-type",this.separatorKeysCodes=[le,se,me],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(v))this.messageTypesList.push({name:F.get(v[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(ke(""),ve((e=>e||"")),Fe((e=>this.fetchMessageTypes(e))),Te())}ngAfterViewInit(){}setDisabledState(e){this.disabled=e,this.disabled?this.messageTypeConfigForm.disable({emitEvent:!1}):this.messageTypeConfigForm.enable({emitEvent:!1})}writeValue(e){this.searchText="",this.messageTypes.length=0,e&&e.forEach((e=>{const t=this.messageTypesList.find((t=>t.value===e));t?this.messageTypes.push({name:t.name,value:t.value}):this.messageTypes.push({name:e,value:e})}))}displayMessageTypeFn(e){return e?e.name:void 0}textIsNotEmpty(e){return!!(e&&null!=e&&e.length>0)}createMessageType(e,t){e.preventDefault(),this.transformMessageType(t)}add(e){this.transformMessageType(e.value)}fetchMessageTypes(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Se(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return Se(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t=null;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},t&&this.addMessageType(t)}this.clear("")}remove(e){const t=this.messageTypes.indexOf(e);t>=0&&(this.messageTypes.splice(t,1),this.updateModel())}selected(e){this.addMessageType(e.option.value),this.clear("")}addMessageType(e){-1===this.messageTypes.findIndex((t=>t.value===e.value))&&(this.messageTypes.push(e),this.updateModel())}onFocus(){this.messageTypeConfigForm.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.messageTypeInput.nativeElement.value=e,this.messageTypeConfigForm.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}updateModel(){const e=this.messageTypes.map((e=>e.value));this.required?(this.chipList.errorState=!e.length,this.propagateChange(e.length>0?e:null)):(this.chipList.errorState=!1,this.propagateChange(e))}}e("MessageTypesConfigComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,deps:[{token:E.Store},{token:$.TranslateService},{token:L.TruncatePipe},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:P,useExisting:i((()=>fn)),multi:!0}],viewQueries:[{propertyName:"chipList",first:!0,predicate:["chipList"],descendants:!0},{propertyName:"matAutocomplete",first:!0,predicate:["messageTypeAutocomplete"],descendants:!0},{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n { messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Ie.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:Ne.HighlightPipe,name:"highlight"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:P,useExisting:i((()=>fn)),multi:!0}],template:'\n {{ label }}\n \n \n {{messageType.name}}\n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-message-types-found\n
\n \n \n {{ \'tb.rulenode.no-message-type-matching\' | translate :\n { messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n \n {{ \'tb.rulenode.message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:L.TruncatePipe},{type:D.FormBuilder}]},propDecorators:{required:[{type:l}],label:[{type:l}],placeholder:[{type:l}],disabled:[{type:l}],chipList:[{type:a,args:["chipList",{static:!1}]}],matAutocomplete:[{type:a,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:a,args:["messageTypeInput",{static:!1}]}]}});class gn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=It,this.credentialsTypeTranslationsMap=Nt,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[V.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.currentValue&&"disableCertPemCredentials"===t){"cert.PEM"===this.credentialsConfigFormGroup.get("type").value&&setTimeout((()=>{this.credentialsConfigFormGroup.get("type").patchValue("anonymous",{emitEvent:!0})}))}}}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}writeValue(e){ee(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),this.updateValidators())}updateView(){let e=this.credentialsConfigFormGroup.value;const t=e.type;switch(t){case"anonymous":e={type:t};break;case"basic":e={type:t,username:e.username,password:e.password};break;case"cert.PEM":delete e.username}this.propagateChange(e)}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}validate(e){return this.credentialsConfigFormGroup.valid?null:{credentialsConfig:{valid:!1}}}credentialsTypeChanged(){this.credentialsConfigFormGroup.patchValue({username:null,password:null,caCert:null,caCertFileName:null,privateKey:null,privateKeyFileName:null,cert:null,certFileName:null}),this.updateValidators()}updateValidators(e=!1){const t=this.credentialsConfigFormGroup.get("type").value;switch(e&&this.credentialsConfigFormGroup.reset({type:t},{emitEvent:!1}),this.credentialsConfigFormGroup.setValidators([]),this.credentialsConfigFormGroup.get("username").setValidators([]),this.credentialsConfigFormGroup.get("password").setValidators([]),t){case"anonymous":break;case"basic":this.credentialsConfigFormGroup.get("username").setValidators([V.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[V.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(V.required,[["caCert","caCertFileName"],["privateKey","privateKeyFileName","cert","certFileName"]])])}this.credentialsConfigFormGroup.get("username").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.get("password").updateValueAndValidity({emitEvent:e}),this.credentialsConfigFormGroup.updateValueAndValidity({emitEvent:e})}requiredFilesSelected(e,t=null){return n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:P,useExisting:i((()=>gn)),multi:!0},{provide:R,useExisting:i((()=>gn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:K.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Me.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Me.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Me.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Me.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Me.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Re.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:P,useExisting:i((()=>gn)),multi:!0},{provide:R,useExisting:i((()=>gn)),multi:!0}],template:'
\n \n \n tb.rulenode.credentials\n \n {{ credentialsTypeTranslationsMap.get(credentialsConfigFormGroup.get(\'type\').value) | translate }}\n \n \n \n \n tb.rulenode.credentials-type\n \n \n {{ credentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.username\n \n \n {{ \'tb.rulenode.username-required\' | translate }}\n \n \n \n tb.rulenode.password\n \n \n \n {{ \'tb.rulenode.password-required\' | translate }}\n \n \n \n \n
{{ \'tb.rulenode.credentials-pem-hint\' | translate }}
\n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n
\n
\n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]},propDecorators:{required:[{type:l}],disableCertPemCredentials:[{type:l}],passwordFieldRequired:[{type:l}]}});class yn{constructor(e,t,n){this.store=e,this.fb=t,this.translate=n,this.destroy$=new qe,this.selectOptions=[];for(const e of Rt.keys())this.selectOptions.push({value:e,name:this.translate.instant(Rt.get(e))})}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.chipControlGroup.disable({emitEvent:!1}):this.chipControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:P,useExisting:i((()=>yn)),multi:!0}],ngImport:t,template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:pe.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:pe.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:P,useExisting:i((()=>yn)),multi:!0}],template:'
\n \n \n {{ option.name }}\n \n
\n',styles:[":host{width:100%}:host .chip-label{font-weight:400;font-size:12px;letter-spacing:.25px;color:#3d3d3d}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]},propDecorators:{labelText:[{type:l}]}});class xn extends h{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new qe,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(w),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[V.required]],value:[e[n],[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.updateModel()}))}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value){const n=this.selectOptions.find((t=>t.value===e.key));n&&t.push(n)}const n=[];for(const r of this.selectOptions)ee(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[V.required]],value:["",[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.controls[e.length-1])}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Le(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,deps:[{token:E.Store},{token:$.TranslateService},{token:t.Injector},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:i((()=>xn)),multi:!0},{provide:R,useExisting:i((()=>xn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultLayoutAlignDirective,selector:" [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]",inputs:["fxLayoutAlign","fxLayoutAlign.xs","fxLayoutAlign.sm","fxLayoutAlign.md","fxLayoutAlign.lg","fxLayoutAlign.xl","fxLayoutAlign.lt-sm","fxLayoutAlign.lt-md","fxLayoutAlign.lt-lg","fxLayoutAlign.lt-xl","fxLayoutAlign.gt-xs","fxLayoutAlign.gt-sm","fxLayoutAlign.gt-md","fxLayoutAlign.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:xe.DefaultShowHideDirective,selector:" [fxShow], [fxShow.print], [fxShow.xs], [fxShow.sm], [fxShow.md], [fxShow.lg], [fxShow.xl], [fxShow.lt-sm], [fxShow.lt-md], [fxShow.lt-lg], [fxShow.lt-xl], [fxShow.gt-xs], [fxShow.gt-sm], [fxShow.gt-md], [fxShow.gt-lg], [fxHide], [fxHide.print], [fxHide.xs], [fxHide.sm], [fxHide.md], [fxHide.lg], [fxHide.xl], [fxHide.lt-sm], [fxHide.lt-md], [fxHide.lt-lg], [fxHide.lt-xl], [fxHide.gt-xs], [fxHide.gt-sm], [fxHide.gt-md], [fxHide.gt-lg]",inputs:["fxShow","fxShow.print","fxShow.xs","fxShow.sm","fxShow.md","fxShow.lg","fxShow.xl","fxShow.lt-sm","fxShow.lt-md","fxShow.lt-lg","fxShow.lt-xl","fxShow.gt-xs","fxShow.gt-sm","fxShow.gt-md","fxShow.gt-lg","fxHide","fxHide.print","fxHide.xs","fxHide.sm","fxHide.md","fxHide.lg","fxHide.xl","fxHide.lt-sm","fxHide.lt-md","fxHide.lt-lg","fxHide.lt-xl","fxHide.gt-xs","fxHide.gt-sm","fxHide.gt-md","fxHide.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),Ge([C()],xn.prototype,"disabled",void 0),Ge([C()],xn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:P,useExisting:i((()=>xn)),multi:!0},{provide:R,useExisting:i((()=>xn)),multi:!0}],template:'
\n
\n \n
\n
\n
\n
\n \n {{ selectText }}\n \n \n {{option.name}}\n \n \n \n {{ selectRequiredText }}\n \n \n arrow_forward\n \n {{ valText }}\n \n \n {{ valRequiredText }}\n \n \n
\n \n
\n
\n
\n {{ hintText }}\n \n
\n
\n \n \n
\n \n
\n',styles:[":host ::ng-deep{width:100%}:host ::ng-deep .tb-sv-map-config{margin-bottom:12px}:host ::ng-deep .tb-sv-map-config .map-label{font-weight:400;font-size:12px;color:#3d3d3d;letter-spacing:.25px}:host ::ng-deep .tb-sv-map-config .body{max-height:363px;overflow:auto;margin-top:7px}:host ::ng-deep .tb-sv-map-config .body .mapping-block{margin-bottom:15px}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block{border:1px solid #E0E0E0;width:100%;border-radius:6px;padding:22px 22px 0;align-items:center}:host ::ng-deep .tb-sv-map-config .body .mapping-block .inputs-block .arrow-icon{width:24px;height:24px;line-height:24px;font-size:24px;margin:0 2px 22px;color:#9e9e9e}:host ::ng-deep .tb-sv-map-config tb-error{display:block;margin-top:-12px;margin-bottom:8px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:t.Injector},{type:D.FormBuilder}]},propDecorators:{selectOptions:[{type:l}],disabled:[{type:l}],labelText:[{type:l}],requiredText:[{type:l}],targetKeyPrefix:[{type:l}],selectText:[{type:l}],selectRequiredText:[{type:l}],valText:[{type:l}],valRequiredText:[{type:l}],hintText:[{type:l}],popupHelpLink:[{type:l}],required:[{type:l}]}});class bn extends h{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(y),this.directionTypeTranslations=x,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[V.required]],maxLevel:[null,[]],filters:[null]}),this.relationsQueryFormGroup.valueChanges.subscribe((e=>{this.relationsQueryFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.relationsQueryFormGroup.disable({emitEvent:!1}):this.relationsQueryFormGroup.enable({emitEvent:!1})}writeValue(e){this.relationsQueryFormGroup.reset(e||{},{emitEvent:!1})}}e("RelationsQueryConfigOldComponent",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:bn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:i((()=>bn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Pe.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:P,useExisting:i((()=>bn)),multi:!0}],template:'
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n relation.direction\n \n \n {{ directionTypeTranslations.get(type) | translate }}\n \n \n \n \n tb.rulenode.max-relation-level\n \n \n
\n
relation.relation-filters
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]},propDecorators:{disabled:[{type:l}],required:[{type:l}]}});class hn{constructor(e,t,n){this.store=e,this.translate=t,this.fb=n,this.destroy$=new qe,this.separatorKeysCodes=[le,se,me]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]}),this.attributeControlGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}writeValue(e){this.attributeControlGroup.patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}removeKey(e,t){const n=this.attributeControlGroup.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.attributeControlGroup.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.attributeControlGroup.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.attributeControlGroup.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}clearChipGrid(e){this.attributeControlGroup.get(e).patchValue([],{emitEvent:!0})}}e("SelectAttributesComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:hn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:P,useExisting:i((()=>hn)),multi:!0}],ngImport:t,template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:P,useExisting:i((()=>hn)),multi:!0}],template:'
\n \n tb.rulenode.client-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.shared-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.server-attributes\n \n \n {{key}}\n close\n \n \n \n \n \n \n tb.rulenode.latest-telemetry\n \n \n {{key}}\n close\n \n \n \n \n \n
\n {{ \'tb.rulenode.kv-map-pattern-hint\' | translate }}\n \n
\n \n \n
\n',styles:[":host ::ng-deep .chip-grid{width:100%;margin-bottom:16px}:host ::ng-deep .fetch-slide-toggle{width:100%;margin-bottom:22px;display:block}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]},propDecorators:{popupHelpLink:[{type:l}]}});class Cn{}e("RulenodeCoreConfigCommonModule",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Cn,declarations:[mn,pn,cn,fn,gn,Ye,rn,on,ln,Xt,yn,un,xn,dn,bn,hn],imports:[B,k,Ae],exports:[mn,pn,cn,fn,gn,Ye,rn,on,ln,Xt,yn,un,xn,dn,bn,hn]}),Cn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,imports:[B,k,Ae]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,decorators:[{type:s,args:[{declarations:[mn,pn,cn,fn,gn,Ye,rn,on,ln,Xt,yn,un,xn,dn,bn,hn],imports:[B,k,Ae],exports:[mn,pn,cn,fn,gn,Ye,rn,on,ln,Xt,yn,un,xn,dn,bn,hn]}]}]});class vn{}e("RuleNodeCoreConfigActionModule",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),vn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:vn,declarations:[nn,Xe,en,Wt,_t,We,et,tt,nt,$t,rt,at,zt,jt,Yt,Zt,tn,Ze,ot,Jt,Qt,an,sn],imports:[B,k,Ae,Cn],exports:[nn,Xe,en,Wt,_t,We,et,tt,nt,$t,rt,at,zt,jt,Yt,Zt,tn,Ze,ot,Jt,Qt,an,sn]}),vn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,imports:[B,k,Ae,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,decorators:[{type:s,args:[{declarations:[nn,Xe,en,Wt,_t,We,et,tt,nt,$t,rt,at,zt,jt,Yt,Zt,tn,Ze,ot,Jt,Qt,an,sn],imports:[B,k,Ae,Cn],exports:[nn,Xe,en,Wt,_t,We,et,tt,nt,$t,rt,at,zt,jt,Yt,Zt,tn,Ze,ot,Jt,Qt,an,sn]}]}]});class Fn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[V.min(0),V.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:ee(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:ee(e?.outputValueKey)?e.outputValueKey:null,useCache:!ee(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!ee(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:ee(e?.periodValueKey)?e.periodValueKey:null,round:ee(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!ee(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return te(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([V.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"],dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n \n \n \n \n \n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n",styles:[":host ::ng-deep .slide-toggles-block .slide-toggle{margin:12px 0}:host ::ng-deep .period-input{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]}});class Ln extends m{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=Ct;for(const e of vt.keys())e!==Ct.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,te(e)}toggleChange(e){this.customerAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=ee(e?.telemetry)?e.telemetry?Ct.LATEST_TELEMETRY:Ct.ATTRIBUTES:ee(e?.dataToFetch)?e.dataToFetch:Ct.ATTRIBUTES,n=ee(e?.attrMapping)?e.attrMapping:ee(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===Ct.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[V.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ln,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","name","useSelectOnMdLg","ignoreMdLgSize","appearance","disabled"],outputs:["valueChange"]},{kind:"component",type:mn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]}});class kn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[V.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ne(e)&&(e.attributesControl={clientAttributeNames:ee(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:ee(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:ee(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:ee(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!ee(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:ee(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!ee(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kn,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:pn,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:hn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .device-relations{width:100%}:host .failure-toggle{margin:25px 0}:host .device-attribute{margin-top:12px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]}});class Tn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.entityDetailsTranslationsMap=gt,this.entityDetailsList=[],this.searchText="",this.displayDetailsFn=this.displayDetails.bind(this);for(const e of Object.keys(ft))this.entityDetailsList.push(ft[e]);this.detailsFormControl=new O(""),this.filteredEntityDetails=this.detailsFormControl.valueChanges.pipe(ke(""),ve((e=>e||"")),Fe((e=>this.fetchEntityDetails(e))),Te())}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return this.searchText="",this.detailsFormControl.patchValue("",{emitEvent:!0}),this.detailsList=e?e.detailsList:[],t=ee(e?.addToMetadata)?e.addToMetadata?Pt.METADATA:Pt.DATA:e?.fetchTo?e.fetchTo:Pt.DATA,{detailsList:ee(e?.detailsList)?e.detailsList:null,fetchTo:t}}prepareOutputConfig(e){return e.detailsList=this.detailsList,e}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[V.required]],fetchTo:[e.fetchTo,[]]}),this.detailsList=e?e.detailsList:[]}displayDetails(e){return e?this.translate.instant(gt.get(e)):void 0}fetchEntityDetails(e){if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Se(this.entityDetailsList.filter((t=>this.translate.instant(gt.get(ft[t])).toUpperCase().includes(e))))}return Se(this.entityDetailsList)}detailsFieldSelected(e){this.addDetailsField(e.option.value),this.clear("")}removeDetailsField(e){const t=this.detailsList.indexOf(e);t>=0&&(this.detailsList.splice(t,1),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}addDetailsField(e){this.detailsList||(this.detailsList=[]);-1===this.detailsList.indexOf(e)&&(this.detailsList.push(e),this.entityDetailsConfigForm.get("detailsList").setValue(this.detailsList))}onEntityDetailsInputFocus(){this.detailsFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clearChipGrid(){this.detailsList=[],this.entityDetailsConfigForm.get("detailsList").patchValue([],{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}clear(e=""){this.detailsInput.nativeElement.value=e,this.detailsFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.detailsInput.nativeElement.blur(),this.detailsInput.nativeElement.focus()}),0)}}e("EntityDetailsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tn,selector:"tb-enrichment-node-entity-details-config",viewQueries:[{propertyName:"detailsInput",first:!0,predicate:["detailsInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Ie.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:Ne.HighlightPipe,name:"highlight"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n {{ \'tb.rulenode.entity-details\' | translate }}\n \n \n \n {{entityDetailsTranslationsMap.get(details) | translate}}\n \n close\n \n \n \n \n \n \n \n \n \n
\n
\n {{ \'tb.rulenode.no-entity-details-matching\' | translate }}\n
\n
\n
\n
\n {{ \'tb.rulenode.entity-details-list-empty\' | translate }}\n
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]},propDecorators:{detailsInput:[{type:a,args:["detailsInput",{static:!1}]}]}});class In extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me],this.aggregationTypes=T,this.aggregations=Object.keys(T),this.aggregationTypesTranslations=I,this.fetchMode=yt,this.samplingOrders=Object.keys(ht),this.samplingOrdersTranslate=Lt,this.timeUnits=Object.values(ut),this.timeUnitsTranslationMap=pt,this.deduplicationStrategiesHintTranslations=bt,this.headerOptions=[],this.timeUnitMap={[ut.MILLISECONDS]:1,[ut.SECONDS]:1e3,[ut.MINUTES]:6e4,[ut.HOURS]:36e5,[ut.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null;for(const e of xt.keys())this.headerOptions.push({value:e,name:this.translate.instant(xt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[]],aggregation:[e.aggregation,[V.required]],fetchMode:[e.fetchMode,[V.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}toggleChange(e){this.getTelemetryFromDatabaseConfigForm.get("fetchMode").patchValue(e,{emitEvent:!0})}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,delete e.interval,te(e)}prepareInputConfig(e){return ne(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:ee(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:ee(e?.aggregation)?e.aggregation:T.NONE,fetchMode:ee(e?.fetchMode)?e.fetchMode:yt.FIRST,orderBy:ee(e?.orderBy)?e.orderBy:ht.ASC,limit:ee(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!ee(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:ee(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:ee(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:ut.MINUTES,endInterval:ee(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:ee(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:ut.MINUTES},startIntervalPattern:ee(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:ee(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===yt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([V.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([V.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([V.required,V.min(2),V.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([V.required,V.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([V.required,V.min(1),V.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([V.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([V.required,V.min(1),V.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([V.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([])),this.getTelemetryFromDatabaseConfigForm.get("aggregation").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("orderBy").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("limit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}addKey(e,t){const n=e.input;let r=e.value;if((r||"").trim()){r=r.trim();let e=this.getTelemetryFromDatabaseConfigForm.get(t).value;e&&-1!==e.indexOf(r)||(e||(e=[]),e.push(r),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(e,{emitEvent:!0}))}n&&(n.value="")}}e("GetTelemetryFromDatabaseConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:In,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style"]},{kind:"component",type:ae.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ye.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:D.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:He.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","name","useSelectOnMdLg","ignoreMdLgSize","appearance","disabled"],outputs:["valueChange"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n {{\'tb.rulenode.timeseries-keys\' | translate}}\n \n \n {{key}}\n close\n \n \n \n \n \n {{ "tb.rulenode.general-pattern-hint" | translate }}\n \n \n \n \n\n \n \n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-value-required\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n {{ \'tb.rulenode.time-value-range\' | translate }}\n \n \n \n {{ \'tb.rulenode.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()} }}\n
\n
\n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n
\n {{ \'tb.rulenode.metadata-dynamic-interval-hint\' | translate }}\n \n
\n
\n
\n
\n \n
\n \n \n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n
\n',styles:[":host ::ng-deep label.tb-title{margin-bottom:-10px}:host ::ng-deep .fetch-interval{margin-top:12px}:host ::ng-deep .fetch-interval .interval-slide-toggle{width:100%;margin:4px 0 16px}:host ::ng-deep .fetch-interval .input-block{width:100%}:host ::ng-deep .interval-description{text-align:center;font-size:12px;color:#3d3d3d;margin-bottom:9px;font-weight:500}:host ::ng-deep .fetch-strategy-fieldset{margin-top:12px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block{margin-top:8px;align-items:center;width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .fetch-mod-toggle{margin-bottom:12px;width:630px}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block{width:100%}:host ::ng-deep .fetch-strategy-fieldset .fetch-strategy-block .input-block .additional-inputs{margin-bottom:16px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]}});class Nn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ne(e)&&(e.attributesControl={clientAttributeNames:ee(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:ee(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:ee(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:ee(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!ee(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA,tellFailureIfAbsent:!!ee(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:ee(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"component",type:hn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n \n \n \n \n \n \n
\n',styles:[":host label.tb-title{margin-bottom:-10px}:host .failure-slide-toggle{margin:25px 0}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.FormBuilder}]}});class Sn extends m{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of Object.keys(N))this.originatorFields.push({value:N[e].value,name:this.translate.instant(N[e].name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return te(e)}prepareInputConfig(e){return{dataMapping:ee(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:ee(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[V.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:un,selector:"tb-slide-toggle",inputs:["slideToggleName","slideToggleTooltip"]},{kind:"component",type:xn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .msg-metadata-chip{margin-bottom:12px}:host .skip-slide-toggle{margin-top:20px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]}});class qn extends m{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=Ct,this.msgMetadataLabelTranslations=Ft,this.originatorFields=[],this.fetchToData=[],this.destroy$=new qe,this.defaultKvMap={serialNumber:"sn"},this.defaultSvMap={[N.name.value]:`relatedEntity${this.translate.instant(N.name.name)}`},this.dataToFetchPrevValue="";for(const e of Object.keys(N))this.originatorFields.push({value:N[e].value,name:this.translate.instant(N[e].name)});for(const e of vt.keys())this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}toggleChange(e){this.relatedAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,te(e)}prepareInputConfig(e){let t;return ee(e?.telemetry)?this.dataToFetchPrevValue=e.telemetry?Ct.LATEST_TELEMETRY:Ct.ATTRIBUTES:this.dataToFetchPrevValue=ee(e?.dataToFetch)?e.dataToFetch:Ct.ATTRIBUTES,t=ee(e?.attrMapping)?e.attrMapping:ee(e?.dataMapping)?e.dataMapping:null,{relationsQuery:ee(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:this.dataToFetchPrevValue,dataMapping:t,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===Ct.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[V.required]],dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[V.required]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e===Ct.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultSvMap,{emitEvent:!1}),e!==Ct.FIELDS&&this.dataToFetchPrevValue===Ct.FIELDS&&this.relatedAttributesConfigForm.get("dataMapping").patchValue(this.defaultKvMap,{emitEvent:!1}),this.dataToFetchPrevValue=e}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qn,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","name","useSelectOnMdLg","ignoreMdLgSize","appearance","disabled"],outputs:["valueChange"]},{kind:"component",type:mn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:cn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:xn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-data-block{margin-top:12px}:host .fetch-data-block .fetch-to-data-toggle{margin-bottom:12px;width:630px}:host .fetch-data-block .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]}});class Mn extends m{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=Ct;for(const e of vt.keys())e!==Ct.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.tenantAttributesConfigForm}toggleChange(e){this.tenantAttributesConfigForm.get("dataToFetch").patchValue(e,{emitEvent:!0})}prepareInputConfig(e){let t,n;return t=ee(e?.telemetry)?e.telemetry?Ct.LATEST_TELEMETRY:Ct.ATTRIBUTES:ee(e?.dataToFetch)?e.dataToFetch:Ct.ATTRIBUTES,n=ee(e?.attrMapping)?e.attrMapping:ee(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===Ct.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[V.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,deps:[{token:E.Store},{token:D.FormBuilder},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mn,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"],dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:He.ToggleHeaderComponent,selector:"tb-toggle-header",inputs:["value","name","useSelectOnMdLg","ignoreMdLgSize","appearance","disabled"],outputs:["valueChange"]},{kind:"component",type:mn,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:dn,selector:"tb-fieldset-component",inputs:["label","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n \n \n \n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{margin-bottom:12px;width:420px}:host .msg-metadata-chip{margin-bottom:12px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder},{type:$.TranslateService}]}});class An extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:ee(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:An,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:yn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]}});class Gn{}e("RulenodeCoreConfigEnrichmentModule",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Gn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Gn,declarations:[Ln,Tn,kn,Nn,Sn,In,qn,Mn,Fn,An],imports:[B,k,Cn],exports:[Ln,Tn,kn,Nn,Sn,In,qn,Mn,Fn,An]}),Gn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,imports:[B,k,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,decorators:[{type:s,args:[{declarations:[Ln,Tn,kn,Nn,Sn,In,qn,Mn,Fn,An],imports:[B,k,Cn],exports:[Ln,Tn,kn,Nn,Sn,In,qn,Mn,Fn,An]}]}]});class En extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=St,this.azureIotHubCredentialsTypeTranslationsMap=qt}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[V.required]],host:[e?e.host:null,[V.required]],port:[e?e.port:null,[V.required,V.min(1),V.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[V.required,V.min(1),V.max(200)]],clientId:[e?e.clientId:null,[V.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[V.required]],sasKey:[e&&e.credentials?e.credentials.sasKey:null,[]],caCert:[e&&e.credentials?e.credentials.caCert:null,[]],caCertFileName:[e&&e.credentials?e.credentials.caCertFileName:null,[]],privateKey:[e&&e.credentials?e.credentials.privateKey:null,[]],privateKeyFileName:[e&&e.credentials?e.credentials.privateKeyFileName:null,[]],cert:[e&&e.credentials?e.credentials.cert:null,[]],certFileName:[e&&e.credentials?e.credentials.certFileName:null,[]],password:[e&&e.credentials?e.credentials.password:null,[]]})})}prepareOutputConfig(e){const t=e.credentials.type;return"sas"===t&&(e.credentials={type:t,sasKey:e.credentials.sasKey,caCert:e.credentials.caCert,caCertFileName:e.credentials.caCertFileName}),e}validatorTriggers(){return["credentials.type"]}updateValidators(e){const t=this.azureIotHubConfigForm.get("credentials"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([V.required]);break;case"cert.PEM":t.get("privateKey").setValidators([V.required]),t.get("privateKeyFileName").setValidators([V.required]),t.get("cert").setValidators([V.required]),t.get("certFileName").setValidators([V.required])}t.get("sasKey").updateValueAndValidity({emitEvent:e}),t.get("privateKey").updateValueAndValidity({emitEvent:e}),t.get("privateKeyFileName").updateValueAndValidity({emitEvent:e}),t.get("cert").updateValueAndValidity({emitEvent:e}),t.get("certFileName").updateValueAndValidity({emitEvent:e})}}e("AzureIotHubConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:En,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:K.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Me.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Me.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Me.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Me.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Me.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:D.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Re.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n \n \n \n tb.rulenode.hostname\n \n \n {{ \'tb.rulenode.hostname-required\' | translate }}\n \n \n \n tb.rulenode.device-id\n \n \n {{ \'tb.rulenode.device-id-required\' | translate }}\n \n \n \n \n \n tb.rulenode.credentials\n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(azureIotHubConfigForm.get(\'credentials.type\').value) | translate }}\n \n \n
\n \n tb.rulenode.credentials-type\n \n \n {{ azureIotHubCredentialsTypeTranslationsMap.get(credentialsType) | translate }}\n \n \n \n {{ \'tb.rulenode.credentials-type-required\' | translate }}\n \n \n
\n \n \n \n \n tb.rulenode.sas-key\n \n \n \n {{ \'tb.rulenode.sas-key-required\' | translate }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n tb.rulenode.private-key-password\n \n \n \n \n
\n
\n
\n
\n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Dn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=At,this.ToByteStandartCharsetTypeTranslationMap=Gt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[V.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[V.required]],retries:[e?e.retries:null,[V.min(0)]],batchSize:[e?e.batchSize:null,[V.min(0)]],linger:[e?e.linger:null,[V.min(0)]],bufferMemory:[e?e.bufferMemory:null,[V.min(0)]],acks:[e?e.acks:null,[V.required]],keySerializer:[e?e.keySerializer:null,[V.required]],valueSerializer:[e?e.valueSerializer:null,[V.required]],otherProperties:[e?e.otherProperties:null,[]],addMetadataKeyValuesAsKafkaHeaders:[!!e&&e.addMetadataKeyValuesAsKafkaHeaders,[]],kafkaHeadersCharset:[e?e.kafkaHeadersCharset:null,[]]})}validatorTriggers(){return["addMetadataKeyValuesAsKafkaHeaders"]}updateValidators(e){this.kafkaConfigForm.get("addMetadataKeyValuesAsKafkaHeaders").value?this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([V.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dn,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.key-pattern\n \n \n \n
tb.rulenode.key-pattern-hint
\n \n tb.rulenode.bootstrap-servers\n \n \n {{ \'tb.rulenode.bootstrap-servers-required\' | translate }}\n \n \n \n tb.rulenode.retries\n \n \n {{ \'tb.rulenode.min-retries-message\' | translate }}\n \n \n \n tb.rulenode.batch-size-bytes\n \n \n {{ \'tb.rulenode.min-batch-size-bytes-message\' | translate }}\n \n \n \n tb.rulenode.linger-ms\n \n \n {{ \'tb.rulenode.min-linger-ms-message\' | translate }}\n \n \n \n tb.rulenode.buffer-memory-bytes\n \n \n {{ \'tb.rulenode.min-buffer-memory-bytes-message\' | translate }}\n \n \n \n tb.rulenode.acks\n \n \n {{ ackValue }}\n \n \n \n \n tb.rulenode.key-serializer\n \n \n {{ \'tb.rulenode.key-serializer-required\' | translate }}\n \n \n \n tb.rulenode.value-serializer\n \n \n {{ \'tb.rulenode.value-serializer-required\' | translate }}\n \n \n \n \n \n \n {{ \'tb.rulenode.add-metadata-key-values-as-kafka-headers\' | translate }}\n \n
tb.rulenode.add-metadata-key-values-as-kafka-headers-hint
\n \n tb.rulenode.charset-encoding\n \n \n {{ ToByteStandartCharsetTypeTranslationMap.get(charset) | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Vn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[]}configForm(){return this.mqttConfigForm}onConfigurationSet(e){this.mqttConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[V.required]],host:[e?e.host:null,[V.required]],port:[e?e.port:null,[V.required,V.min(1),V.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[V.required,V.min(1),V.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&re(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]}),this.subscriptions.push(this.mqttConfigForm.get("clientId").valueChanges.subscribe((e=>{re(e)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1})})))}ngOnDestroy(){this.subscriptions.forEach((e=>e.unsubscribe()))}}e("MqttConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:gn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n \n tb.rulenode.connect-timeout\n \n \n {{ \'tb.rulenode.connect-timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n {{ \'tb.rulenode.connect-timeout-range\' | translate }}\n \n \n
\n \n tb.rulenode.client-id\n \n {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class wn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=S,this.entityType=b}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[V.required]],targets:[e?e.targets:[],[V.required]]})}}e("NotificationConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wn,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Ke.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Be.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]}});class Pn extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.pubSubConfigForm}onConfigurationSet(e){this.pubSubConfigForm=this.fb.group({projectId:[e?e.projectId:null,[V.required]],topicName:[e?e.topicName:null,[V.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[V.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[V.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Re.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-pub-sub-config",template:'
\n \n tb.rulenode.gcp-project-id\n \n \n {{ \'tb.rulenode.gcp-project-id-required\' | translate }}\n \n \n \n tb.rulenode.pubsub-topic-name\n \n \n {{ \'tb.rulenode.pubsub-topic-name-required\' | translate }}\n \n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Rn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"]}configForm(){return this.rabbitMqConfigForm}onConfigurationSet(e){this.rabbitMqConfigForm=this.fb.group({exchangeNamePattern:[e?e.exchangeNamePattern:null,[]],routingKeyPattern:[e?e.routingKeyPattern:null,[]],messageProperties:[e?e.messageProperties:null,[]],host:[e?e.host:null,[V.required]],port:[e?e.port:null,[V.required,V.min(1),V.max(65535)]],virtualHost:[e?e.virtualHost:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]],automaticRecoveryEnabled:[!!e&&e.automaticRecoveryEnabled,[]],connectionTimeout:[e?e.connectionTimeout:null,[V.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[V.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-node-rabbit-mq-config",template:'
\n \n tb.rulenode.exchange-name-pattern\n \n \n \n tb.rulenode.routing-key-pattern\n \n \n \n tb.rulenode.message-properties\n \n \n {{ property }}\n \n \n \n
\n \n tb.rulenode.host\n \n \n {{ \'tb.rulenode.host-required\' | translate }}\n \n \n \n tb.rulenode.port\n \n \n {{ \'tb.rulenode.port-required\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n {{ \'tb.rulenode.port-range\' | translate }}\n \n \n
\n \n tb.rulenode.virtual-host\n \n \n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n \n {{ \'tb.rulenode.automatic-recovery\' | translate }}\n \n \n tb.rulenode.connection-timeout-ms\n \n \n {{ \'tb.rulenode.min-connection-timeout-ms-message\' | translate }}\n \n \n \n tb.rulenode.handshake-timeout-ms\n \n \n {{ \'tb.rulenode.min-handshake-timeout-ms-message\' | translate }}\n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class On extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(Mt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[V.required]],requestMethod:[e?e.requestMethod:null,[V.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],ignoreRequestBody:[!!e&&e.ignoreRequestBody,[]],enableProxy:[!!e&&e.enableProxy,[]],useSystemProxyProperties:[!!e&&e.enableProxy,[]],proxyScheme:[e?e.proxyHost:null,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],readTimeoutMs:[e?e.readTimeoutMs:null,[]],maxParallelRequestsCount:[e?e.maxParallelRequestsCount:null,[V.min(0)]],headers:[e?e.headers:null,[]],useRedisQueueForMsgPersistence:[!!e&&e.useRedisQueueForMsgPersistence,[]],trimQueue:[!!e&&e.trimQueue,[]],maxQueueSize:[e?e.maxQueueSize:null,[]],credentials:[e?e.credentials:null,[]]})}validatorTriggers(){return["useSimpleClientHttpFactory","useRedisQueueForMsgPersistence","enableProxy","useSystemProxyProperties"]}updateValidators(e){const t=this.restApiCallConfigForm.get("useSimpleClientHttpFactory").value,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[V.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[V.required,V.min(1),V.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([V.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([V.min(0)]):this.restApiCallConfigForm.get("maxQueueSize").setValidators([]),this.restApiCallConfigForm.get("readTimeoutMs").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("maxQueueSize").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e}),this.restApiCallConfigForm.get("credentials").updateValueAndValidity({emitEvent:e})}}e("RestApiCallConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:On,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:gn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-node-rest-api-call-config",template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.request-method\n \n \n {{ requestType }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n \n {{ \'tb.rulenode.use-simple-client-http-factory\' | translate }}\n \n \n {{ \'tb.rulenode.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\n \n {{ \'tb.rulenode.ignore-request-body\' | translate }}\n \n
\n \n {{ \'tb.rulenode.use-system-proxy-properties\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-scheme\n \n \n {{ proxyScheme }}\n \n \n \n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n
\n \n tb.rulenode.read-timeout\n \n tb.rulenode.read-timeout-hint\n \n \n tb.rulenode.max-parallel-requests-count\n \n tb.rulenode.max-parallel-requests-count-hint\n \n \n
\n \n \n \n {{ \'tb.rulenode.use-redis-queue\' | translate }}\n \n
\n \n {{ \'tb.rulenode.trim-redis-queue\' | translate }}\n \n \n tb.rulenode.redis-queue-max-size\n \n \n
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Hn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.smtpProtocols=["smtp","smtps"],this.tlsVersions=["TLSv1","TLSv1.1","TLSv1.2","TLSv1.3"]}configForm(){return this.sendEmailConfigForm}onConfigurationSet(e){this.sendEmailConfigForm=this.fb.group({useSystemSmtpSettings:[!!e&&e.useSystemSmtpSettings,[]],smtpProtocol:[e?e.smtpProtocol:null,[]],smtpHost:[e?e.smtpHost:null,[]],smtpPort:[e?e.smtpPort:null,[]],timeout:[e?e.timeout:null,[]],enableTls:[!!e&&e.enableTls,[]],tlsVersion:[e?e.tlsVersion:null,[]],enableProxy:[!!e&&e.enableProxy,[]],proxyHost:[e?e.proxyHost:null,[]],proxyPort:[e?e.proxyPort:null,[]],proxyUser:[e?e.proxyUser:null,[]],proxyPassword:[e?e.proxyPassword:null,[]],username:[e?e.username:null,[]],password:[e?e.password:null,[]]})}validatorTriggers(){return["useSystemSmtpSettings","enableProxy"]}updateValidators(e){const t=this.sendEmailConfigForm.get("useSystemSmtpSettings").value,n=this.sendEmailConfigForm.get("enableProxy").value;t?(this.sendEmailConfigForm.get("smtpProtocol").setValidators([]),this.sendEmailConfigForm.get("smtpHost").setValidators([]),this.sendEmailConfigForm.get("smtpPort").setValidators([]),this.sendEmailConfigForm.get("timeout").setValidators([]),this.sendEmailConfigForm.get("proxyHost").setValidators([]),this.sendEmailConfigForm.get("proxyPort").setValidators([])):(this.sendEmailConfigForm.get("smtpProtocol").setValidators([V.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([V.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([V.required,V.min(1),V.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([V.required,V.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[V.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[V.required,V.min(1),V.max(65535)]:[])),this.sendEmailConfigForm.get("smtpProtocol").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("smtpPort").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("timeout").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyHost").updateValueAndValidity({emitEvent:e}),this.sendEmailConfigForm.get("proxyPort").updateValueAndValidity({emitEvent:e})}}e("SendEmailConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Hn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ue.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Oe.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-node-send-email-config",template:'
\n \n {{ \'tb.rulenode.use-system-smtp-settings\' | translate }}\n \n
\n \n tb.rulenode.smtp-protocol\n \n \n {{ smtpProtocol.toUpperCase() }}\n \n \n \n
\n \n tb.rulenode.smtp-host\n \n \n {{ \'tb.rulenode.smtp-host-required\' | translate }}\n \n \n \n tb.rulenode.smtp-port\n \n \n {{ \'tb.rulenode.smtp-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n {{ \'tb.rulenode.smtp-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.timeout-msec\n \n \n {{ \'tb.rulenode.timeout-required\' | translate }}\n \n \n {{ \'tb.rulenode.min-timeout-msec-message\' | translate }}\n \n \n \n {{ \'tb.rulenode.enable-tls\' | translate }}\n \n \n tb.rulenode.tls-version\n \n \n {{ tlsVersion }}\n \n \n \n \n {{ \'tb.rulenode.enable-proxy\' | translate }}\n \n
\n
\n \n tb.rulenode.proxy-host\n \n \n {{ \'tb.rulenode.proxy-host-required\' | translate }}\n \n \n \n tb.rulenode.proxy-port\n \n \n {{ \'tb.rulenode.proxy-port-required\' | translate }}\n \n \n {{ \'tb.rulenode.proxy-port-range\' | translate }}\n \n \n
\n \n tb.rulenode.proxy-user\n \n \n \n tb.rulenode.proxy-password\n \n \n
\n \n tb.rulenode.username\n \n \n \n tb.rulenode.password\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Kn extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.sendSmsConfigForm}onConfigurationSet(e){this.sendSmsConfigForm=this.fb.group({numbersToTemplate:[e?e.numbersToTemplate:null,[V.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[V.required]],useSystemSmsSettings:[!!e&&e.useSystemSmsSettings,[]],smsProviderConfiguration:[e?e.smsProviderConfiguration:null,[]]})}validatorTriggers(){return["useSystemSmsSettings"]}updateValidators(e){this.sendSmsConfigForm.get("useSystemSmsSettings").value?this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([]):this.sendSmsConfigForm.get("smsProviderConfiguration").setValidators([V.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ze.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-node-send-sms-config",template:'
\n \n tb.rulenode.numbers-to-template\n \n \n {{ \'tb.rulenode.numbers-to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.sms-message-template\n \n \n {{ \'tb.rulenode.sms-message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Bn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(q),this.slackChanelTypesTranslateMap=M}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[V.required]],conversationType:[e?e.conversationType:null,[V.required]],conversation:[e?e.conversation:null,[V.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([V.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,deps:[{token:E.Store},{token:D.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bn,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_e.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:_e.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:je.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n \n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.FormBuilder}]}});class Un extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.snsConfigForm}onConfigurationSet(e){this.snsConfigForm=this.fb.group({topicArnPattern:[e?e.topicArnPattern:null,[V.required]],accessKeyId:[e?e.accessKeyId:null,[V.required]],secretAccessKey:[e?e.secretAccessKey:null,[V.required]],region:[e?e.region:null,[V.required]]})}}e("SnsConfigComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Un,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class zn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=kt,this.sqsQueueTypes=Object.keys(kt),this.sqsQueueTypeTranslationsMap=Tt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[V.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[V.required]],delaySeconds:[e?e.delaySeconds:null,[V.min(0),V.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[V.required]],secretAccessKey:[e?e.secretAccessKey:null,[V.required]],region:[e?e.region:null,[V.required]]})}}e("SqsConfigComponent",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,decorators:[{type:n,args:[{selector:"tb-external-node-sqs-config",template:'
\n \n tb.rulenode.queue-type\n \n \n {{ sqsQueueTypeTranslationsMap.get(type) | translate }}\n \n \n \n \n tb.rulenode.queue-url-pattern\n \n \n {{ \'tb.rulenode.queue-url-pattern-required\' | translate }}\n \n \n \n \n tb.rulenode.delay-seconds\n \n \n {{ \'tb.rulenode.min-delay-seconds-message\' | translate }}\n \n \n {{ \'tb.rulenode.max-delay-seconds-message\' | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.aws-access-key-id\n \n \n {{ \'tb.rulenode.aws-access-key-id-required\' | translate }}\n \n \n \n tb.rulenode.aws-secret-access-key\n \n \n {{ \'tb.rulenode.aws-secret-access-key-required\' | translate }}\n \n \n \n tb.rulenode.aws-region\n \n \n {{ \'tb.rulenode.aws-region-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class _n{}e("RulenodeCoreConfigExternalModule",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,deps:[],target:t.ɵɵFactoryTarget.NgModule}),_n.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:_n,declarations:[Un,zn,Pn,Dn,Vn,wn,Rn,On,Hn,En,Kn,Bn],imports:[B,k,Ae,Cn],exports:[Un,zn,Pn,Dn,Vn,wn,Rn,On,Hn,En,Kn,Bn]}),_n.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,imports:[B,k,Ae,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,decorators:[{type:s,args:[{declarations:[Un,zn,Pn,Dn,Vn,wn,Rn,On,Hn,En,Kn,Bn],imports:[B,k,Ae,Cn],exports:[Un,zn,Pn,Dn,Vn,wn,Rn,On,Hn,En,Kn,Bn]}]}]});class jn extends m{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.alarmStatusTranslationsMap=A,this.alarmStatusList=[],this.searchText="",this.displayStatusFn=this.displayStatus.bind(this);for(const e of Object.keys(G))this.alarmStatusList.push(G[e]);this.statusFormControl=new H(""),this.filteredAlarmStatus=this.statusFormControl.valueChanges.pipe(ke(""),ve((e=>e||"")),Fe((e=>this.fetchAlarmStatus(e))),Te())}ngOnInit(){super.ngOnInit()}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return this.searchText="",this.statusFormControl.patchValue("",{emitEvent:!0}),e}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e?e.alarmStatusList:null,[V.required]]})}displayStatus(e){return e?this.translate.instant(A.get(e)):void 0}fetchAlarmStatus(e){const t=this.getAlarmStatusList();if(this.searchText=e,this.searchText&&this.searchText.length){const e=this.searchText.toUpperCase();return Se(t.filter((t=>this.translate.instant(A.get(G[t])).toUpperCase().includes(e))))}return Se(t)}alarmStatusSelected(e){this.addAlarmStatus(e.option.value),this.clear("")}removeAlarmStatus(e){const t=this.alarmStatusConfigForm.get("alarmStatusList").value;if(t){const n=t.indexOf(e);n>=0&&(t.splice(n,1),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}}addAlarmStatus(e){let t=this.alarmStatusConfigForm.get("alarmStatusList").value;t||(t=[]);-1===t.indexOf(e)&&(t.push(e),this.alarmStatusConfigForm.get("alarmStatusList").setValue(t))}getAlarmStatusList(){return this.alarmStatusList.filter((e=>-1===this.alarmStatusConfigForm.get("alarmStatusList").value.indexOf(e)))}onAlarmStatusInputFocus(){this.statusFormControl.updateValueAndValidity({onlySelf:!0,emitEvent:!0})}clear(e=""){this.alarmStatusInput.nativeElement.value=e,this.statusFormControl.patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.alarmStatusInput.nativeElement.blur(),this.alarmStatusInput.nativeElement.focus()}),0)}}e("CheckAlarmStatusComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,deps:[{token:E.Store},{token:$.TranslateService},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jn,selector:"tb-filter-node-check-alarm-status-config",viewQueries:[{propertyName:"alarmStatusInput",first:!0,predicate:["alarmStatusInput"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ie.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Ie.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Ie.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:K.AsyncPipe,name:"async"},{kind:"pipe",type:Ne.HighlightPipe,name:"highlight"},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n \n tb.rulenode.alarm-status-filter\n \n \n \n {{alarmStatusTranslationsMap.get(alarmStatus) | translate}}\n \n close\n \n \n \n \n \n \n \n \n
\n
\n tb.rulenode.no-alarm-status-matching\n
\n
\n
\n
\n
\n \n
\n\n\n\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:$.TranslateService},{type:D.UntypedFormBuilder}]},propDecorators:{alarmStatusInput:[{type:a,args:["alarmStatusInput",{static:!1}]}]}});class $n extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}configForm(){return this.checkMessageConfigForm}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e?e.messageNames:null,[]],metadataNames:[e?e.metadataNames:null,[]],checkAllKeys:[!!e&&e.checkAllKeys,[]]})}validateConfig(){const e=this.checkMessageConfigForm.get("messageNames").value,t=this.checkMessageConfigForm.get("metadataNames").value;return e.length>0||t.length>0}removeMessageName(e){const t=this.checkMessageConfigForm.get("messageNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("messageNames").setValue(t,{emitEvent:!0}))}removeMetadataName(e){const t=this.checkMessageConfigForm.get("metadataNames").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.checkMessageConfigForm.get("metadataNames").setValue(t,{emitEvent:!0}))}addMessageName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("messageNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("messageNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}addMetadataName(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.checkMessageConfigForm.get("metadataNames").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.checkMessageConfigForm.get("metadataNames").setValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CheckMessageConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$n,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"],dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n \n tb.rulenode.data-keys\n \n \n {{messageName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n tb.rulenode.metadata-keys\n \n \n {{metadataName}}\n close\n \n \n \n tb.rulenode.separator-hint\n \n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
tb.rulenode.check-all-keys-hint
\n
\n',styles:[":host label.tb-title{margin-bottom:-10px}\n"]}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Qn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.keys(y),this.entitySearchDirectionTranslationsMap=x}configForm(){return this.checkRelationConfigForm}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[!!e&&e.checkForSingleEntity,[]],direction:[e?e.direction:null,[]],entityType:[e?e.entityType:null,e&&e.checkForSingleEntity?[V.required]:[]],entityId:[e?e.entityId:null,e&&e.checkForSingleEntity?[V.required]:[]],relationType:[e?e.relationType:null,[V.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[V.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[V.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qn,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:$e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:Ve.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["label","floatLabel","required","disabled","subscriptSizing"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
tb.rulenode.check-relation-hint
\n \n relation.direction\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n
\n \n \n \n \n
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Jn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=st,this.perimeterTypes=Object.keys(st),this.perimeterTypeTranslationMap=mt,this.rangeUnits=Object.keys(dt),this.rangeUnitTranslationMap=ct}configForm(){return this.geoFilterConfigForm}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[V.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[V.required]],perimeterType:[e?e.perimeterType:null,[V.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName:null,[]],centerLatitude:[e?e.centerLatitude:null,[]],centerLongitude:[e?e.centerLatitude:null,[]],range:[e?e.range:null,[]],rangeUnit:[e?e.rangeUnit:null,[]],polygonsDefinition:[e?e.polygonsDefinition:null,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([V.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==st.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([])):(this.geoFilterConfigForm.get("centerLatitude").setValidators([V.required,V.min(-90),V.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([V.required,V.min(-180),V.max(180)]),this.geoFilterConfigForm.get("range").setValidators([V.required,V.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([V.required])),t||n!==st.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([V.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLatitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("centerLongitude").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("range").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("rangeUnit").updateValueAndValidity({emitEvent:e}),this.geoFilterConfigForm.get("polygonsDefinition").updateValueAndValidity({emitEvent:e})}}e("GpsGeoFilterConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:D.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n \n tb.rulenode.latitude-key-name\n \n \n {{ \'tb.rulenode.latitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.longitude-key-name\n \n \n {{ \'tb.rulenode.longitude-key-name-required\' | translate }}\n \n \n \n tb.rulenode.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-message-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.circle-center-latitude\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n tb.rulenode.circle-center-longitude\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n tb.rulenode.range\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n tb.rulenode.range-units\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n
\n
\n
\n
\n \n tb.rulenode.polygon-definition\n \n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Yn extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e?e.messageTypes:null,[V.required]]})}}e("MessageTypeConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yn,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n
\n',dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:fn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Wn extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.allowedEntityTypes=[b.DEVICE,b.ASSET,b.ENTITY_VIEW,b.TENANT,b.CUSTOMER,b.USER,b.DASHBOARD,b.RULE_CHAIN,b.RULE_NODE]}configForm(){return this.originatorTypeConfigForm}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e?e.originatorTypes:null,[V.required]]})}}e("OriginatorTypeConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n
\n',dependencies:[{kind:"component",type:Qe.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["label","floatLabel","required","disabled","subscriptSizing","allowedEntityTypes","ignoreAuthorityFilter"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class Xn extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-filter-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class Zn extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-switch-function"}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.switchConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",o=this.switchConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.switchConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.switchConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class er{}e("RuleNodeCoreConfigFilterModule",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[],target:t.ɵɵFactoryTarget.NgModule}),er.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:er,declarations:[$n,Qn,Jn,Yn,Wn,Xn,Zn,jn],imports:[B,k,Cn],exports:[$n,Qn,Jn,Yn,Wn,Xn,Zn,jn]}),er.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,imports:[B,k,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:s,args:[{declarations:[$n,Qn,Jn,Yn,Wn,Xn,Zn,jn],imports:[B,k,Cn],exports:[$n,Qn,Jn,Yn,Wn,Xn,Zn,jn]}]}]});class tr extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=it,this.originatorSources=Object.keys(it),this.originatorSourceTranslationMap=lt,this.allowedEntityTypes=[b.DEVICE,b.ASSET,b.ENTITY_VIEW,b.USER,b.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[V.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===it.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([V.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===it.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([V.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([V.required,V.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:j.DefaultFlexDirective,selector:" [fxFlex], [fxFlex.xs], [fxFlex.sm], [fxFlex.md], [fxFlex.lg], [fxFlex.xl], [fxFlex.lt-sm], [fxFlex.lt-md], [fxFlex.lt-lg], [fxFlex.lt-xl], [fxFlex.gt-xs], [fxFlex.gt-sm], [fxFlex.gt-md], [fxFlex.gt-lg]",inputs:["fxFlex","fxFlex.xs","fxFlex.sm","fxFlex.md","fxFlex.lg","fxFlex.xl","fxFlex.lt-sm","fxFlex.lt-md","fxFlex.lt-lg","fxFlex.lt-xl","fxFlex.gt-xs","fxFlex.gt-sm","fxFlex.gt-md","fxFlex.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:bn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:n,args:[{selector:"tb-transformation-node-change-originator-config",template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | translate }}\n \n \n \n
\n \n \n \n tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n \n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class nr extends m{constructor(e,t,n,r){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=r,this.tbelEnabled=X(this.store).tbelEnabled,this.scriptLanguage=c,this.changeScript=new o,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-transformer-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:c.JS,[V.required]],jsScript:[e?e.jsScript:null,[V.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==c.TBEL||this.tbelEnabled||(t=c.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===c.JS?[V.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===c.TBEL?[V.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=c.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===c.JS?"jsScript":"tbelScript",r=t===c.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===c.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:E.Store},{token:D.UntypedFormBuilder},{token:Z.NodeScriptTestService},{token:$.TranslateService}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:ae.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder},{type:Z.NodeScriptTestService},{type:$.TranslateService}]},propDecorators:{jsFuncComponent:[{type:a,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:a,args:["tbelFuncComponent",{static:!1}]}]}});class rr extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.mailBodyTypes=[{name:"tb.mail-body-type.plain-text",value:"false"},{name:"tb.mail-body-type.html",value:"true"},{name:"tb.mail-body-type.dynamic",value:"dynamic"}]}configForm(){return this.toEmailConfigForm}onConfigurationSet(e){this.toEmailConfigForm=this.fb.group({fromTemplate:[e?e.fromTemplate:null,[V.required]],toTemplate:[e?e.toTemplate:null,[V.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[V.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null],bodyTemplate:[e?e.bodyTemplate:null,[V.required]]}),this.toEmailConfigForm.get("mailBodyType").valueChanges.pipe(ke([e?.subjectTemplate])).subscribe((e=>{"dynamic"===e?(this.toEmailConfigForm.get("isHtmlTemplate").patchValue("",{emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").setValidators(V.required)):this.toEmailConfigForm.get("isHtmlTemplate").clearValidators(),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity()}))}}e("ToEmailConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:J.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:Y.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:$.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:n,args:[{selector:"tb-transformation-node-to-email-config",template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n \n \n \n tb.rulenode.to-template\n \n \n {{ \'tb.rulenode.to-template-required\' | translate }}\n \n \n \n \n tb.rulenode.cc-template\n \n \n \n \n tb.rulenode.bcc-template\n \n \n \n \n tb.rulenode.subject-template\n \n \n {{ \'tb.rulenode.subject-template-required\' | translate }}\n \n \n \n \n tb.rulenode.mail-body-type\n \n \n {{ type.name | translate }}\n \n \n \n \n tb.rulenode.dynamic-mail-body-type\n \n \n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class or extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[V.required]],keys:[e?e.keys:null,[V.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_e.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:_e.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ar extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[V.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[V.required]]})}}e("RenameKeysConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:_e.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:_e.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ir extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[V.required]]})}}e("NodeJsonPathConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatLabel,selector:"mat-label"},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class lr extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[V.required]],keys:[e?e.keys:null,[V.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:lr,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n',dependencies:[{kind:"directive",type:K.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:K.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ue.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:z.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:_.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:_.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:_.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_e.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:_e.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:pe.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:pe.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:pe.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:pe.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:j.DefaultLayoutGapDirective,selector:" [fxLayoutGap], [fxLayoutGap.xs], [fxLayoutGap.sm], [fxLayoutGap.md], [fxLayoutGap.lg], [fxLayoutGap.xl], [fxLayoutGap.lt-sm], [fxLayoutGap.lt-md], [fxLayoutGap.lt-lg], [fxLayoutGap.lt-xl], [fxLayoutGap.gt-xs], [fxLayoutGap.gt-sm], [fxLayoutGap.gt-md], [fxLayoutGap.gt-lg]",inputs:["fxLayoutGap","fxLayoutGap.xs","fxLayoutGap.sm","fxLayoutGap.md","fxLayoutGap.lg","fxLayoutGap.xl","fxLayoutGap.lt-sm","fxLayoutGap.lt-md","fxLayoutGap.lt-lg","fxLayoutGap.lt-xl","fxLayoutGap.gt-xs","fxLayoutGap.gt-sm","fxLayoutGap.gt-md","fxLayoutGap.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"},{kind:"pipe",type:Ye,name:"safeHtml"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class sr{}e("RulenodeCoreConfigTransformModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:sr,declarations:[tr,nr,rr,or,ar,ir,lr],imports:[B,k,Cn],exports:[tr,nr,rr,or,ar,ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,imports:[B,k,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:s,args:[{declarations:[tr,nr,rr,or,ar,ir,lr],imports:[B,k,Cn],exports:[tr,nr,rr,or,ar,ir,lr]}]}]});class mr extends m{constructor(e,t){super(e),this.store=e,this.fb=t,this.entityType=b}configForm(){return this.ruleChainInputConfigForm}onConfigurationSet(e){this.ruleChainInputConfigForm=this.fb.group({ruleChainId:[e?e.ruleChainId:null,[V.required]]})}}e("RuleChainInputComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:$e.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:D.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class ur extends m{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[{token:E.Store},{token:D.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ur,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:j.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:D.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:D.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:$.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:E.Store},{type:D.UntypedFormBuilder}]}});class pr{}e("RuleNodeCoreConfigFlowModule",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:pr,declarations:[mr,ur],imports:[B,k,Cn],exports:[mr,ur]}),pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,imports:[B,k,Cn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:s,args:[{declarations:[mr,ur],imports:[B,k,Cn],exports:[mr,ur]}]}]});class dr{constructor(e){!function(e){e.setTranslation("en_US",{tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","create-entity-if-not-exists-hint":"Create a new entity set above if it does not exist.","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","entity-cache-expiration":"Entities cache expiration time (sec)","entity-cache-expiration-hint":"Specifies maximum time interval allowed to store found entity records. 0 value means that records will never expire.","entity-cache-expiration-required":"Entities cache expiration time is required.","entity-cache-expiration-range":"Entities cache expiration time should be greater than or equal to 0.","customer-name-pattern":"Customer name pattern","customer-name-pattern-required":"Customer name pattern is required","create-customer-if-not-exists":"Create new customer if not exists","customer-cache-expiration":"Customers cache expiration time (sec)","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. If you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required!","limit-range":"Limit should be in a range from 2 to 1000!","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647!","start-interval-value-required":"Start interval value is required!","end-interval-value-required":"End interval value is required!",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","add-timeseries-key":"Add timeseries key","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Hint: use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Max relation level should be greater than 0 or unspecified!","relation-type":"Relation type","relation-type-pattern":"Relation type pattern","relation-type-pattern-required":"Relation type pattern is required","relation-types-list":"Relation types to propagate","relation-types-list-hint":"If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required!","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required!","target-key":"Target key","target-key-required":"Target key is required!","attr-mapping-required":"At least one mapping entry should be specified!","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","source-field":"Source field","source-field-required":"Source field is required!","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","originator-alarm-originator":"Alarm Originator","originator-entity":"Entity","clone-message":"Clone message",transform:"Transform","default-ttl":"Default TTL in seconds","default-ttl-required":"Default TTL is required.","min-default-ttl-message":"Only 0 minimum TTL is allowed.","message-count":"Message count (0 - unlimited)","message-count-required":"Message count is required.","min-message-count-message":"Only 0 minimum message count is allowed.","period-seconds":"Period in seconds","period-seconds-required":"Period is required.","use-metadata-period-in-seconds-patterns":"Use period in seconds pattern","use-metadata-period-in-seconds-patterns-hint":"If selected, rule node use period in seconds interval pattern from message metadata or data assuming that intervals are in the seconds.","period-in-seconds-pattern":"Period in seconds pattern","period-in-seconds-pattern-required":"Period in seconds pattern is required","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","alarm-status-filter":"Alarm status filter","alarm-status-list-empty":"Alarm status list is empty","no-alarm-status-matching":"No alarm status matching were found.",propagate:"Propagate alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":'Comma separated address list, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","body-template":"Body Template","body-template-required":"Body Template is required","dynamic-mail-body-type":"Dynamic mail body type","mail-body-type":"Mail body type","request-id-metadata-attribute":"Request Id Metadata attribute name","timeout-sec":"Timeout in seconds","timeout-required":"Timeout is required","min-timeout-message":"Only 0 minimum timeout value is allowed.","endpoint-url-pattern":"Endpoint URL pattern","endpoint-url-pattern-required":"Endpoint URL pattern is required","request-method":"Request method","use-simple-client-http-factory":"Use simple client HTTP factory","ignore-request-body":"Without request body","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message body","read-timeout":"Read timeout in millis","read-timeout-hint":"The value of 0 means an infinite timeout","max-parallel-requests-count":"Max number of parallel requests","max-parallel-requests-count-hint":"The value of 0 specifies no limit in parallel processing",headers:"Headers","headers-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in header/value fields',header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","key-pattern":"Key pattern","key-pattern-hint":"Hint: Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","topic-pattern-required":"Topic pattern is required",topic:"Topic","topic-required":"Topic is required","bootstrap-servers":"Bootstrap servers","bootstrap-servers-required":"Bootstrap servers value is required","other-properties":"Other properties",key:"Key","key-required":"Key is required",retries:"Automatically retry times if fails","min-retries-message":"Only 0 minimum retries is allowed.","batch-size-bytes":"Produces batch size in bytes","min-batch-size-bytes-message":"Only 0 minimum batch size is allowed.","linger-ms":"Time to buffer locally (ms)","min-linger-ms-message":"Only 0 ms minimum value is allowed.","buffer-memory-bytes":"Client buffer max size in bytes","min-buffer-memory-message":"Only 0 minimum buffer size is allowed.",acks:"Number of acknowledgments","key-serializer":"Key serializer","key-serializer-required":"Key serializer is required","value-serializer":"Value serializer","value-serializer-required":"Value serializer is required","topic-arn-pattern":"Topic ARN pattern","topic-arn-pattern-required":"Topic ARN pattern is required","aws-access-key-id":"AWS Access Key ID","aws-access-key-id-required":"AWS Access Key ID is required","aws-secret-access-key":"AWS Secret Access Key","aws-secret-access-key-required":"AWS Secret Access Key is required","aws-region":"AWS Region","aws-region-required":"AWS Region is required","exchange-name-pattern":"Exchange name pattern","routing-key-pattern":"Routing key pattern","message-properties":"Message properties",host:"Host","host-required":"Host is required",port:"Port","port-required":"Port is required","port-range":"Port should be in a range from 1 to 65535.","virtual-host":"Virtual host",username:"Username",password:"Password","automatic-recovery":"Automatic recovery","connection-timeout-ms":"Connection timeout (ms)","min-connection-timeout-ms-message":"Only 0 ms minimum value is allowed.","handshake-timeout-ms":"Handshake timeout (ms)","min-handshake-timeout-ms-message":"Only 0 ms minimum value is allowed.","client-properties":"Client properties","queue-url-pattern":"Queue URL pattern","queue-url-pattern-required":"Queue URL pattern is required","delay-seconds":"Delay (seconds)","min-delay-seconds-message":"Only 0 seconds minimum value is allowed.","max-delay-seconds-message":"Only 900 seconds maximum value is allowed.",name:"Name","name-required":"Name is required","queue-type":"Queue type","sqs-queue-standard":"Standard","sqs-queue-fifo":"FIFO","gcp-project-id":"GCP project ID","gcp-project-id-required":"GCP project ID is required","gcp-service-account-key":"GCP service account key file","gcp-service-account-key-required":"GCP service account key file is required","pubsub-topic-name":"Topic name","pubsub-topic-name-required":"Topic name is required","message-attributes":"Message attributes","message-attributes-hint":'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',"connect-timeout":"Connection timeout (sec)","connect-timeout-required":"Connection timeout is required.","connect-timeout-range":"Connection timeout should be in a range from 1 to 200.","client-id":"Client ID","client-id-hint":'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"device-id":"Device ID","device-id-required":"Device ID is required.","clean-session":"Clean session","enable-ssl":"Enable SSL",credentials:"Credentials","credentials-type":"Credentials type","credentials-type-required":"Credentials type is required.","credentials-anonymous":"Anonymous","credentials-basic":"Basic","credentials-pem":"PEM","credentials-pem-hint":"At least Server CA certificate file or a pair of Client certificate and Client private key files are required","credentials-sas":"Shared Access Signature","sas-key":"SAS Key","sas-key-required":"SAS Key is required.",hostname:"Hostname","hostname-required":"Hostname is required.","azure-ca-cert":"CA certificate file","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"Server CA certificate file","private-key":"Client private key file",cert:"Client certificate file","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","use-metadata-interval-patterns-hint":"If selected, rule node use start and end interval patterns from message metadata or data assuming that intervals are in the milliseconds.","use-message-alarm-data":"Use message alarm data","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields are present","check-all-keys-hint":"If selected, checks that all specified keys are present in the message data and metadata.","check-relation-to-specific-entity":"Check relation to specific entity","check-relation-hint":"Checks existence of relation to specific entity or to any entity based on direction and relation type.","delete-relation-to-specific-entity":"Delete relation to specific entity","delete-relation-hint":"Deletes relation from the originator of the incoming message to the specified entity or list of entities based on direction and type.","remove-current-relations":"Remove current relations","remove-current-relations-hint":"Removes current relations from the originator of the incoming message based on direction and type.","change-originator-to-related-entity":"Change originator to related entity","change-originator-to-related-entity-hint":"Used to process submitted message as a message from another entity.","start-interval":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required!","end-interval-required":"Interval end is required!","smtp-protocol":"Protocol","smtp-host":"SMTP host","smtp-host-required":"SMTP host is required.","smtp-port":"SMTP port","smtp-port-required":"You must supply a smtp port.","smtp-port-range":"SMTP port should be in a range from 1 to 65535.","timeout-msec":"Timeout ms","min-timeout-msec-message":"Only 0 ms minimum value is allowed.","enter-username":"Enter username","enter-password":"Enter password","enable-tls":"Enable TLS","tls-version":"TLS version","enable-proxy":"Enable proxy","use-system-proxy-properties":"Use system proxy properties","proxy-host":"Proxy host","proxy-host-required":"Proxy host is required.","proxy-port":"Proxy port","proxy-port-required":"Proxy port is required.","proxy-port-range":"Proxy port should be in a range from 1 to 65535.","proxy-user":"Proxy user","proxy-password":"Proxy password","proxy-scheme":"Proxy scheme","numbers-to-template":"Phone Numbers To Template","numbers-to-template-required":"Phone Numbers To Template is required","numbers-to-template-hint":'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',"sms-message-template":"SMS message Template","sms-message-template-required":"SMS message Template is required","use-system-sms-settings":"Use system SMS provider settings","min-period-0-seconds-message":"Only 0 second minimum period is allowed.","max-pending-messages":"Maximum pending messages","max-pending-messages-required":"Maximum pending messages is required.","max-pending-messages-range":"Maximum pending messages should be in a range from 1 to 100000.","originator-types-filter":"Originator types filter","interval-seconds":"Interval in seconds","interval-seconds-required":"Interval is required.","min-interval-seconds-message":"Only 1 second minimum interval is allowed.","output-timeseries-key-prefix":"Output timeseries key prefix","output-timeseries-key-prefix-required":"Output timeseries key prefix required.","separator-hint":'Press "Enter" to complete field input.',"entity-details":"Select entity details","entity-details-id":"Id","entity-details-title":"Title","entity-details-country":"Country","entity-details-state":"State","entity-details-city":"City","entity-details-zip":"Zip","entity-details-address":"Address","entity-details-address2":"Address2","entity-details-additional_info":"Additional Info","entity-details-phone":"Phone","entity-details-email":"Email","entity-details-list-empty":"No entity details selected!","no-entity-details-matching":"No entity details matching were found.","custom-table-name":"Custom table name","custom-table-name-required":"Table Name is required","custom-table-hint":"Enter the table name without prefix 'cs_tb_'.","message-field":"Message field","message-field-required":"Message field is required.","table-col":"Table column","table-col-required":"Table column is required.","latitude-key-name":"Latitude key name","longitude-key-name":"Longitude key name","latitude-key-name-required":"Latitude key name is required.","longitude-key-name-required":"Longitude key name is required.","fetch-perimeter-info-from-message-metadata":"Fetch perimeter information from message metadata","perimeter-key-name":"Perimeter key name","perimeter-key-name-required":"Perimeter key name is required.","perimeter-circle":"Circle","perimeter-polygon":"Polygon","perimeter-type":"Perimeter type","circle-center-latitude":"Center latitude","circle-center-latitude-required":"Center latitude is required.","circle-center-longitude":"Center longitude","circle-center-longitude-required":"Center longitude is required.","range-unit-meter":"Meter","range-unit-kilometer":"Kilometer","range-unit-foot":"Foot","range-unit-mile":"Mile","range-unit-nautical-mile":"Nautical mile","range-units":"Range units",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"Please, use the following format for manual definition of polygon: [[lat1,lon1],[lat2,lon2], ... ,[latN,lonN]].","min-inside-duration":"Minimal inside duration","min-inside-duration-value-required":"Minimal inside duration is required","min-inside-duration-time-unit":"Minimal inside duration time unit","min-outside-duration":"Minimal outside duration","min-outside-duration-value-required":"Minimal outside duration is required","min-outside-duration-time-unit":"Minimal outside duration time unit","tell-failure-if-absent":"Tell Failure","tell-failure-if-absent-hint":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"get-latest-value-with-ts":"Fetch timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","trim-redis-queue":"Trim redis queue","redis-queue-max-size":"Redis queue max size","add-metadata-key-values-as-kafka-headers":"Add Message metadata key-value pairs to Kafka record headers","add-metadata-key-values-as-kafka-headers-hint":"If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.","charset-encoding":"Charset encoding","charset-encoding-required":"Charset encoding is required.","charset-us-ascii":"US-ASCII","charset-iso-8859-1":"ISO-8859-1","charset-utf-8":"UTF-8","charset-utf-16be":"UTF-16BE","charset-utf-16le":"UTF-16LE","charset-utf-16":"UTF-16","select-queue-hint":"The queue name can be selected from a drop-down list or add a custom name.","persist-alarm-rules":"Persist state of alarm rules","fetch-alarm-rules":"Fetch state of alarm rules","input-value-key":"Input value key","input-value-key-required":"Input value key is required!","output-value-key":"Output value key","output-value-key-required":"Output value key is required!","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15!","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-cashing":"Use cashing","use-cashing-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required!","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-hint":'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',"output-node-name-hint":"The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.","skip-latest-persistence":"Skip latest persistence","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting to use the timestamp of the message processing instead of the timestamp from the message. Useful for all sorts of sequential processing if you merge messages from multiple sources (devices, assets, etc).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message body and ${metadataKey} to extract value from the message metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time series","message-body-type":"Message body","message-metadata-type":"Message metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-type-field-input":"Type","argument-type-field-input-required":"Argument type is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Hint: use 0 to convert result to integer","add-to-body-field-input":"Add to message body","add-to-metadata-field-input":"Add to message metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Hint: specify a mathematical expression to evaluate. For example, transform Fahrenheit to Celsius using (x - 32) / 1.8)","retained-message":"Retained","attributes-mapping":"Attributes mapping*","latest-telemetry-mapping":"Latest telemetry mapping*","add-mapped-attribute-to":"Add mapped attributes to:","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to:","add-mapped-fields-to":"Add mapped fields to:","add-selected-details-to":"Add selected details to:","clear-selected-details":"Clear selected details","clear-selected-keys":"Clear selected keys","fetch-credentials-to":"Fetch credentials to:","add-originator-attributes-to":"Add originator attributes to:","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound message metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell Failure","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to:",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output message metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end")!',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch:","mapping-of-customers":"Mapping of customer's:",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to:","device-profiles":"Device profiles","mapping-of-tenant":"Mapping of tenant's:","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping entry","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,deps:[{token:$.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),dr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:dr,declarations:[Je],imports:[B,k],exports:[vn,er,Gn,_n,sr,pr,Je]}),dr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,imports:[B,k,vn,er,Gn,_n,sr,pr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,decorators:[{type:s,args:[{declarations:[Je],imports:[B,k],exports:[vn,er,Gn,_n,sr,pr,Je]}]}],ctorParameters:function(){return[{type:$.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map From 78235deb7db3ee76be5551ebf0fda676147f9f21 Mon Sep 17 00:00:00 2001 From: Ruslan Vasylkiv <87172504+rusikv@users.noreply.github.com> Date: Mon, 17 Jul 2023 23:46:06 +0300 Subject: [PATCH 273/421] Removed deleteEntityLatestTimeseries, edited strategies names (#8948) * added rewrite param to delete latest timeseries, enabled single selection deletion * Removed deleteEntityLatestTimeseries, edited strategies names --- ui-ngx/src/app/core/http/attribute.service.ts | 8 ------- .../attribute/attribute-table.component.ts | 21 ++++++++----------- .../delete-timeseries-panel.component.html | 2 +- .../delete-timeseries-panel.component.ts | 8 +++---- .../models/telemetry/telemetry.models.ts | 12 +++++------ .../assets/locale/locale.constant-en_US.json | 8 +++---- 6 files changed, 24 insertions(+), 35 deletions(-) diff --git a/ui-ngx/src/app/core/http/attribute.service.ts b/ui-ngx/src/app/core/http/attribute.service.ts index f568758f41..c810a0af22 100644 --- a/ui-ngx/src/app/core/http/attribute.service.ts +++ b/ui-ngx/src/app/core/http/attribute.service.ts @@ -64,14 +64,6 @@ export class AttributeService { return this.http.delete(url, defaultHttpOptionsFromConfig(config)); } - public deleteEntityLatestTimeseries(entityId: EntityId, timeseries: Array, rewrite = true, - config?: RequestConfig): Observable { - const keys = timeseries.map(attribute => encodeURIComponent(attribute.key)).join(','); - let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/latest/delete?keys=${keys}` + - `&rewrite=${rewrite}`; - return this.http.delete(url, defaultHttpOptionsFromConfig(config)); - } - public saveEntityAttributes(entityId: EntityId, attributeScope: AttributeScope, attributes: Array, config?: RequestConfig): Observable { const attributesData: {[key: string]: any} = {}; diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts index 2969feea76..245411f2f9 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts @@ -386,7 +386,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI if ($event) { $event.stopPropagation(); } - const isMultipleDeletion = isUndefinedOrNull(attribute) && this.dataSource.selection.selected.length > 1; + const isMultipleDeletion = isUndefinedOrNull(attribute) && this.dataSource.selection.selected.length > 1; const target = $event.target || $event.srcElement || $event.currentTarget; const config = new OverlayConfig(); config.backdropClass = 'cdk-overlay-transparent-backdrop'; @@ -424,34 +424,31 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI componentRef.onDestroy(() => { if (componentRef.instance.result !== null) { const strategy = componentRef.instance.result; - const timeseries = attribute ? [attribute]: this.dataSource.selection.selected; + const deleteTimeseries = attribute ? [attribute]: this.dataSource.selection.selected; let deleteAllDataForKeys = false; let rewriteLatestIfDeleted = false; let startTs = null; let endTs = null; let deleteLatest = true; - let task: Observable; - if (strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA_INCLUDING_KEY) { + if (strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA) { deleteAllDataForKeys = true; } - if (strategy === TimeseriesDeleteStrategy.DELETE_OLD_DATA_EXCEPT_LATEST_VALUE) { + if (strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA_EXCEPT_LATEST_VALUE) { deleteAllDataForKeys = true; deleteLatest = false; } if (strategy === TimeseriesDeleteStrategy.DELETE_LATEST_VALUE) { rewriteLatestIfDeleted = componentRef.instance.rewriteLatestIfDeleted; - task = this.attributeService.deleteEntityLatestTimeseries(this.entityIdValue, timeseries, rewriteLatestIfDeleted); + startTs = deleteTimeseries[0].lastUpdateTs; + endTs = startTs + 1; } - if (strategy === TimeseriesDeleteStrategy.DELETE_DATA_FOR_TIME_PERIOD) { + if (strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD) { startTs = componentRef.instance.startDateTime.getTime(); endTs = componentRef.instance.endDateTime.getTime(); rewriteLatestIfDeleted = componentRef.instance.rewriteLatestIfDeleted; } - if (!task) { - task = this.attributeService.deleteEntityTimeseries(this.entityIdValue, timeseries, deleteAllDataForKeys, - startTs, endTs, rewriteLatestIfDeleted, deleteLatest); - } - task.subscribe(() => this.reloadAttributes()); + this.attributeService.deleteEntityTimeseries(this.entityIdValue, deleteTimeseries, deleteAllDataForKeys, + startTs, endTs, rewriteLatestIfDeleted, deleteLatest).subscribe(() => this.reloadAttributes()); } }); } diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html index 0bd9ac21ef..a49f89a6cc 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html @@ -55,7 +55,7 @@
- {{ "attribute.delete-timeseries.rewrite-latest-value-if-deleted" | translate }} + {{ "attribute.delete-timeseries.rewrite-latest-value" | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts index 2bf6b44859..364ecd2c9a 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts @@ -35,7 +35,7 @@ export interface DeleteTimeseriesPanelData { }) export class DeleteTimeseriesPanelComponent implements OnInit { - strategy: string = TimeseriesDeleteStrategy.DELETE_ALL_DATA_INCLUDING_KEY; + strategy: string = TimeseriesDeleteStrategy.DELETE_ALL_DATA; result: string = null; @@ -48,8 +48,8 @@ export class DeleteTimeseriesPanelComponent implements OnInit { strategiesTranslationsMap = timeseriesDeleteStrategyTranslations; multipleDeletionStrategies = [ - TimeseriesDeleteStrategy.DELETE_ALL_DATA_INCLUDING_KEY, - TimeseriesDeleteStrategy.DELETE_OLD_DATA_EXCEPT_LATEST_VALUE + TimeseriesDeleteStrategy.DELETE_ALL_DATA, + TimeseriesDeleteStrategy.DELETE_ALL_DATA_EXCEPT_LATEST_VALUE ]; constructor(@Inject(DELETE_TIMESERIES_PANEL_DATA) public data: DeleteTimeseriesPanelData, @@ -77,7 +77,7 @@ export class DeleteTimeseriesPanelComponent implements OnInit { } isPeriodStrategy(): boolean { - return this.strategy === TimeseriesDeleteStrategy.DELETE_DATA_FOR_TIME_PERIOD; + return this.strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD; } isDeleteLatestStrategy(): boolean { diff --git a/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts b/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts index 76f6b0f247..d93dde4530 100644 --- a/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts +++ b/ui-ngx/src/app/shared/models/telemetry/telemetry.models.ts @@ -62,10 +62,10 @@ export enum TelemetryFeature { } export enum TimeseriesDeleteStrategy { - DELETE_ALL_DATA_INCLUDING_KEY = 'DELETE_ALL_DATA_INCLUDING_KEY', - DELETE_OLD_DATA_EXCEPT_LATEST_VALUE = 'DELETE_OLD_DATA_EXCEPT_LATEST_VALUE', + DELETE_ALL_DATA = 'DELETE_ALL_DATA', + DELETE_ALL_DATA_EXCEPT_LATEST_VALUE = 'DELETE_ALL_DATA_EXCEPT_LATEST_VALUE', DELETE_LATEST_VALUE = 'DELETE_LATEST_VALUE', - DELETE_DATA_FOR_TIME_PERIOD = 'DELETE_DATA_FOR_TIME_PERIOD' + DELETE_ALL_DATA_FOR_TIME_PERIOD = 'DELETE_ALL_DATA_FOR_TIME_PERIOD' } export type TelemetryType = LatestTelemetry | AttributeScope; @@ -98,10 +98,10 @@ export const isClientSideTelemetryType = new Map( export const timeseriesDeleteStrategyTranslations = new Map( [ - [TimeseriesDeleteStrategy.DELETE_ALL_DATA_INCLUDING_KEY, 'attribute.delete-timeseries.all-data-including-key'], - [TimeseriesDeleteStrategy.DELETE_OLD_DATA_EXCEPT_LATEST_VALUE, 'attribute.delete-timeseries.old-data-except-latest'], + [TimeseriesDeleteStrategy.DELETE_ALL_DATA, 'attribute.delete-timeseries.all-data'], + [TimeseriesDeleteStrategy.DELETE_ALL_DATA_EXCEPT_LATEST_VALUE, 'attribute.delete-timeseries.all-data-except-latest-value'], [TimeseriesDeleteStrategy.DELETE_LATEST_VALUE, 'attribute.delete-timeseries.latest-value'], - [TimeseriesDeleteStrategy.DELETE_DATA_FOR_TIME_PERIOD, 'attribute.delete-timeseries.data-for-time-period'] + [TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD, 'attribute.delete-timeseries.all-data-for-time-period'] ] ) 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 091ee1e3bf..190a47788c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -723,11 +723,11 @@ "ends-on": "Ends on", "strategy": "Strategy", "delete-strategy": "Delete strategy", - "all-data-including-key": "Delete all data including key", - "old-data-except-latest": "Delete old data except latest value", + "all-data": "Delete all data", + "all-data-except-latest-value": "Delete all data except latest value", "latest-value": "Delete latest value", - "data-for-time-period": "Delete data for time period", - "rewrite-latest-value-if-deleted": "Rewrite latest value if deleted" + "all-data-for-time-period": "Delete all data for time period", + "rewrite-latest-value": "Rewrite latest value" } }, "api-usage": { From c3e775c35389ad9ca7bc9bf2c2b8ebf31e41896f Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 18 Jul 2023 11:38:41 +0300 Subject: [PATCH 274/421] added mqtt server chain certificate --- .../src/main/resources/thingsboard.yml | 13 ++--- .../dao/device/DeviceConnectivityInfo.java | 1 + .../DeviceConnectivityMqttSslCertService.java | 53 +++++++++++++++++++ .../server/dao/device/DeviceServiceImpl.java | 8 +++ .../TbDeviceConnectivitySslCertService.java | 21 ++++++++ .../dao/util/DeviceConnectivityUtil.java | 3 +- 6 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/device/TbDeviceConnectivitySslCertService.java diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index f11cd15bf8..6eb0a3948c 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -990,27 +990,28 @@ device: connectivity: http: enabled: "${DEVICE_CONNECTIVITY_HTTP_ENABLED:true}" - host: "${DEVICE_CONNECTIVITY_HTTP_HOST:localhost}" + host: "${DEVICE_CONNECTIVITY_HTTP_HOST:}" port: "${DEVICE_CONNECTIVITY_HTTP_PORT:8080}" https: enabled: "${DEVICE_CONNECTIVITY_HTTPS_ENABLED:false}" - host: "${DEVICE_CONNECTIVITY_HTTPS_HOST:localhost}" + host: "${DEVICE_CONNECTIVITY_HTTPS_HOST:}" port: "${DEVICE_CONNECTIVITY_HTTPS_PORT:443}" mqtt: enabled: "${DEVICE_CONNECTIVITY_MQTT_ENABLED:true}" - host: "${DEVICE_CONNECTIVITY_MQTT_HOST:localhost}" + host: "${DEVICE_CONNECTIVITY_MQTT_HOST:}" port: "${DEVICE_CONNECTIVITY_MQTT_PORT:1883}" mqtts: enabled: "${DEVICE_CONNECTIVITY_MQTTS_ENABLED:false}" - host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:localhost}" + host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:}" port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" + tb_server_chain_path: "${DEVICE_CONNECTIVITY_MQTTS_SERVER_CHAIN_PATH:}" coap: enabled: "${DEVICE_CONNECTIVITY_COAP_ENABLED:true}" - host: "${DEVICE_CONNECTIVITY_COAP_HOST:localhost}" + host: "${DEVICE_CONNECTIVITY_COAP_HOST:}" port: "${DEVICE_CONNECTIVITY_COAP_PORT:5683}" coaps: enabled: "${DEVICE_CONNECTIVITY_COAPS_ENABLED:false}" - host: "${DEVICE_CONNECTIVITY_COAPS_HOST:localhost}" + host: "${DEVICE_CONNECTIVITY_COAPS_HOST:}" port: "${DEVICE_CONNECTIVITY_COAPS_PORT:5684}" # Edges parameters diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java index f570919290..5b169a6e79 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java @@ -22,4 +22,5 @@ public class DeviceConnectivityInfo { private Boolean enabled; private String host; private String port; + private String sslCertPath; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java new file mode 100644 index 0000000000..f6736e918f --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java @@ -0,0 +1,53 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.device; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.ResourceUtils; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; + +@Service +@Slf4j +public class DeviceConnectivityMqttSslCertService implements TbDeviceConnectivitySslCertService { + + private String certificate; + @Autowired + private DeviceConnectivityConfiguration deviceConnectivityConfiguration; + + @PostConstruct + private void postConstruct() throws IOException { + String sslCertPath = deviceConnectivityConfiguration.getConnectivity() + .get(MQTTS) + .getSslCertPath(); + if (!sslCertPath.isEmpty() && ResourceUtils.resourceExists(this, sslCertPath)) { + certificate = FileUtils.readFileToString(new File(sslCertPath), StandardCharsets.UTF_8); + } + } + + @Override + public String getMqttSslCertificate() { + return certificate; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 376133b173..f34c1fa99d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -99,6 +99,7 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.JSON_EXAMPL import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CHECK_DOCUMENTATION; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.SERVER_CHAIN_PEM; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getCoapClientCommand; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getCurlCommand; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getMosquittoPublishCommand; @@ -136,6 +137,9 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Tue, 18 Jul 2023 11:51:18 +0300 Subject: [PATCH 275/421] fixed tests --- .../thingsboard/server/controller/DeviceControllerTest.java | 4 ++-- .../dao/device/DeviceConnectivityMqttSslCertService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java index 111ca2e6de..12fa4377f6 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java @@ -766,7 +766,7 @@ public class DeviceControllerTest extends AbstractControllerTest { credentials.getCredentialsId())); assertThat(commands.get(COAP)).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId())); - assertThat(commands.get(COAPS)).isEqualTo(String.format("coap-client-openssl -v 9 -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + assertThat(commands.get(COAPS)).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId())); } @@ -856,7 +856,7 @@ public class DeviceControllerTest extends AbstractControllerTest { assertThat(commands).hasSize(2); assertThat(commands.get(COAP)).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId())); - assertThat(commands.get(COAPS)).isEqualTo(String.format("coap-client-openssl -v 9 -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + assertThat(commands.get(COAPS)).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId())); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java index f6736e918f..e5851b43c4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java @@ -41,7 +41,7 @@ public class DeviceConnectivityMqttSslCertService implements TbDeviceConnectivit String sslCertPath = deviceConnectivityConfiguration.getConnectivity() .get(MQTTS) .getSslCertPath(); - if (!sslCertPath.isEmpty() && ResourceUtils.resourceExists(this, sslCertPath)) { + if (sslCertPath != null && ResourceUtils.resourceExists(this, sslCertPath)) { certificate = FileUtils.readFileToString(new File(sslCertPath), StandardCharsets.UTF_8); } } From bebd5021ee35586726eb95a60d1236bf077b8c13 Mon Sep 17 00:00:00 2001 From: rusikv Date: Tue, 18 Jul 2023 12:24:49 +0300 Subject: [PATCH 276/421] Fixed notification rules page not working when rule saved without additional config --- .../home/pages/notification/rule/rule-table-config.resolver.ts | 2 +- ui-ngx/src/app/shared/models/notification.models.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-table-config.resolver.ts index 86f8120ae0..f547f997bd 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/rule/rule-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/rule/rule-table-config.resolver.ts @@ -81,7 +81,7 @@ export class RuleTableConfigResolver implements Resolve this.translate.instant(TriggerTypeTranslationMap.get(rule.triggerType)) || '', () => ({}), true), new EntityTableColumn('additionalConfig.description', 'notification.description', '30%', - (target) => target.additionalConfig.description || '', + (target) => target.additionalConfig?.description || '', () => ({}), false) ); } diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index 4d8a9cffcd..edafef4704 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -116,7 +116,7 @@ export interface NotificationRule extends Omit, 'la triggerType: TriggerType; triggerConfig: NotificationRuleTriggerConfig; recipientsConfig: NotificationRuleRecipientConfig; - additionalConfig: {description: string}; + additionalConfig?: {description: string}; } export type NotificationRuleTriggerConfig = Partial Date: Wed, 19 Jul 2023 12:28:42 +0300 Subject: [PATCH 277/421] fixes after merge to PE --- .../server/common/data/EntityType.java | 9 ++++-- .../server/common/data/EntityTypeTest.java | 30 +++++++++++++++++++ .../thingsboard/server/common/msg/TbMsg.java | 6 +--- .../TbCopyAttributesToEntityViewNode.java | 4 +-- .../rule/engine/debug/TbMsgGeneratorNode.java | 16 ++++++---- .../engine/telemetry/TbMsgTimeseriesNode.java | 2 +- 6 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 common/data/src/test/java/org/thingsboard/server/common/data/EntityTypeTest.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java index dd53d61f8b..014cc2b521 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java @@ -35,7 +35,13 @@ public enum EntityType { ALARM, RULE_CHAIN, RULE_NODE, - ENTITY_VIEW, + ENTITY_VIEW { + // backward compatibility for TbMsgTypeSwitchNode to return correct rule node connection. + @Override + public String getNormalName() { + return "Entity View"; + } + }, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, @@ -53,7 +59,6 @@ public enum EntityType { NOTIFICATION, NOTIFICATION_RULE; - public static final List NORMAL_NAMES = EnumSet.allOf(EntityType.class).stream() .map(EntityType::getNormalName).collect(Collectors.toUnmodifiableList()); diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/EntityTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/EntityTypeTest.java new file mode 100644 index 0000000000..9eee9ec23d --- /dev/null +++ b/common/data/src/test/java/org/thingsboard/server/common/data/EntityTypeTest.java @@ -0,0 +1,30 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class EntityTypeTest { + + // backward-compatibility test + @Test + void getNormalNameTest() { + assertThat(EntityType.ENTITY_VIEW.getNormalName()).isEqualTo("Entity View"); + } + +} diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index c6c1a36694..125260def5 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -438,11 +438,7 @@ public final class TbMsg implements Serializable { public TbMsgCallback getCallback() { // May be null in case of deserialization; - if (callback != null) { - return callback; - } else { - return TbMsgCallback.EMPTY; - } + return Objects.requireNonNullElse(callback, TbMsgCallback.EMPTY); } public void pushToStack(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index 4f69225274..360e81d644 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -96,7 +96,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) { if (ATTRIBUTES_DELETED.name().equals(msg.getType())) { List attributes = new ArrayList<>(); - for (JsonElement element : new JsonParser().parse(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray()) { + for (JsonElement element : JsonParser.parseString(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray()) { if (element.isJsonPrimitive()) { JsonPrimitive value = element.getAsJsonPrimitive(); if (value.isString()) { @@ -111,7 +111,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { getFutureCallback(ctx, msg, entityView)); } } else { - Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())); + Set attributes = JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData())); List filteredAttributes = attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr.getKey(), entityView)).collect(Collectors.toList()); ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), entityView.getId(), scope, filteredAttributes, diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java index 2f1aae5000..febb2c1067 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java @@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.msg.TbMsgType; @@ -96,7 +97,7 @@ public class TbMsgGeneratorNode implements TbNode { if (initialized.compareAndSet(false, true)) { this.scriptEngine = ctx.createScriptEngine(config.getScriptLang(), ScriptLanguage.TBEL.equals(config.getScriptLang()) ? config.getTbelScript() : config.getJsScript(), "prevMsg", "prevMetadata", "prevMsgType"); - scheduleTickMsg(ctx); + scheduleTickMsg(ctx, null); } } else if (initialized.compareAndSet(true, false)) { destroy(); @@ -113,7 +114,7 @@ public class TbMsgGeneratorNode implements TbNode { log.trace("onMsg onSuccess callback, took {}ms, config {}, msg {}", sw.stopAndGetTotalTimeMillis(), config, msg); if (initialized.get() && (config.getMsgCount() == TbMsgGeneratorNodeConfiguration.UNLIMITED_MSG_COUNT || currentMsgCount < config.getMsgCount())) { ctx.enqueueForTellNext(m, TbNodeConnectionType.SUCCESS); - scheduleTickMsg(ctx); + scheduleTickMsg(ctx, msg); currentMsgCount++; } }, @@ -121,14 +122,14 @@ public class TbMsgGeneratorNode implements TbNode { log.trace("onMsg onFailure callback, took {}ms, config {}, msg {}", sw.stopAndGetTotalTimeMillis(), config, msg, t); if (initialized.get() && (config.getMsgCount() == TbMsgGeneratorNodeConfiguration.UNLIMITED_MSG_COUNT || currentMsgCount < config.getMsgCount())) { ctx.tellFailure(msg, t); - scheduleTickMsg(ctx); + scheduleTickMsg(ctx, msg); currentMsgCount++; } }); } } - private void scheduleTickMsg(TbContext ctx) { + private void scheduleTickMsg(TbContext ctx, TbMsg msg) { log.trace("scheduleTickMsg, config {}", config); long curTs = System.currentTimeMillis(); if (lastScheduledTs == 0L) { @@ -136,7 +137,8 @@ public class TbMsgGeneratorNode implements TbNode { } lastScheduledTs = lastScheduledTs + delay; long curDelay = Math.max(0L, (lastScheduledTs - curTs)); - TbMsg tickMsg = ctx.newMsg(config.getQueueName(), TbMsgType.GENERATOR_NODE_SELF_MSG, ctx.getSelfId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + TbMsg tickMsg = ctx.newMsg(config.getQueueName(), TbMsgType.GENERATOR_NODE_SELF_MSG, ctx.getSelfId(), + getCustomerIdFromMsg(msg), TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); nextTickId = tickMsg.getId(); ctx.tellSelf(tickMsg, curDelay); } @@ -159,6 +161,10 @@ public class TbMsgGeneratorNode implements TbNode { } + private CustomerId getCustomerIdFromMsg(TbMsg msg) { + return msg != null ? msg.getCustomerId() : null; + } + @Override public void destroy() { log.trace("destroy, config {}", config); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index 706135eaa2..4118d28c22 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -88,7 +88,7 @@ public class TbMsgTimeseriesNode implements TbNode { } long ts = computeTs(msg, config.isUseServerTs()); String src = msg.getData(); - Map> tsKvMap = JsonConverter.convertToTelemetry(new JsonParser().parse(src), ts); + Map> tsKvMap = JsonConverter.convertToTelemetry(JsonParser.parseString(src), ts); if (tsKvMap.isEmpty()) { ctx.tellFailure(msg, new IllegalArgumentException("Msg body is empty: " + src)); return; From 2cac9aab9d47841e5e0114a48b57c22812aa4b36 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 19 Jul 2023 12:36:36 +0300 Subject: [PATCH 278/421] fix typo --- .../java/org/thingsboard/server/common/data/EntityType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java index 014cc2b521..8ca6585718 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java @@ -36,7 +36,7 @@ public enum EntityType { RULE_CHAIN, RULE_NODE, ENTITY_VIEW { - // backward compatibility for TbMsgTypeSwitchNode to return correct rule node connection. + // backward compatibility for TbOriginatorTypeSwitchNode to return correct rule node connection. @Override public String getNormalName() { return "Entity View"; From 81f9659af19bb071cd6d5546fddceacdc51a8404 Mon Sep 17 00:00:00 2001 From: rusikv Date: Wed, 19 Jul 2023 14:40:38 +0300 Subject: [PATCH 279/421] Add custom translation for Subject and Text columns in inbox notifications table --- .../notification/inbox/inbox-table-config.resolver.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-config.resolver.ts index f8088c28cb..84aa5d7e33 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/inbox/inbox-table-config.resolver.ts @@ -39,6 +39,7 @@ import { } from '@home/pages/notification/inbox/inbox-notification-dialog.component'; import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; +import { UtilsService } from '@core/services/utils.service'; @Injectable() export class InboxTableConfigResolver implements Resolve> { @@ -48,7 +49,8 @@ export class InboxTableConfigResolver implements Resolve('createdTime', 'common.created-time', this.datePipe, '170px'), new EntityTableColumn('type', 'notification.type', '10%', (notification) => this.translate.instant(NotificationTemplateTypeTranslateMap.get(notification.type).name)), - new EntityTableColumn('subject', 'notification.subject', '30%'), - new EntityTableColumn('text', 'notification.message', '60%') + new EntityTableColumn('subject', 'notification.subject', '30%', + (entity) => this.utilsService.customTranslation(entity.subject, entity.subject)), + new EntityTableColumn('text', 'notification.message', '60%', + (entity) => this.utilsService.customTranslation(entity.text, entity.text)) ); } From d6532d2811e36c2f530e1f9cfb897bffd375223b Mon Sep 17 00:00:00 2001 From: LeoMorgan113 Date: Wed, 19 Jul 2023 16:21:14 +0300 Subject: [PATCH 280/421] Added public-api for websocket services. Exported notification-websocket and websocket services --- ui-ngx/src/app/core/public-api.ts | 2 +- ui-ngx/src/app/core/ws/public-api.ts | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 ui-ngx/src/app/core/ws/public-api.ts diff --git a/ui-ngx/src/app/core/public-api.ts b/ui-ngx/src/app/core/public-api.ts index bbf97cde57..cf36240cea 100644 --- a/ui-ngx/src/app/core/public-api.ts +++ b/ui-ngx/src/app/core/public-api.ts @@ -18,7 +18,7 @@ export * from './api/public-api'; export * from './http/public-api'; export * from './local-storage/local-storage.service'; export * from './services/public-api'; -export * from './ws/telemetry-websocket.service'; +export * from './ws/public-api'; export * from './core.state'; export * from './core.module'; export * from './utils'; diff --git a/ui-ngx/src/app/core/ws/public-api.ts b/ui-ngx/src/app/core/ws/public-api.ts new file mode 100644 index 0000000000..d0f5fa8832 --- /dev/null +++ b/ui-ngx/src/app/core/ws/public-api.ts @@ -0,0 +1,19 @@ +/// +/// Copyright © 2016-2023 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. +/// + +export * from './notification-websocket.service'; +export * from './telemetry-websocket.service'; +export * from './websocket.service'; From 7bd2df3233f7d5f6faf13097c5feeb5d50b0883d Mon Sep 17 00:00:00 2001 From: deaflynx Date: Thu, 13 Jul 2023 13:35:53 +0300 Subject: [PATCH 281/421] EntitiesTableWidgetComponent set rowPointer if has row/dblrow click action --- .../components/widget/lib/entities-table-widget.component.html | 3 ++- .../components/widget/lib/entities-table-widget.component.ts | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html index d89eaeda27..1844ab3ea5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html @@ -88,7 +88,8 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index 00ddd527d4..4a5a891703 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -150,6 +150,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni public displayedColumns: string[] = []; public entityDatasource: EntityDatasource; public noDataDisplayMessageText: string; + public rowPointer: boolean; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -278,6 +279,8 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.setCellButtonAction = !!this.ctx.actionsApi.getActionDescriptors('actionCellButton').length; + this.rowPointer = !!this.ctx.actionsApi.getActionDescriptors('rowClick').length || !!this.ctx.actionsApi.getActionDescriptors('rowDoubleClick').length; + if (this.settings.entitiesTitle && this.settings.entitiesTitle.length) { this.entitiesTitlePattern = this.utils.customTranslation(this.settings.entitiesTitle, this.settings.entitiesTitle); } else { From 8a1bbe04cc6ca5cc153f7802d4f46eed0c4b607b Mon Sep 17 00:00:00 2001 From: deaflynx Date: Wed, 19 Jul 2023 16:48:29 +0300 Subject: [PATCH 282/421] legend.component .tb-legend-label add cursor:pointer --- .../app/modules/home/components/widget/lib/legend.component.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/legend.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/legend.component.scss index ae61340873..a12903ff47 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/legend.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/legend.component.scss @@ -72,6 +72,7 @@ text-align: left; white-space: nowrap; outline: none; + cursor: pointer; &.tb-horizontal { width: 95%; From 881861d80dee78e27fd3d16e69e6ea2739c440f7 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 19 Jul 2023 19:44:47 +0200 Subject: [PATCH 283/421] deleted 'remove latest api' --- .../controller/TelemetryController.java | 56 ------------------- .../DefaultTelemetrySubscriptionService.java | 7 --- .../controller/TelemetryControllerTest.java | 44 --------------- .../dao/timeseries/TimeseriesService.java | 2 - .../dao/timeseries/BaseTimeseriesService.java | 33 ++--------- .../api/RuleEngineTelemetryService.java | 2 - 6 files changed, 4 insertions(+), 140 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index 449e82fc41..6937fa6c84 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -537,57 +537,6 @@ public class TelemetryController extends BaseController { }); } - @ApiOperation(value = "Delete entity latest time-series data (deleteEntityLatestTimeseries)", - notes = "Delete latest time-series for selected entity based on entity id, entity type and keys. " + - TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, - produces = MediaType.APPLICATION_JSON_VALUE) - @ApiResponses(value = { - @ApiResponse(code = 200, message = "Timeseries for the selected keys in the request was removed. " + - "Platform creates an audit log event about entity latest timeseries removal with action type 'TIMESERIES_DELETED'."), - @ApiResponse(code = 400, message = "Platform returns a bad request in case if keys list is empty."), - @ApiResponse(code = 401, message = "User is not authorized to delete entity latest timeseries for selected entity. Most likely, User belongs to different Customer or Tenant."), - @ApiResponse(code = 500, message = "The exception was thrown during processing the request. " + - "Platform creates an audit log event about entity latest timeseries removal with action type 'TIMESERIES_DELETED' that includes an error stacktrace."), - }) - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/{entityType}/{entityId}/timeseries/latest/delete", method = RequestMethod.DELETE) - @ResponseBody - public DeferredResult deleteEntityLatestTimeseries(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, defaultValue = "DEVICE") - @PathVariable("entityType") String entityType, - @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) - @PathVariable("entityId") String entityIdStr, - @ApiParam(value = TELEMETRY_KEYS_DESCRIPTION, required = true) - @RequestParam(name = "keys") String keysStr, - @ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.") - @RequestParam(name = "rewrite", defaultValue = "false") boolean rewrite) throws ThingsboardException { - EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); - return deleteLatestTimeseries(entityId, keysStr, rewrite); - } - - private DeferredResult deleteLatestTimeseries(EntityId entityIdStr, String keysStr, boolean rewrite) throws ThingsboardException { - List keys = toKeysList(keysStr); - if (keys.isEmpty()) { - return getImmediateDeferredResult("Empty keys: " + keysStr, HttpStatus.BAD_REQUEST); - } - SecurityUser user = getCurrentUser(); - - return accessValidator.validateEntityAndCallback(user, Operation.WRITE_TELEMETRY, entityIdStr, (result, tenantId, entityId) -> - tsSubService.deleteLatestAndNotify(tenantId, entityId, keys, rewrite, new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void tmp) { - logLatestTimeseriesDeleted(user, entityId, keys, null); - result.setResult(new ResponseEntity<>(HttpStatus.OK)); - } - - @Override - public void onFailure(Throwable t) { - logLatestTimeseriesDeleted(user, entityId, keys, t); - result.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); - } - }) - ); - } - @ApiOperation(value = "Delete device attributes (deleteDeviceAttributes)", notes = "Delete device attributes using provided Device Id, scope and a list of keys. " + "Referencing a non-existing Device Id will cause an error" + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, @@ -880,11 +829,6 @@ public class TelemetryController extends BaseController { toException(e), keys, startTs, endTs); } - private void logLatestTimeseriesDeleted(SecurityUser user, EntityId entityId, List keys, Throwable e) { - notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.TIMESERIES_DELETED, user, - toException(e), keys); - } - private void logTelemetryUpdated(SecurityUser user, EntityId entityId, List telemetry, Throwable e) { notificationEntityService.logEntityAction(user.getTenantId(), entityId, ActionType.TIMESERIES_UPDATED, user, toException(e), telemetry); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index a97b7f386d..3f5e52796a 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -316,13 +316,6 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer addWsCallback(deleteFuture, list -> onTimeSeriesDelete(tenantId, entityId, keys, list)); } - @Override - public void deleteLatestAndNotify(TenantId tenantId, EntityId entityId, List keys, boolean rewrite, FutureCallback callback) { - ListenableFuture> deleteFuture = tsService.removeLatest(tenantId, entityId, keys, rewrite); - addVoidCallback(deleteFuture, callback); - addWsCallback(deleteFuture, list -> onTimeSeriesDelete(tenantId, entityId, keys, list)); - } - @Override public void saveAttrAndNotify(TenantId tenantId, EntityId entityId, String scope, String key, long value, FutureCallback callback) { saveAndNotify(tenantId, entityId, scope, Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(key, value) diff --git a/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java index 2fdab098e4..d97937c684 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java @@ -46,50 +46,6 @@ public class TelemetryControllerTest extends AbstractControllerTest { doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", invalidRequestBody, String.class, status().isBadRequest()); } - @Test - public void testDeleteLatest() throws Exception { - loginTenantAdmin(); - Device device = createDevice(); - - SingleEntityFilter filter = new SingleEntityFilter(); - filter.setSingleEntity(device.getId()); - - getWsClient().subscribeLatestUpdate(List.of(new EntityKey(TIME_SERIES, "data")), filter); - - getWsClient().registerWaitForUpdate(1); - - long startTs = System.currentTimeMillis(); - - String testBody = "{\"data\": \"value\"}"; - doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", testBody, String.class, status().isOk()); - - long endTs = System.currentTimeMillis(); - - ObjectNode latest = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data", ObjectNode.class); - - Assert.assertNotNull(latest); - var data = latest.get("data"); - Assert.assertNotNull(data); - - Assert.assertEquals("value", data.get(0).get("value").asText()); - - ObjectNode timeseries = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data&startTs={startTs}&endTs={endTs}", ObjectNode.class, startTs, endTs); - - Assert.assertNotNull(timeseries); - - Assert.assertEquals("value", timeseries.get("data").get(0).get("value").asText()); - - doDeleteAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/latest/delete?keys=data", String.class); - - latest = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data", ObjectNode.class); - - Assert.assertTrue(latest.get("data").get(0).get("value").isNull()); - - timeseries = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/timeseries?keys=data&startTs={startTs}&endTs={endTs}", ObjectNode.class, startTs, endTs); - - Assert.assertEquals("value", timeseries.get("data").get(0).get("value").asText()); - } - @Test public void testDeleteAllTelemetryWithLatest() throws Exception { loginTenantAdmin(); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java index 06e42e09e7..c2bc997235 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java @@ -58,8 +58,6 @@ public interface TimeseriesService { ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys); - ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys, boolean rewrite); - ListenableFuture> removeAllLatest(TenantId tenantId, EntityId entityId); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index d101e63a65..6b8bfa9d64 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -46,7 +46,6 @@ import org.thingsboard.server.dao.service.Validator; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -252,37 +251,13 @@ public class BaseTimeseriesService implements TimeseriesService { @Override public ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys) { - return removeLatest(tenantId, entityId, keys, false); - } - - @Override - public ListenableFuture> removeLatest(TenantId tenantId, EntityId entityId, Collection keys, boolean rewrite) { validate(entityId); List> futures = Lists.newArrayListWithExpectedSize(keys.size()); - - ListenableFuture> latestFuture; - - if (rewrite) { - latestFuture = findLatest(tenantId, entityId, keys); - } else { - latestFuture = Futures.immediateFuture(null); + for (String key : keys) { + DeleteTsKvQuery query = new BaseDeleteTsKvQuery(key, 0, System.currentTimeMillis(), false); + futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); } - - return Futures.transformAsync(latestFuture, latest -> { - Map keyTsMap; - if (latest != null) { - keyTsMap = latest.stream().collect(Collectors.toMap(TsKvEntry::getKey, TsKvEntry::getTs)); - } else { - keyTsMap = Collections.emptyMap(); - } - - for (String key : keys) { - long startTs = keyTsMap.getOrDefault(key, 0L); - DeleteTsKvQuery query = new BaseDeleteTsKvQuery(key, startTs, System.currentTimeMillis(), rewrite); - futures.add(timeseriesLatestDao.removeLatest(tenantId, entityId, query)); - } - return Futures.allAsList(futures); - }, MoreExecutors.directExecutor()); + return Futures.allAsList(futures); } @Override diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java index 795eaeb785..a61e83f48f 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineTelemetryService.java @@ -71,6 +71,4 @@ public interface RuleEngineTelemetryService { void deleteAllLatest(TenantId tenantId, EntityId entityId, FutureCallback> callback); void deleteTimeseriesAndNotify(TenantId tenantId, EntityId entityId, List keys, List deleteTsKvQueries, FutureCallback callback); - - void deleteLatestAndNotify(TenantId tenantId, EntityId entityId, List keys, boolean rewrite, FutureCallback callback); } From bcf32658f91faedcad9dfa1731fdde9efa33fc8c Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Thu, 20 Jul 2023 10:08:43 +0300 Subject: [PATCH 284/421] Update js-func.component.html --- ui-ngx/src/app/shared/components/js-func.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e621fe1e50..41e834668e 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.html +++ b/ui-ngx/src/app/shared/components/js-func.component.html @@ -27,7 +27,7 @@ - +
Date: Thu, 20 Jul 2023 11:16:28 +0300 Subject: [PATCH 285/421] UI: Updated file units models --- .../shared/components/unit-input.component.ts | 8 +- ui-ngx/src/assets/model/units.json | 4028 ++++++++--------- 2 files changed, 2014 insertions(+), 2022 deletions(-) diff --git a/ui-ngx/src/app/shared/components/unit-input.component.ts b/ui-ngx/src/app/shared/components/unit-input.component.ts index 01a5db32d0..e70bb0e183 100644 --- a/ui-ngx/src/app/shared/components/unit-input.component.ts +++ b/ui-ngx/src/app/shared/components/unit-input.component.ts @@ -24,10 +24,6 @@ import { ResourcesService } from '@core/services/resources.service'; const unitsModels = '/assets/model/units.json'; -interface UnitsJson { - units: Array; -} - @Component({ selector: 'tb-unit-input', templateUrl: './unit-input.component.html', @@ -151,8 +147,8 @@ export class UnitInputComponent implements ControlValueAccessor, OnInit { private unitsConstant(): Observable> { if (this.fetchUnits$ === null) { - this.fetchUnits$ = this.resourcesService.loadJsonResource(unitsModels).pipe( - map(units => units.units.map(u => ({ + this.fetchUnits$ = this.resourcesService.loadJsonResource>(unitsModels).pipe( + map(units => units.map(u => ({ symbol: u.symbol, name: this.translate.instant(u.name), tags: u.tags diff --git a/ui-ngx/src/assets/model/units.json b/ui-ngx/src/assets/model/units.json index 720719b366..988c3f34ce 100644 --- a/ui-ngx/src/assets/model/units.json +++ b/ui-ngx/src/assets/model/units.json @@ -1,2017 +1,2013 @@ +[{ + "name": "unit.millimeter", + "symbol": "mm", + "tags": ["level","height","distance","length","width","gap","depth","millimeter","millimeters","rainfall","precipitation", + "displacement","position","movement","transition","mm"] +}, { - "units": [ - { - "name": "unit.millimeter", - "symbol": "mm", - "tags": ["level","height","distance","length","width","gap","depth","millimeter","millimeters","rainfall","precipitation", - "displacement","position","movement","transition","mm"] - }, - { - "name": "unit.centimeter", - "symbol": "cm", - "tags": ["level","height","distance","length","width","gap","depth","centimeter","centimeters","rainfall","precipitation", - "displacement","position","movement","transition","cm"] - }, - { - "name": "unit.angstrom", - "symbol": "Å", - "tags": ["level","height","distance","length","width","gap","depth","atomic scale","atomic distance","nanoscale", - "angstrom","angstroms","Å"] - }, - { - "name": "unit.nanometer", - "symbol": "nm", - "tags": ["level","height","distance","length","width","gap","depth","nanoscale","atomic scale","molecular scale", - "nanometer","nanometers","nm"] - }, - { - "name": "unit.micrometer", - "symbol": "µm", - "tags": ["level","height","distance","length","width","gap","depth","microns","micrometer","micrometers","µm"] - }, - { - "name": "unit.meter", - "symbol": "m", - "tags": ["level","height","distance","length","width","gap","depth","meter","meters","m"] - }, - { - "name": "unit.kilometer", - "symbol": "km", - "tags": ["distance","height","length","width","gap","depth","kilometer","kilometers","km"] - }, - { - "name": "unit.inch", - "symbol": "in", - "tags": ["level","height","distance","length","width","gap","depth","inch","inches","in"] - }, - { - "name": "unit.foot", - "symbol": "ft", - "tags": ["level","height","distance","length","width","gap","depth","foot","feet","ft"] - }, - { - "name": "unit.yard", - "symbol": "yd", - "tags": ["level","height","distance","length","width","gap","depth","yard","yards","yd"] - }, - { - "name": "unit.mile", - "symbol": "mi", - "tags": ["level","height","distance","length","width","gap","depth","mile","miles","mi"] - }, - { - "name": "unit.nautical-mile", - "symbol": "nm", - "tags": ["level","height","distance","length","width","gap","depth","nautical mile","nm"] - }, - { - "name": "unit.astronomical-unit", - "symbol": "AU", - "tags": ["distance","celestial bodies","solar system","AU"] - }, - { - "name": "unit.reciprocal-metre", - "symbol": "m⁻¹", - "tags": ["wavenumber","wave density","wave frequency","m⁻¹"] - }, - { - "name": "unit.meter-per-meter", - "symbol": "m/m", - "tags": ["ratio of length to length","meter per meter","m/m"] - }, - { - "name": "unit.steradian", - "symbol": "sr", - "tags": ["solid angle","spatial extent","steradian","sr"] - }, - { - "name": "unit.thou", - "symbol": "thou", - "tags": ["length","measurement","thou"] - }, - { - "name": "unit.barleycorn", - "symbol": "barleycorn", - "tags": ["length","shoe size","barleycorn"] - }, - { - "name": "unit.hand", - "symbol": "hand", - "tags": ["length","horse measurement","hand"] - }, - { - "name": "unit.chain", - "symbol": "ch", - "tags": ["length","land surveying","ch"] - }, - { - "name": "unit.furlong", - "symbol": "fur", - "tags": ["length","land surveying","fur"] - }, - { - "name": "unit.league", - "symbol": "league", - "tags": ["length","historical measurement","league"] - }, - { - "name": "unit.fathom", - "symbol": "fathom", - "tags": ["depth","nautical measurement","fathom"] - }, - { - "name": "unit.cable", - "symbol": "cable", - "tags": ["distance","nautical measurement","cable"] - }, - { - "name": "unit.link", - "symbol": "link", - "tags": ["length","land surveying","link"] - }, - { - "name": "unit.rod", - "symbol": "rod", - "tags": ["length","land surveying","rod"] - }, - { - "name": "unit.nanogram", - "symbol": "ng", - "tags": ["mass","weight","heaviness","load","nanogram","nanograms","ng"] - }, - { - "name": "unit.microgram", - "symbol": "μg", - "tags": ["mass","weight","heaviness","load","μg","microgram"] - }, - { - "name": "unit.milligram", - "symbol": "mg", - "tags": ["mass","weight","heaviness","load","milligram","miligrams","mg"] - }, - { - "name": "unit.gram", - "symbol": "g", - "tags": ["mass","weight","heaviness","load","gram","grams","g"] - }, - { - "name": "unit.kilogram", - "symbol": "kg", - "tags": ["mass","weight","heaviness","load","kilogram","kilograms","kg"] - }, - { - "name": "unit.tonne", - "symbol": "t", - "tags": ["mass","weight","heaviness","load","tonne","tons","t"] - }, - { - "name": "unit.ounce", - "symbol": "oz", - "tags": ["mass","weight","heaviness","load","ounce","ounces","oz"] - }, - { - "name": "unit.pound", - "symbol": "lb", - "tags": ["mass","weight","heaviness","load","pound","pounds","lb"] - }, - { - "name": "unit.stone", - "symbol": "st", - "tags": ["mass","weight","heaviness","load","stone","stones","st"] - }, - { - "name": "unit.hundredweight-count", - "symbol": "cwt", - "tags": ["mass","weight","heaviness","load","hundredweight count","cwt"] - }, - { - "name": "unit.short-tons", - "symbol": "short tons", - "tags": ["mass","weight","heaviness","load","short ton","short tons"] - }, - { - "name": "unit.dalton", - "symbol": "Da", - "tags": ["atomic mass unit","AMU","unified atomic mass unit","dalton","Da"] - }, - { - "name": "unit.grain", - "symbol": "gr", - "tags": ["mass","measurement","grain","gr"] - }, - { - "name": "unit.drachm", - "symbol": "dr", - "tags": ["mass","measurement","drachm","dr"] - }, - { - "name": "unit.quarter", - "symbol": "qr", - "tags": ["mass","measurement","quarter","qr"] - }, - { - "name": "unit.slug", - "symbol": "slug", - "tags": ["mass","measurement","slug"] - }, - { - "name": "unit.carat", - "symbol": "ct", - "tags": ["gemstone","pearl","jewelry","carat","ct"] - }, - { - "name": "unit.cubic-millimeter", - "symbol": "mm³", - "tags": ["volume","capacity","extent","cubic millimeter","mm³"] - }, - { - "name": "unit.cubic-centimeter", - "symbol": "cm³", - "tags": ["volume","capacity","extent","cubic centimeter","cubic centimeters","cm³"] - }, - { - "name": "unit.cubic-meter", - "symbol": "m³", - "tags": ["volume","capacity","extent","cubic meter","cubic meters","m³"] - }, - { - "name": "unit.cubic-kilometer", - "symbol": "km³", - "tags": ["volume","capacity","extent","cubic kilometer","cubic kilometers","km³"] - }, - { - "name": "unit.microliter", - "symbol": "µL", - "tags": ["volume","liquid measurement","microliter","µL"] - }, - { - "name": "unit.milliliter", - "symbol": "mL", - "tags": ["volume","capacity","extent","milliliter","milliliters","mL"] - }, - { - "name": "unit.liter", - "symbol": "l", - "tags": ["volume","capacity","extent","liter","liters","l"] - }, - { - "name": "unit.hectoliter", - "symbol": "hl", - "tags": ["volume","capacity","extent","hectoliter","hectoliters","hl"] - }, - { - "name": "unit.cubic-inch", - "symbol": "in³", - "tags": ["volume","capacity","extent","cubic inch","cubic inches","in³"] - }, - { - "name": "unit.cubic-foot", - "symbol": "ft³", - "tags": ["volume","capacity","extent","cubic foot","cubic feet","ft³"] - }, - { - "name": "unit.cubic-yard", - "symbol": "yd³", - "tags": ["volume","capacity","extent","cubic yard","cubic yards","yd³"] - }, - { - "name": "unit.fluid-ounce", - "symbol": "fl-oz", - "tags": ["volume","capacity","extent","fluid ounce","fluid ounces","fl-oz"] - }, - { - "name": "unit.pint", - "symbol": "pt", - "tags": ["volume","capacity","extent","pint","pints","pt"] - }, - { - "name": "unit.quart", - "symbol": "qt", - "tags": ["volume","capacity","extent","quart","quarts","qt"] - }, - { - "name": "unit.gallon", - "symbol": "gal", - "tags": ["volume","capacity","extent","gallon","gallons","gal"] - }, - { - "name": "unit.oil-barrels", - "symbol": "bbl", - "tags": ["volume","capacity","extent","oil barrel","oil barrels","bbl"] - }, - { - "name": "unit.cubic-meter-per-kilogram", - "symbol": "m³/kg", - "tags": ["specific volume","volume per unit mass","cubic meter per kilogram","m³/kg"] - }, - { - "name": "unit.gill", - "symbol": "gi", - "tags": ["volume","liquid measurement","gi"] - }, - { - "name": "unit.hogshead", - "symbol": "hhd", - "tags": ["volume","liquid measurement","hhd"] - }, - { - "name": "unit.teaspoon", - "symbol": "tsp", - "tags": ["volume","cooking measurement","tsp"] - }, - { - "name": "unit.tablespoon", - "symbol": "tbsp", - "tags": ["volume","cooking measurement","tbsp"] - }, - { - "name": "unit.cup", - "symbol": "cup", - "tags": ["volume","cooking measurement","cup"] - }, - { - "name": "unit.celsius", - "symbol": "°C", - "tags": ["temperature","heat","cold","warmth","degrees","celsius","shipment condition","°C"] - }, - { - "name": "unit.kelvin", - "symbol": "K", - "tags": ["temperature","heat","cold","warmth","degrees","kelvin","K","color quality","white balance","color temperature"] - }, - { - "name": "unit.rankine", - "symbol": "°R", - "tags": ["temperature","heat","cold","warmth","Rankine","°R"] - }, - { - "name": "unit.fahrenheit", - "symbol": "°F", - "tags": ["temperature","heat","cold","warmth","degrees","fahrenheit","°F"] - }, - { - "name": "unit.meter-per-second", - "symbol": "m/s", - "tags": ["speed","velocity","pace","meter per second","m/s","peak","peak to peak","root mean square (RMS)", - "vibration","wind speed","weather"] - }, - { - "name": "unit.kilometer-per-hour", - "symbol": "km/h", - "tags": ["speed","velocity","pace","kilometer per hour","km/h"] - }, - { - "name": "unit.foot-per-second", - "symbol": "ft/s", - "tags": ["speed","velocity","pace","foot per second","ft/s"] - }, - { - "name": "unit.mile-per-hour", - "symbol": "mph", - "tags": ["speed","velocity","pace","mile per hour","mph"] - }, - { - "name": "unit.knot", - "symbol": "kt", - "tags": ["speed","velocity","pace","knot","knots","kt"] - }, - { - "name": "unit.millimeters-per-minute", - "symbol": "mm/min", - "tags": ["feed rate","cutting feed rate","millimeters per minute","mm/min"] - }, - { - "name": "unit.kilometer-per-hour-squared", - "symbol": "km/h²", - "tags": ["acceleration","rate of change of velocity","kilometer per hour squared","km/h²"] - }, - { - "name": "unit.foot-per-second-squared", - "symbol": "ft/s²", - "tags": ["acceleration","rate of change of velocity","foot per second squared","ft/s²"] - }, - { - "name": "unit.pascal", - "symbol": "Pa", - "tags": ["pressure","force","compression","tension","pascal","pascals","Pa","atmospheric pressure","air pressure", - "weather","altitude","flight"] - }, - { - "name": "unit.kilopascal", - "symbol": "kPa", - "tags": ["pressure","force","compression","tension","kilopascal","kilopascals","kPa"] - }, - { - "name": "unit.megapascal", - "symbol": "MPa", - "tags": ["pressure","force","compression","tension","megapascal","megapascals","MPa"] - }, - { - "name": "unit.gigapascal", - "symbol": "GPa", - "tags": ["pressure","force","compression","tension","gigapascal","gigapascals","GPa"] - }, - { - "name": "unit.millibar", - "symbol": "mbar", - "tags": ["pressure","force","compression","tension","millibar","millibars","mbar"] - }, - { - "name": "unit.bar", - "symbol": "bar", - "tags": ["pressure","force","compression","tension","bar","bars"] - }, - { - "name": "unit.kilobar", - "symbol": "kbar", - "tags": ["pressure","force","compression","tension","kilobar","kilobars","kbar"] - }, - { - "name": "unit.newton", - "symbol": "N", - "tags": ["force","pressure","newton","newtons","N","push","pull","weight","gravity","N"] - }, - { - "name": "unit.newton-meter", - "symbol": "Nm", - "tags": ["torque","rotational force","newton meter","Nm"] - }, - { - "name": "unit.foot-pounds", - "symbol": "ft·lbf", - "tags": ["torque","rotational force","foot-pound","foot-pounds","ft·lbf"] - }, - { - "name": "unit.inch-pounds", - "symbol": "in·lbf", - "tags": ["torque","rotational force","inch-pounds","inch-pound","in·lbf"] - }, - { - "name": "unit.newton-per-meter", - "symbol": "N/m", - "tags": ["linear density","force per unit length","newton per meter","N/m"] - }, - { - "name": "unit.atmospheres", - "symbol": "atm", - "tags": ["pressure","force","compression","tension","atmosphere","atmospheres","atmospheric pressure","atm"] - }, - { - "name": "unit.pounds-per-square-inch", - "symbol": "psi", - "tags": ["pressure","force","compression","tension","pounds per square inch","psi"] - }, - { - "name": "unit.torr", - "symbol": "Torr", - "tags": ["pressure","force","compression","tension","vacuum pressure","torr"] - }, - { - "name": "unit.inches-of-mercury", - "symbol": "inHg", - "tags": ["pressure","force","compression","tension","vacuum pressure","inHg","atmospheric pressure","barometric pressure"] - }, - { - "name": "unit.pascal-per-square-meter", - "symbol": "Pa/m²", - "tags": ["pressure","stress","mechanical strength","pascal per square meter","Pa/m²"] - }, - { - "name": "unit.pound-per-square-inch", - "symbol": "psi/in²", - "tags": ["pressure","stress","mechanical strength","pound per square inch","psi/in²"] - }, - { - "name": "unit.newton-per-square-meter", - "symbol": "N/m²", - "tags": ["pressure","stress","mechanical strength","newton per square meter","N/m²"] - }, - { - "name": "unit.kilogram-force-per-square-meter", - "symbol": "kgf/m²", - "tags": ["pressure","stress","mechanical strength","kilogram-force per square meter","kgf/m²"] - }, - { - "name": "unit.pascal-per-square-centimeter", - "symbol": "Pa/cm²", - "tags": ["pressure","stress","mechanical strength","pascal per square centimeter","Pa/cm²"] - }, - { - "name": "unit.ton-force-per-square-inch", - "symbol": "tonf/in²", - "tags": ["pressure","stress","mechanical strength","ton-force per square inch","tonf/in²"] - }, - { - "name": "unit.kilonewton-per-square-meter", - "symbol": "kN/m²", - "tags": ["stress","pressure","mechanical strength","kilonewton per square meter","kN/m²"] - }, - { - "name": "unit.newton-per-square-millimeter", - "symbol": "N/mm²", - "tags": ["stress","pressure","mechanical strength","newton per square millimeter","N/mm²"] - }, - { - "name": "unit.microjoule", - "symbol": "μJ", - "tags": ["energy","microjoule","microjoules","μJ"] - }, - { - "name": "unit.millijoule", - "symbol": "mJ", - "tags": ["energy","millijoule","millijoules","mJ"] - }, - { - "name": "unit.joule", - "symbol": "J", - "tags": ["joule","joules","energy","work done","heat","electricity","mechanical work"] - }, - { - "name": "unit.kilojoule", - "symbol": "kJ", - "tags": ["energy","kilojoule","kilojoules","kJ"] - }, - { - "name": "unit.megajoule", - "symbol": "MJ", - "tags": ["energy","megajoule","megajoules","MJ"] - }, - { - "name": "unit.gigajoule", - "symbol": "GJ", - "tags": ["energy","gigajoule","gigajoules","GJ"] - }, - { - "name": "unit.watt-hour", - "symbol": "Wh", - "tags": ["energy","watt-hour","watt-hours","energy usage","power consumption","energy consumption","electricity usage"] - }, - { - "name": "unit.kilowatt-hour", - "symbol": "kWh", - "tags": ["energy","kilowatt-hour","kilowatt-hours","energy usage","power consumption","energy consumption","electricity usage"] - }, - { - "name": "unit.electron-volts", - "symbol": "eV", - "tags": ["energy","subatomic particles","radiation"] - }, - { - "name": "unit.joules-per-coulomb", - "symbol": "J/C", - "tags": ["electrical potential energy","voltage","joules per coulomb","J/C"] - }, - { - "name": "unit.british-thermal-unit", - "symbol": "BTU", - "tags": ["energy","heat","work done","british thermal unit","british thermal units","BTU"] - }, - { - "name": "unit.foot-pound", - "symbol": "ft·lb", - "tags": ["energy","foot-pound","foot-pounds","ft·lb","ft⋅lbf"] - }, - { - "name": "unit.calorie", - "symbol": "Cal", - "tags": ["energy","food energy","Calorie","Calories","Cal"] - }, - { - "name": "unit.small-calorie", - "symbol": "cal", - "tags": ["energy","small calorie","calories","cal"] - }, - { - "name": "unit.kilocalorie", - "symbol": "kcal", - "tags": ["energy","small calorie","kilocalories","kcal"] - }, - { - "name": "unit.joule-per-kelvin", - "symbol": "J/K", - "tags": ["specific heat capacity","heat capacity per unit temperature","joule per kelvin","J/K"] - }, - { - "name": "unit.joule-per-kilogram-kelvin", - "symbol": "J/(kg·K)", - "tags": ["specific heat capacity","heat capacity per unit mass and temperature","joule per kilogram-kelvin","J/(kg·K)"] - }, - { - "name": "unit.joule-per-kilogram", - "symbol": "J/kg", - "tags": ["specific energy","specific energy capacity","joule per kilogram","J/kg"] - }, - { - "name": "unit.watt-per-meter-kelvin", - "symbol": "W/(m·K)", - "tags": ["thermal conductivity","watt per meter-kelvin","W/(m·K)"] - }, - { - "name": "unit.joule-per-cubic-meter", - "symbol": "J/m³", - "tags": ["energy density","joule per cubic meter","J/m³"] - }, - { - "name": "unit.therm", - "symbol": "thm", - "tags": ["energy","natural gas consumption","BTU","therm","thm"] - }, - { - "name": "unit.electric-dipole-moment", - "symbol": "C·m", - "tags": ["electric dipole","dipole moment","coulomb meter","C·m"] - }, - { - "name": "unit.magnetic-dipole-moment", - "symbol": "A·m²", - "tags": ["magnetic dipole","dipole moment","ampere square meter","A·m²"] - }, - { - "name": "unit.debye", - "symbol": "D", - "tags": ["polarization","electric dipole moment","debye","D"] - }, - { - "name": "unit.coulomb-per-square-meter-per-volt", - "symbol": "C·m²/V", - "tags": ["polarization","electric field","coulomb per square meter per volt","C·m²/V"] - }, - { - "name": "unit.milliwatt", - "symbol": "mW", - "tags": ["power","horsepower","performance","milliwatt","milliwatts","electricity","mW"] - }, - { - "name": "unit.microwatt", - "symbol": "μW", - "tags": ["power","horsepower","performance","microwatt","microwatts","electricity","μW"] - }, - { - "name": "unit.watt", - "symbol": "W", - "tags": ["power","horsepower","performance","watt","watts","electricity","W"] - }, - { - "name": "unit.kilowatt", - "symbol": "kW", - "tags": ["power","horsepower","performance","kilowatt","kilowatts","electricity","kW"] - }, - { - "name": "unit.megawatt", - "symbol": "MW", - "tags": ["power","horsepower","performance","megawatt","megawatts","electricity","MW"] - }, - { - "name": "unit.gigawatt", - "symbol": "GW", - "tags": ["power","horsepower","performance","gigawatt","gigawatts","electricity","GW"] - }, - { - "name": "unit.metric-horsepower", - "symbol": "PS", - "tags": ["power","performance","metric horsepower","PS"] - }, - { - "name": "unit.milliwatt-per-square-centimeter", - "symbol": "mW/cm²", - "tags": ["power density","radiation intensity","sunlight intensity","signal power","intensity", - "milliwatts per square centimeter","UV Intensity","mW/cm²"] - }, - { - "name": "unit.watt-per-square-centimeter", - "symbol": "W/cm²", - "tags": ["power density","intensity of power","watts per square centimeter","W/cm²"] - }, - { - "name": "unit.kilowatt-per-square-centimeter", - "symbol": "kW/cm²", - "tags": ["power density","intensity of power","kilowatts per square centimeter","kW/cm²"] - }, - { - "name": "unit.milliwatt-per-square-meter", - "symbol": "mW/m²", - "tags": ["power density","intensity of power","milliwatts per square meter","mW/m²"] - }, - { - "name": "unit.watt-per-square-meter", - "symbol": "W/m²", - "tags": ["power density","intensity of power","watts per square meter","W/m²"] - }, - { - "name": "unit.kilowatt-per-square-meter", - "symbol": "kW/m²", - "tags": ["power density","intensity of power","kilowatts per square meter","kW/m²"] - }, - { - "name": "unit.watt-per-square-inch", - "symbol": "W/in²", - "tags": ["power density","intensity of power","watts per square inch","W/in²"] - }, - { - "name": "unit.kilowatt-per-square-inch", - "symbol": "kW/in²", - "tags": ["power density","intensity of power","kilowatts per square inch","kW/in²"] - }, - { - "name": "unit.horsepower", - "symbol": "hp", - "tags": ["power","horsepower","performance","electricity","horsepowers","hp"] - }, - { - "name": "unit.btu-per-hour", - "symbol": "BTU/h", - "tags": ["power","heat transfer","thermal energy","HVAC","BTU/h"] - }, - { - "name": "unit.coulomb", - "symbol": "C", - "tags": ["charge","electricity","electrostatics","Coulomb","C"] - }, - { - "name": "unit.millicoulomb", - "symbol": "mC", - "tags": ["charge","electricity","electrostatics","millicoulombs","mC"] - }, - { - "name": "unit.microcoulomb", - "symbol": "µC", - "tags": ["charge","electricity","electrostatics","microcoulomb","µC"] - }, - { - "name": "unit.picocoulomb", - "symbol": "pC", - "tags": ["charge","electricity","electrostatics","picocoulomb","pC"] - }, - { - "name": "unit.coulomb-per-meter", - "symbol": "C/m", - "tags": ["electric displacement field per length","coulomb per meter","C/m"] - }, - { - "name": "unit.coulomb-per-cubic-meter", - "symbol": "C/m³", - "tags": ["electric charge density","coulomb per cubic meter","C/m³"] - }, - { - "name": "unit.coulomb-per-square-meter", - "symbol": "C/m²", - "tags": ["electric surface charge density","coulomb per square meter","C/m²"] - }, - { - "name": "unit.square-millimeter", - "symbol": "mm²", - "tags": ["area","lot","zone","space","region","square millimeter","square millimeters","mm²","sq-mm"] - }, - { - "name": "unit.square-centimeter", - "symbol": "cm²", - "tags": ["area","lot","zone","space","region","square centimeter","square centimeters","cm²","sq-cm"] - }, - { - "name": "unit.square-meter", - "symbol": "m²", - "tags": ["area","lot","zone","space","region","square meter","square meters","m²","sq-m"] - }, - { - "name": "unit.hectare", - "symbol": "ha", - "tags": ["area","lot","zone","space","region","hectare","hectares","ha"] - }, - { - "name": "unit.square-kilometer", - "symbol": "km²", - "tags": ["area","lot","zone","space","region","square kilometer","square kilometers","km²","sq-km"] - }, - { - "name": "unit.square-inch", - "symbol": "in²", - "tags": ["area","lot","zone","space","region","square inch","square inches","in²","sq-in"] - }, - { - "name": "unit.square-foot", - "symbol": "ft²", - "tags": ["area","lot","zone","space","region","square foot","square feet","ft²","sq-ft"] - }, - { - "name": "unit.square-yard", - "symbol": "yd²", - "tags": ["area","lot","zone","space","region","square yard","square yards","yd²","sq-yd"] - }, - { - "name": "unit.acre", - "symbol": "a", - "tags": ["area","lot","zone","space","region","acre","acres","a"] - }, - { - "name": "unit.square-mile", - "symbol": "ml²", - "tags": ["area","lot","zone","space","region","square mile","square miles","ml²","sq-mi"] - }, - { - "name": "unit.are", - "symbol": "are", - "tags": ["area","land measurement","are"] - }, - { - "name": "unit.barn", - "symbol": "barn", - "tags": ["cross-sectional area","particle physics","nuclear physics","barn"] - }, - { - "name": "unit.circular-inch", - "symbol": "circin", - "tags": ["area","circular measurement","circular inch","circin"] - }, - { - "name": "unit.milliampere-hour", - "symbol": "mAh", - "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity", - "electrical flow","milliampere-hour","milliampere-hours","mAh"] - }, - { - "name": "unit.ampere-hours", - "symbol": "Ah", - "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity", - "electrical flow","ampere","ampere-hours","Ah"] - }, - { - "name": "unit.kiloampere-hours", - "symbol": "kAh", - "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity","electrical flow", - "kiloampere-hours","kiloampere-hour","kAh"] - }, - { - "name": "unit.nanoampere", - "symbol": "nA", - "tags": ["current","amperes","nanoampere","nA"] - }, - { - "name": "unit.picoampere", - "symbol": "pA", - "tags": ["current","amperes","picoampere","pA"] - }, - { - "name": "unit.microampere", - "symbol": "μA", - "tags": ["electric current","microampere","microamperes","μA"] - }, - { - "name": "unit.milliampere", - "symbol": "mA", - "tags": ["electric current","milliampere","milliamperes","mA"] - }, - { - "name": "unit.ampere", - "symbol": "A", - "tags": ["electric current","current flow","flow of electricity","electrical flow","ampere","amperes","amperage","A"] - }, - { - "name": "unit.kiloamperes", - "symbol": "kA", - "tags": ["electric current","current flow","kiloamperes","kA"] - }, - { - "name": "unit.microampere-per-square-centimeter", - "symbol": "µA/cm²", - "tags": ["Current density","microampere per square centimeter","µA/cm²"] - }, - { - "name": "unit.ampere-per-square-meter", - "symbol": "A/m²", - "tags": ["current density","current per unit area","ampere per square meter","A/m²"] - }, - { - "name": "unit.ampere-per-meter", - "symbol": "A/m", - "tags": ["magnetic field strength","magnetic field intensity","ampere per meter","A/m"] - }, - { - "name": "unit.oersted", - "symbol": "Oe", - "tags": ["magnetic field","oersted","Oe"] - }, - { - "name": "unit.bohr-magneton", - "symbol": "μB", - "tags": ["atomic physics","magnetic moment","bohr magneton","μB"] - }, - { - "name": "unit.ampere-meter-squared", - "symbol": "A·m²", - "tags": ["magnetic moment","dipole moment","ampere-meter squared","A·m²"] - }, - { - "name": "unit.ampere-meter", - "symbol": "A·m", - "tags": ["magnetic field","current loop","ampere-meter","A·m"] - }, - { - "name": "unit.nanovolt", - "symbol": "nV", - "tags": ["voltage","volts","nanovolt","nV"] - }, - { - "name": "unit.picovolt", - "symbol": "pV", - "tags": ["voltage","volts","picovolt","pV"] - }, - { - "name": "unit.millivolts", - "symbol": "mV", - "tags": ["electric potential","electric tension","voltage","millivolt","millivolts","mV"] - }, - { - "name": "unit.microvolts", - "symbol": "μV", - "tags": ["electric potential","electric tension","voltage","microvolt","microvolts","μV"] - }, - { - "name": "unit.volt", - "symbol": "V", - "tags": ["electric potential","electric tension","voltage","volt","volts","V","power source","battery","battery level"] - }, - { - "name": "unit.kilovolts", - "symbol": "kV", - "tags": ["electric potential","electric tension","voltage","kilovolt","kilovolts","kV"] - }, - { - "name": "unit.dbmV", - "symbol": "dBmV", - "tags": ["decibels millivolt","voltage level","signal","dBmV"] - }, - { - "name": "unit.volt-meter", - "symbol": "V·m", - "tags": ["electric flux","volt-meter","V·m"] - }, - { - "name": "unit.kilovolt-meter", - "symbol": "kV·m", - "tags": ["electric flux","kilovolt-meter","kV·m"] - }, - { - "name": "unit.megavolt-meter", - "symbol": "MV·m", - "tags": ["electric flux","megavolt-meter","MV·m"] - }, - { - "name": "unit.microvolt-meter", - "symbol": "µV·m", - "tags": ["electric flux","microvolt-meter","µV·m"] - }, - { - "name": "unit.millivolt-meter", - "symbol": "mV·m", - "tags": ["electric flux","millivolt-meter","mV·m"] - }, - { - "name": "unit.nanovolt-meter", - "symbol": "nV·m", - "tags": ["electric flux","nanovolt-meter","nV·m"] - }, - { - "name": "unit.ohm", - "symbol": "Ω", - "tags": ["electrical resistance","resistance","impedance","ohm"] - }, - { - "name": "unit.microohm", - "symbol": "μΩ", - "tags": ["electrical resistance","resistance","microohm","μΩ"] - }, - { - "name": "unit.milliohm", - "symbol": "mΩ", - "tags": ["electrical resistance","resistance","milliohm","mΩ"] - }, - { - "name": "unit.kilohm", - "symbol": "kΩ", - "tags": ["electrical resistance","resistance","kilohm","kΩ"] - }, - { - "name": "unit.megohm", - "symbol": "MΩ", - "tags": ["electrical resistance","resistance","megohm","MΩ"] - }, - { - "name": "unit.gigohm", - "symbol": "GΩ", - "tags": ["electrical resistance","resistance","gigohm","GΩ"] - }, - { - "name": "unit.hertz", - "symbol": "Hz", - "tags": ["frequency","cycles per second","hertz","Hz"] - }, - { - "name": "unit.kilohertz", - "symbol": "kHz", - "tags": ["frequency","cycles per second","kilohertz","kHz"] - }, - { - "name": "unit.megahertz", - "symbol": "MHz", - "tags": ["frequency","cycles per second","megahertz","MHz"] - }, - { - "name": "unit.gigahertz", - "symbol": "GHz", - "tags": ["frequency","cycles per second","gigahertz","GHz"] - }, - { - "name": "unit.rpm", - "symbol": "RPM", - "tags": ["speed","velocity","cycle","engine","Revolutions Per Minute","RPM","angular velocity","rotation speed"] - }, - { - "name": "unit.candela-per-square-meter", - "symbol": "cd/m²", - "tags": ["brightness","light level","Luminance","Candela per square meter","cd/m²"] - }, - { - "name": "unit.candela", - "symbol": "cd", - "tags": ["light intensity","candle power","luminous intensity","Candela","cd"] - }, - { - "name": "unit.lumen", - "symbol": "lm", - "tags": ["total light output","light power","luminous flux","Lumen","lm"] - }, - { - "name": "unit.lux", - "symbol": "lx", - "tags": ["illumination","light level on a surface","illuminance","Lux","lx"] - }, - { - "name": "unit.foot-candle", - "symbol": "fc", - "tags": ["illuminance","light level","foot-candle","fc"] - }, - { - "name": "unit.lumen-per-square-meter", - "symbol": "lm/m²", - "tags": ["illuminance","light level","lumen per square meter","lm/m²"] - }, - { - "name": "unit.lux-second", - "symbol": "lx·s", - "tags": ["light exposure","illumination time","light dosage","Lux second","lx·s"] - }, - { - "name": "unit.lumen-second", - "symbol": "lm·s", - "tags": ["total light energy","luminous energy","Lumen second","lm·s"] - }, - { - "name": "unit.lumens-per-watt", - "symbol": "lm/W", - "tags": ["lighting efficiency","light output per energy","luminous efficacy","Lumens per watt","lm/W"] - }, - { - "name": "unit.absorbance", - "symbol": "AU", - "tags": ["optical density","light absorption","absorbance","AU"] - }, - { - "name": "unit.mole", - "symbol": "mol", - "tags": ["amount of substance","substance quantity","mole","moles","mol"] - }, - { - "name": "unit.nanomole", - "symbol": "nmol", - "tags": ["amount of substance","substance quantity","concentration","nanomole","nmol"] - }, - { - "name": "unit.micromole", - "symbol": "μmol", - "tags": ["amount of substance","substance quantity","micromole","μmol"] - }, - { - "name": "unit.millimole", - "symbol": "mmol", - "tags": ["amount of substance","substance quantity","millimole","mmol"] - }, - { - "name": "unit.kilomole", - "symbol": "kmol", - "tags": ["amount of substance","substance quantity","kilomole","kmol"] - }, - { - "name": "unit.mole-per-cubic-meter", - "symbol": "mol/m³", - "tags": ["concentration","amount of substance","mole per cubic meter","mol/m³"] - }, - { - "name": "unit.percent", - "symbol": "%", - "tags": ["power source","state of charge (SoC)","battery","battery level","level","humidity","moisture","percentage", - "relative humidity","water content","soil moisture","irrigation","water in soil","soil water content","VWC", - "Volumetric Water Content","Total Harmonic Distortion","THD","power quality","UV Transmittance","%"] - }, - { - "name": "unit.rssi", - "symbol": "rssi", - "tags": ["signal strength","signal level","received signal strength indicator","rssi","dBm"] - }, - { - "name": "unit.ppm", - "symbol": "ppm", - "tags": ["carbon dioxide","co²","carbon monoxide","co","aqi","air quality","total volatile organic compounds","tvoc","ppm"] - }, - { - "name": "unit.ppb", - "symbol": "ppb", - "tags": ["ozone","o³","nitrogen dioxide","no²","sulfur dioxide","so²","aqi","air quality","tvoc","ppb"] - }, - { - "name": "unit.micrograms-per-cubic-meter", - "symbol": "µg/m³", - "tags": ["coarse particulate matter","pm10","fine particulate matter","pm2.5","aqi","air quality", - "total volatile organic compounds","tvoc","micrograms per cubic meter","µg/m³"] - }, - { - "name": "unit.aqi", - "symbol": "aqi", - "tags": ["AQI","air quality index"] - }, - { - "name": "unit.gram-per-cubic-meter", - "symbol": "g/m³", - "tags": ["humidity","moisture","absolute humidity","g/m³"] - }, - { - "name": "unit.gram-per-kilogram", - "symbol": "g/kg", - "tags": ["humidity","moisture","specific humidity","g/kg"] - }, - { - "name": "unit.millimeters-per-second", - "symbol": "mm/s", - "tags": ["velocity","speed","rate of motion","peak","peak to peak","root mean square (RMS)","vibration","mm/s"] - }, - { - "name": "unit.neper", - "symbol": "Np", - "tags": ["logarithmic unit","ratio","gain","loss","attenuation","neper","Np"] - }, - { - "name": "unit.bel", - "symbol": "B", - "tags": ["logarithmic unit","power ratio","intensity ratio","bel","B"] - }, - { - "name": "unit.decibel", - "symbol": "dB", - "tags": ["noise level","sound level","volume","acoustics","decibel","dB"] - }, - { - "name": "unit.meters-per-second-squared", - "symbol": "m/s²", - "tags": ["peak","peak to peak","root mean square (RMS)","vibration","meters per second squared","m/s²"] - }, - { - "name": "unit.becquerel", - "symbol": "Bq", - "tags": ["radioactivity","radiation","becquerel","Bq"] - }, - { - "name": "unit.curie", - "symbol": "Ci", - "tags": ["radioactivity","radiation","curie","Ci"] - }, - { - "name": "unit.gray", - "symbol": "Gy", - "tags": ["radiation dose","gray","Gy"] - }, - { - "name": "unit.sievert", - "symbol": "Sv", - "tags": ["radiation dose","sievert","radiation dose equivalent2","Sv"] - }, - { - "name": "unit.roentgen", - "symbol": "R", - "tags": ["radiation exposure","roentgen","R"] - }, - { - "name": "unit.cps", - "symbol": "cps", - "tags": ["radiation detection","counts per second","cps"] - }, - { - "name": "unit.rad", - "symbol": "Rad", - "tags": ["radiation dose","rad"] - }, - { - "name": "unit.rem", - "symbol": "Rem", - "tags": ["radiation dose equivalent","rem"] - }, - { - "name": "unit.dps", - "symbol": "dps", - "tags": ["radioactive decay","radioactivity","disintegrations per second","dps"] - }, - { - "name": "unit.rutherford", - "symbol": "Rd", - "tags": ["radioactive decay","radioactivity","rutherford","Rd"] - }, - { - "name": "unit.coulombs-per-kilogram", - "symbol": "C/kg", - "tags": ["radiation exposure","dose","coulombs per kilogram","electric charge-to-mass ratio","C/kg"] - }, - { - "name": "unit.becquerels-per-cubic-meter", - "symbol": "Bq/m³", - "tags": ["radioactivity","radiation","becquerels per cubic meter","Bq/m³"] - }, - { - "name": "unit.curies-per-liter", - "symbol": "Ci/L", - "tags": ["radioactivity","radiation","curies per liter","Ci/L"] - }, - { - "name": "unit.becquerels-per-second", - "symbol": "Bq/s", - "tags": ["radioactive decay rate","becquerels per second","Bq/s"] - }, - { - "name": "unit.curies-per-second", - "symbol": "Ci/s", - "tags": ["radioactive decay rate","curies per second","Ci/s"] - }, - { - "name": "unit.gy-per-second", - "symbol": "Gy/s", - "tags": ["absorbed dose rate","radiation dose rate","gray per second","Gy/s"] - }, - { - "name": "unit.watt-per-steradian", - "symbol": "W/sr", - "tags": ["radiant intensity","power per unit solid angle","watt per steradian","W/sr"] - }, - { - "name": "unit.watt-per-square-metre-steradian", - "symbol": "W/(m²·sr)", - "tags": ["radiance","radiant flux density","watt per square metre-steradian","W/(m²·sr)"] - }, - { - "name": "unit.ph-level", - "symbol": "pH", - "tags": ["acidity","alkalinity","neutral","acid","base","pH","soil pH","water quality","water pH"] - }, - { - "name": "unit.turbidity", - "symbol": "NTU", - "tags": ["water turbidity","water clarity","Nephelometric Turbidity Units","NTU"] - }, - { - "name": "unit.mg-per-liter", - "symbol": "mg/L", - "tags": ["dissolved oxygen","water quality","mg/L"] - }, - { - "name": "unit.microsiemens-per-centimeter", - "symbol": "µS/cm", - "tags": ["Electrical conductivity","water quality","soil quality","microsiemens per centimeter","µS/cm"] - }, - { - "name": "unit.millisiemens-per-meter", - "symbol": "mS/m", - "tags": ["Electrical conductivity","water quality","soil quality","millisiemens per meter","mS/m"] - }, - { - "name": "unit.siemens-per-meter", - "symbol": "S/m", - "tags": ["Electrical conductivity","water quality","soil quality","siemens per meter","S/m"] - }, - { - "name": "unit.kilogram-per-cubic-meter", - "symbol": "kg/m³", - "tags": ["density","mass per unit volume","kg/m³"] - }, - { - "name": "unit.gram-per-cubic-centimeter", - "symbol": "g/cm³", - "tags": ["density","mass per unit volume","g/cm³"] - }, - { - "name": "unit.kilogram-per-square-meter", - "symbol": "kg/m²", - "tags": ["density","surface density","areal density","mass per unit area","kg/m²"] - }, - { - "name": "unit.milligram-per-milliliter", - "symbol": "mg/mL", - "tags": ["concentration","mass per volume","mg/mL"] - }, - { - "name": "unit.pound-per-cubic-foot", - "symbol": "lb/ft³", - "tags": ["Density","mass per unit volume","lb/ft³"] - }, - { - "name": "unit.ounces-per-cubic-inch", - "symbol": "oz/in³", - "tags": ["density","mass per unit volume","oz/in³"] - }, - { - "name": "unit.tons-per-cubic-yard", - "symbol": "ton/yd³", - "tags": ["density","mass per unit volume","ton/yd³"] - }, - { - "name": "unit.particle-density", - "symbol": "particles/mL", - "tags": ["particle concentration","count","particles/mL"] - }, - { - "name": "unit.kilometers-per-liter", - "symbol": "km/L", - "tags": ["fuel efficiency","km/L"] - }, - { - "name": "unit.miles-per-gallon", - "symbol": "mpg", - "tags": ["fuel efficiency","mpg"] - }, - { - "name": "unit.liters-per-100-km", - "symbol": "L/100km", - "tags": ["fuel efficiency","L/100km"] - }, - { - "name": "unit.gallons-per-mile", - "symbol": "gal/mi", - "tags": ["fuel efficiency","gal/mi"] - }, - { - "name": "unit.liters-per-hour", - "symbol": "L/hr", - "tags": ["fuel consumption","L/hr"] - }, - { - "name": "unit.gallons-per-hour", - "symbol": "gal/hr", - "tags": ["fuel consumption","gal/hr"] - }, - { - "name": "unit.beats-per-minute", - "symbol": "bpm", - "tags": ["heart rate","pulse","bpm"] - }, - { - "name": "unit.millimeters-of-mercury", - "symbol": "mmHg", - "tags": ["blood pressure","systolic","diastolic","mmHg"] - }, - { - "name": "unit.milligrams-per-deciliter", - "symbol": "mg/dL", - "tags": ["glucose","blood sugar","glucose level","mg/dL"] - }, - { - "name": "unit.g-force", - "symbol": "G", - "tags": ["acceleration","gravity","force","g-load","G"] - }, - { - "name": "unit.kilonewton", - "symbol": "kN", - "tags": ["force","kN"] - }, - { - "name": "unit.kilogram-force", - "symbol": "kgf", - "tags": ["force","kgf"] - }, - { - "name": "unit.pound-force", - "symbol": "lbf", - "tags": ["force","lbf"] - }, - { - "name": "unit.kilopound-force", - "symbol": "klbf", - "tags": ["force","klbf"] - }, - { - "name": "unit.dyne", - "symbol": "dyn", - "tags": ["force","dyn"] - }, - { - "name": "unit.poundal", - "symbol": "pdl", - "tags": ["force","pdl"] - }, - { - "name": "unit.kip", - "symbol": "kip", - "tags": ["force","kip"] - }, - { - "name": "unit.gal", - "symbol": "Gal", - "tags": ["acceleration","gravity","g-force","Gal"] - }, - { - "name": "unit.gravity", - "symbol": "gravity", - "tags": ["acceleration","gravity","g-force"] - }, - { - "name": "unit.hectopascal", - "symbol": "hPa", - "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","hPa"] - }, - { - "name": "unit.atmosphere", - "symbol": "atm", - "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","atm"] - }, - { - "name": "unit.millibars", - "symbol": "mb", - "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","mb"] - }, - { - "name": "unit.inch-of-mercury", - "symbol": "inHg", - "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","inHg","richter"] - }, - { - "name": "unit.richter-scale", - "symbol": "richter", - "tags": ["earthquake","seismic activity","richter"] - }, - { - "name": "unit.second", - "symbol": "s", - "tags": ["time","duration","interval","angle","second","arcsecond","sec"] - }, - { - "name": "unit.minute", - "symbol": "min", - "tags": ["time","duration","interval","angle","minute","arcminute","min"] - }, - { - "name": "unit.hour", - "symbol": "h", - "tags": ["time","duration","interval","h"] - }, - { - "name": "unit.day", - "symbol": "d", - "tags": ["time","duration","interval","d"] - }, - { - "name": "unit.week", - "symbol": "wk", - "tags": ["time","duration","interval","wk"] - }, - { - "name": "unit.month", - "symbol": "mo", - "tags": ["time","duration","interval","mo"] - }, - { - "name": "unit.year", - "symbol": "yr", - "tags": ["time","duration","interval","yr"] - }, - { - "name": "unit.cubic-foot-per-minute", - "symbol": "ft³/min", - "tags": ["airflow","ventilation","HVAC","gas flow rate","CFM","flow rate","fluid flow","cubic foot per minute","ft³/min"] - }, - { - "name": "unit.cubic-meters-per-hour", - "symbol": "m³/hr", - "tags": ["airflow","ventilation","HVAC","gas flow rate","cubic meters per hour","m³/hr"] - }, - { - "name": "unit.cubic-meters-per-second", - "symbol": "m³/s", - "tags": ["airflow","ventilation","HVAC","gas flow rate","cubic meters per second","m³/s"] - }, - { - "name": "unit.liter-per-second", - "symbol": "L/s", - "tags": ["airflow","ventilation","HVAC","gas flow rate","liter per second","L/s"] - }, - { - "name": "unit.liter-per-minute", - "symbol": "L/min", - "tags": ["airflow","ventilation","HVAC","gas flow rate","liter per minute","L/min"] - }, - { - "name": "unit.gallons-per-minute", - "symbol": "GPM", - "tags": ["airflow","ventilation","HVAC","gas flow rate","gallons per minute","GPM"] - }, - { - "name": "unit.cubic-foot-per-second", - "symbol": "ft³/s", - "tags": ["flow rate","fluid flow","cubic foot per second","cubic feet per second","ft³/s"] - }, - { - "name": "unit.milliliters-per-minute", - "symbol": "mL/min", - "tags": ["Flow rate","fluid dynamics","milliliters per minute","mL/min"] - }, - { - "name": "unit.bit", - "symbol": "bit", - "tags": ["data","binary digit","information","bit"] - }, - { - "name": "unit.byte", - "symbol": "B", - "tags": ["data","byte","information","storage","memory","B"] - }, - { - "name": "unit.kilobyte", - "symbol": "KB", - "tags": ["data","kilobyte","KB"] - }, - { - "name": "unit.megabyte", - "symbol": "MB", - "tags": ["data","megabyte","MB"] - }, - { - "name": "unit.gigabyte", - "symbol": "GB", - "tags": ["data","gigabyte","GB"] - }, - { - "name": "unit.terabyte", - "symbol": "TB", - "tags": ["data","terabyte","TB"] - }, - { - "name": "unit.petabyte", - "symbol": "PB", - "tags": ["data","petabyte","PB"] - }, - { - "name": "unit.exabyte", - "symbol": "EB", - "tags": ["data","exabyte","EB"] - }, - { - "name": "unit.zettabyte", - "symbol": "ZB", - "tags": ["data","zettabyte","ZB"] - }, - { - "name": "unit.yottabyte", - "symbol": "YB", - "tags": ["data","yottabyte","YB"] - }, - { - "name": "unit.bit-per-second", - "symbol": "bps", - "tags": ["data transfer rate","bps"] - }, - { - "name": "unit.kilobit-per-second", - "symbol": "kbps", - "tags": ["data transfer rate","kbps"] - }, - { - "name": "unit.megabit-per-second", - "symbol": "Mbps", - "tags": ["data transfer rate","Mbps"] - }, - { - "name": "unit.gigabit-per-second", - "symbol": "Gbps", - "tags": ["data transfer rate","Gbps"] - }, - { - "name": "unit.terabit-per-second", - "symbol": "Tbps", - "tags": ["data transfer rate","Tbps"] - }, - { - "name": "unit.byte-per-second", - "symbol": "B/s", - "tags": ["data transfer rate","B/s"] - }, - { - "name": "unit.kilobyte-per-second", - "symbol": "KB/s", - "tags": ["data transfer rate","KB/s"] - }, - { - "name": "unit.megabyte-per-second", - "symbol": "MB/s", - "tags": ["data transfer rate","MB/s"] - }, - { - "name": "unit.gigabyte-per-second", - "symbol": "GB/s", - "tags": ["data transfer rate","GB/s"] - }, - { - "name": "unit.degree", - "symbol": "deg", - "tags": ["angle","degree","degrees","deg"] - }, - { - "name": "unit.radian", - "symbol": "rad", - "tags": ["angle","radian","radians","rad"] - }, - { - "name": "unit.gradian", - "symbol": "grad", - "tags": ["angle","gradian","grades","grad"] - }, - { - "name": "unit.mil", - "symbol": "mil", - "tags": ["angle","military angle","angular mil","mil"] - }, - { - "name": "unit.revolution", - "symbol": "rev", - "tags": ["angle","revolution","full circle","complete turn","rev"] - }, - { - "name": "unit.siemens", - "symbol": "S", - "tags": ["electrical conductance","conductance","siemens","S"] - }, - { - "name": "unit.millisiemens", - "symbol": "mS", - "tags": ["electrical conductance","conductance","millisiemens","mS"] - }, - { - "name": "unit.microsiemens", - "symbol": "μS", - "tags": ["electrical conductance","conductance","microsiemens","μS"] - }, - { - "name": "unit.kilosiemens", - "symbol": "kS", - "tags": ["electrical conductance","conductance","kilosiemens","kS"] - }, - { - "name": "unit.megasiemens", - "symbol": "MS", - "tags": ["electrical conductance","conductance","megasiemens","MS"] - }, - { - "name": "unit.gigasiemens", - "symbol": "GS", - "tags": ["electrical conductance","conductance","gigasiemens","GS"] - }, - { - "name": "unit.farad", - "symbol": "F", - "tags": ["electric capacitance","capacitance","farad","F"] - }, - { - "name": "unit.millifarad", - "symbol": "mF", - "tags": ["electric capacitance","capacitance","millifarad","mF"] - }, - { - "name": "unit.microfarad", - "symbol": "μF", - "tags": ["electric capacitance","capacitance","microfarad","μF"] - }, - { - "name": "unit.nanofarad", - "symbol": "nF", - "tags": ["electric capacitance","capacitance","nanofarad","nF"] - }, - { - "name": "unit.picofarad", - "symbol": "pF", - "tags": ["electric capacitance","capacitance","picofarad","pF"] - }, - { - "name": "unit.kilofarad", - "symbol": "kF", - "tags": ["electric capacitance","capacitance","kilofarad","kF"] - }, - { - "name": "unit.megafarad", - "symbol": "MF", - "tags": ["electric capacitance","capacitance","megafarad","MF"] - }, - { - "name": "unit.gigafarad", - "symbol": "GF", - "tags": ["electric capacitance","capacitance","gigafarad","GF"] - }, - { - "name": "unit.terfarad", - "symbol": "TF", - "tags": ["electric capacitance","capacitance","terafarad","TF"] - }, - { - "name": "unit.farad-per-meter", - "symbol": "F/m", - "tags": ["electric permittivity","farad per meter","F/m"] - }, - { - "name": "unit.tesla", - "symbol": "T", - "tags": ["magnetic field","magnetic field strength","tesla","T","magnetic flux density"] - }, - { - "name": "unit.gauss", - "symbol": "G", - "tags": ["magnetic field","magnetic field strength","gauss","G","magnetic flux density"] - }, - { - "name": "unit.kilogauss", - "symbol": "kG", - "tags": ["magnetic field","magnetic field strength","kilogauss","kG","magnetic flux density"] - }, - { - "name": "unit.millitesla", - "symbol": "mT", - "tags": ["magnetic field","magnetic field strength","millitesla","mT"] - }, - { - "name": "unit.microtesla", - "symbol": "μT", - "tags": ["magnetic field","magnetic field strength","microtesla","μT"] - }, - { - "name": "unit.nanotesla", - "symbol": "nT", - "tags": ["magnetic field","magnetic field strength","nanotesla","nT"] - }, - { - "name": "unit.kilotesla", - "symbol": "kT", - "tags": ["magnetic field","magnetic field strength","kilotesla","kT"] - }, - { - "name": "unit.megatesla", - "symbol": "MT", - "tags": ["magnetic field","magnetic field strength","megatesla","MT"] - }, - { - "name": "unit.millitesla-square-meters", - "symbol": "millitesla square meters", - "tags": ["magnetic field","millitesla square meters"] - }, - { - "name": "unit.gamma", - "symbol": "γ", - "tags": ["magnetic flux density","gamma","γ"] - }, - { - "name": "unit.lambda", - "symbol": "λ", - "tags": ["wavelength","lambda","λ"] - }, - { - "name": "unit.square-meter-per-second", - "symbol": "m²/s", - "tags": ["kinematic viscosity","m²/s"] - }, - { - "name": "unit.square-centimeter-per-second", - "symbol": "cm²/s", - "tags": ["kinematic viscosity","cm²/s"] - }, - { - "name": "unit.stoke", - "symbol": "St", - "tags": ["kinematic viscosity","stokes","St"] - }, - { - "name": "unit.centistokes", - "symbol": "cSt", - "tags": ["kinematic viscosity","centistokes","cSt"] - }, - { - "name": "unit.square-foot-per-second", - "symbol": "ft²/s", - "tags": ["kinematic viscosity","ft²/s"] - }, - { - "name": "unit.square-inch-per-second", - "symbol": "in²/s", - "tags": ["kinematic viscosity","in²/s"] - }, - { - "name": "unit.pascal-second", - "symbol": "Pa·s", - "tags": ["dynamic viscosity","viscosity","fluid mechanics","pascal-second","Pa·s"] - }, - { - "name": "unit.centipoise", - "symbol": "cP", - "tags": ["viscosity","dynamic viscosity","fluid viscosity","centipoise","cP"] - }, - { - "name": "unit.poise", - "symbol": "P", - "tags": ["viscosity","dynamic viscosity","fluid viscosity","poise","P"] - }, - { - "name": "unit.reynolds", - "symbol": "Re", - "tags": ["fluid flow regime","fluid mechanics","reynolds","Re"] - }, - { - "name": "unit.pound-per-foot-hour", - "symbol": "lb/(ft·h)", - "tags": ["pound per foot-hour","lb/(ft·h)"] - }, - { - "name": "unit.newton-second-per-square-meter", - "symbol": "N·s/m²", - "tags": ["newton second per square meter","N·s/m²"] - }, - { - "name": "unit.dyne-second-per-square-centimeter", - "symbol": "dyn·s/cm²", - "tags": ["dyne second per square centimeter","dyn·s/cm²"] - }, - { - "name": "unit.kilogram-per-meter-second", - "symbol": "kg/(m·s)", - "tags": ["kilogram per meter-second","kg/(m·s)"] - }, - { - "name": "unit.tesla-square-meters", - "symbol": "T/m²", - "tags": ["magnetic flux density","tesla square meters","T/m²"] - }, - { - "name": "unit.maxwell", - "symbol": "Mx", - "tags": ["magnetic flux","magnetic field","maxwell","Mx"] - }, - { - "name": "unit.tesla-per-meter", - "symbol": "T/m", - "tags": ["magnetic field","tesla per meter","T/m"] - }, - { - "name": "unit.gauss-per-centimeter", - "symbol": "G/cm", - "tags": ["magnetic field","gauss per centimeter","G/cm"] - }, - { - "name": "unit.weber", - "symbol": "Wb", - "tags": ["magnetic flux","weber","Wb"] - }, - { - "name": "unit.microweber", - "symbol": "µWb", - "tags": ["magnetic flux","microweber","µWb"] - }, - { - "name": "unit.milliweber", - "symbol": "mWb", - "tags": ["magnetic flux","milliweber","mWb"] - }, - { - "name": "unit.gauss-square-centimeter", - "symbol": "G·cm²", - "tags": ["magnetic flux","gauss-square centimeter","G·cm²"] - }, - { - "name": "unit.kilogauss-square-centimeter", - "symbol": "kG·cm²", - "tags": ["magnetic flux","kilogauss-square centimeter","kG·cm²"] - }, - { - "name": "unit.henry", - "symbol": "H", - "tags": ["inductance","magnetic induction","H"] - }, - { - "name": "unit.millihenry", - "symbol": "mH", - "tags": ["inductance","millihenry","mH"] - }, - { - "name": "unit.microhenry", - "symbol": "µH", - "tags": ["inductance","microhenry","µH"] - }, - { - "name": "unit.nanohenry", - "symbol": "nH", - "tags": ["inductance","nanohenry","nH"] - }, - { - "name": "unit.henry-per-meter", - "symbol": "H/m", - "tags": ["magnetic permeability","henry per meter","H/m"] - }, - { - "name": "unit.tesla-meter-per-ampere", - "symbol": "T·m/A", - "tags": ["magnetic field","Tesla Meter per Ampere","T·m/A","magnetic flux"] - }, - { - "name": "unit.gauss-per-oersted", - "symbol": "G/Oe", - "tags": ["magnetic field","Gauss per Oersted","G/Oe"] - }, - { - "name": "unit.kilogram-per-mole", - "symbol": "kg/mol", - "tags": ["molar mass","kilogram per mole","kg/mol"] - }, - { - "name": "unit.gram-per-mole", - "symbol": "g/mol", - "tags": ["molar mass","gram per mole","g/mol"] - }, - { - "name": "unit.milligram-per-mole", - "symbol": "mg/mol", - "tags": ["molar mass","milligram per mole","mg/mol"] - }, - { - "name": "unit.joule-per-mole", - "symbol": "J/mol", - "tags": ["molar energy","joule per mole","J/mol"] - }, - { - "name": "unit.joule-per-mole-kelvin", - "symbol": "J/(mol·K)", - "tags": ["molar heat capacity","joule per mole-kelvin","J/(mol·K)"] - }, - { - "name": "unit.millivolts-per-meter", - "symbol": "mV/m", - "tags": ["electric field strength","millivolts per meter","mV/m"] - }, - { - "name": "unit.volts-per-meter", - "symbol": "V/m", - "tags": ["electric field strength","volts per meter","V/m"] - }, - { - "name": "unit.kilovolts-per-meter", - "symbol": "kV/m", - "tags": ["electric field strength","kilovolts per meter","kV/m"] - }, - { - "name": "unit.radian-per-second", - "symbol": "rad/s", - "tags": ["angular velocity","rotation speed","rad/s"] - }, - { - "name": "unit.radian-per-second-squared", - "symbol": "rad/s²", - "tags": ["angular acceleration","rotation rate of change","rad/s²"] - }, - { - "name": "unit.revolutions-per-minute-per-second", - "symbol": "rpm/s", - "tags": ["angular acceleration","rotation rate of change","rpm/s"] - }, - { - "name": "unit.revolutions-per-minute-per-second-squared", - "symbol": "rpm/s²", - "tags": ["angular acceleration","rotation rate of change","rpm/s²"] - }, - { - "name": "unit.deg-per-second", - "symbol": "deg/s", - "tags": ["angular velocity","degrees per second","deg/s"] - }, - { - "name": "unit.degrees-brix", - "symbol": "°Bx", - "tags": ["sugar content","fruit ripeness","Bx"] - }, - { - "name": "unit.katal", - "symbol": "kat", - "tags": ["catalytic activity","enzyme activity","kat"] - }, - { - "name": "unit.katal-per-cubic-metre", - "symbol": "kat/m³", - "tags": ["catalytic activity concentration","enzyme concentration","kat/m³"] - } - ] -} + "name": "unit.centimeter", + "symbol": "cm", + "tags": ["level","height","distance","length","width","gap","depth","centimeter","centimeters","rainfall","precipitation", + "displacement","position","movement","transition","cm"] +}, +{ + "name": "unit.angstrom", + "symbol": "Å", + "tags": ["level","height","distance","length","width","gap","depth","atomic scale","atomic distance","nanoscale", + "angstrom","angstroms","Å"] +}, +{ + "name": "unit.nanometer", + "symbol": "nm", + "tags": ["level","height","distance","length","width","gap","depth","nanoscale","atomic scale","molecular scale", + "nanometer","nanometers","nm"] +}, +{ + "name": "unit.micrometer", + "symbol": "µm", + "tags": ["level","height","distance","length","width","gap","depth","microns","micrometer","micrometers","µm"] +}, +{ + "name": "unit.meter", + "symbol": "m", + "tags": ["level","height","distance","length","width","gap","depth","meter","meters","m"] +}, +{ + "name": "unit.kilometer", + "symbol": "km", + "tags": ["distance","height","length","width","gap","depth","kilometer","kilometers","km"] +}, +{ + "name": "unit.inch", + "symbol": "in", + "tags": ["level","height","distance","length","width","gap","depth","inch","inches","in"] +}, +{ + "name": "unit.foot", + "symbol": "ft", + "tags": ["level","height","distance","length","width","gap","depth","foot","feet","ft"] +}, +{ + "name": "unit.yard", + "symbol": "yd", + "tags": ["level","height","distance","length","width","gap","depth","yard","yards","yd"] +}, +{ + "name": "unit.mile", + "symbol": "mi", + "tags": ["level","height","distance","length","width","gap","depth","mile","miles","mi"] +}, +{ + "name": "unit.nautical-mile", + "symbol": "nm", + "tags": ["level","height","distance","length","width","gap","depth","nautical mile","nm"] +}, +{ + "name": "unit.astronomical-unit", + "symbol": "AU", + "tags": ["distance","celestial bodies","solar system","AU"] +}, +{ + "name": "unit.reciprocal-metre", + "symbol": "m⁻¹", + "tags": ["wavenumber","wave density","wave frequency","m⁻¹"] +}, +{ + "name": "unit.meter-per-meter", + "symbol": "m/m", + "tags": ["ratio of length to length","meter per meter","m/m"] +}, +{ + "name": "unit.steradian", + "symbol": "sr", + "tags": ["solid angle","spatial extent","steradian","sr"] +}, +{ + "name": "unit.thou", + "symbol": "thou", + "tags": ["length","measurement","thou"] +}, +{ + "name": "unit.barleycorn", + "symbol": "barleycorn", + "tags": ["length","shoe size","barleycorn"] +}, +{ + "name": "unit.hand", + "symbol": "hand", + "tags": ["length","horse measurement","hand"] +}, +{ + "name": "unit.chain", + "symbol": "ch", + "tags": ["length","land surveying","ch"] +}, +{ + "name": "unit.furlong", + "symbol": "fur", + "tags": ["length","land surveying","fur"] +}, +{ + "name": "unit.league", + "symbol": "league", + "tags": ["length","historical measurement","league"] +}, +{ + "name": "unit.fathom", + "symbol": "fathom", + "tags": ["depth","nautical measurement","fathom"] +}, +{ + "name": "unit.cable", + "symbol": "cable", + "tags": ["distance","nautical measurement","cable"] +}, +{ + "name": "unit.link", + "symbol": "link", + "tags": ["length","land surveying","link"] +}, +{ + "name": "unit.rod", + "symbol": "rod", + "tags": ["length","land surveying","rod"] +}, +{ + "name": "unit.nanogram", + "symbol": "ng", + "tags": ["mass","weight","heaviness","load","nanogram","nanograms","ng"] +}, +{ + "name": "unit.microgram", + "symbol": "μg", + "tags": ["mass","weight","heaviness","load","μg","microgram"] +}, +{ + "name": "unit.milligram", + "symbol": "mg", + "tags": ["mass","weight","heaviness","load","milligram","miligrams","mg"] +}, +{ + "name": "unit.gram", + "symbol": "g", + "tags": ["mass","weight","heaviness","load","gram","grams","g"] +}, +{ + "name": "unit.kilogram", + "symbol": "kg", + "tags": ["mass","weight","heaviness","load","kilogram","kilograms","kg"] +}, +{ + "name": "unit.tonne", + "symbol": "t", + "tags": ["mass","weight","heaviness","load","tonne","tons","t"] +}, +{ + "name": "unit.ounce", + "symbol": "oz", + "tags": ["mass","weight","heaviness","load","ounce","ounces","oz"] +}, +{ + "name": "unit.pound", + "symbol": "lb", + "tags": ["mass","weight","heaviness","load","pound","pounds","lb"] +}, +{ + "name": "unit.stone", + "symbol": "st", + "tags": ["mass","weight","heaviness","load","stone","stones","st"] +}, +{ + "name": "unit.hundredweight-count", + "symbol": "cwt", + "tags": ["mass","weight","heaviness","load","hundredweight count","cwt"] +}, +{ + "name": "unit.short-tons", + "symbol": "short tons", + "tags": ["mass","weight","heaviness","load","short ton","short tons"] +}, +{ + "name": "unit.dalton", + "symbol": "Da", + "tags": ["atomic mass unit","AMU","unified atomic mass unit","dalton","Da"] +}, +{ + "name": "unit.grain", + "symbol": "gr", + "tags": ["mass","measurement","grain","gr"] +}, +{ + "name": "unit.drachm", + "symbol": "dr", + "tags": ["mass","measurement","drachm","dr"] +}, +{ + "name": "unit.quarter", + "symbol": "qr", + "tags": ["mass","measurement","quarter","qr"] +}, +{ + "name": "unit.slug", + "symbol": "slug", + "tags": ["mass","measurement","slug"] +}, +{ + "name": "unit.carat", + "symbol": "ct", + "tags": ["gemstone","pearl","jewelry","carat","ct"] +}, +{ + "name": "unit.cubic-millimeter", + "symbol": "mm³", + "tags": ["volume","capacity","extent","cubic millimeter","mm³"] +}, +{ + "name": "unit.cubic-centimeter", + "symbol": "cm³", + "tags": ["volume","capacity","extent","cubic centimeter","cubic centimeters","cm³"] +}, +{ + "name": "unit.cubic-meter", + "symbol": "m³", + "tags": ["volume","capacity","extent","cubic meter","cubic meters","m³"] +}, +{ + "name": "unit.cubic-kilometer", + "symbol": "km³", + "tags": ["volume","capacity","extent","cubic kilometer","cubic kilometers","km³"] +}, +{ + "name": "unit.microliter", + "symbol": "µL", + "tags": ["volume","liquid measurement","microliter","µL"] +}, +{ + "name": "unit.milliliter", + "symbol": "mL", + "tags": ["volume","capacity","extent","milliliter","milliliters","mL"] +}, +{ + "name": "unit.liter", + "symbol": "l", + "tags": ["volume","capacity","extent","liter","liters","l"] +}, +{ + "name": "unit.hectoliter", + "symbol": "hl", + "tags": ["volume","capacity","extent","hectoliter","hectoliters","hl"] +}, +{ + "name": "unit.cubic-inch", + "symbol": "in³", + "tags": ["volume","capacity","extent","cubic inch","cubic inches","in³"] +}, +{ + "name": "unit.cubic-foot", + "symbol": "ft³", + "tags": ["volume","capacity","extent","cubic foot","cubic feet","ft³"] +}, +{ + "name": "unit.cubic-yard", + "symbol": "yd³", + "tags": ["volume","capacity","extent","cubic yard","cubic yards","yd³"] +}, +{ + "name": "unit.fluid-ounce", + "symbol": "fl-oz", + "tags": ["volume","capacity","extent","fluid ounce","fluid ounces","fl-oz"] +}, +{ + "name": "unit.pint", + "symbol": "pt", + "tags": ["volume","capacity","extent","pint","pints","pt"] +}, +{ + "name": "unit.quart", + "symbol": "qt", + "tags": ["volume","capacity","extent","quart","quarts","qt"] +}, +{ + "name": "unit.gallon", + "symbol": "gal", + "tags": ["volume","capacity","extent","gallon","gallons","gal"] +}, +{ + "name": "unit.oil-barrels", + "symbol": "bbl", + "tags": ["volume","capacity","extent","oil barrel","oil barrels","bbl"] +}, +{ + "name": "unit.cubic-meter-per-kilogram", + "symbol": "m³/kg", + "tags": ["specific volume","volume per unit mass","cubic meter per kilogram","m³/kg"] +}, +{ + "name": "unit.gill", + "symbol": "gi", + "tags": ["volume","liquid measurement","gi"] +}, +{ + "name": "unit.hogshead", + "symbol": "hhd", + "tags": ["volume","liquid measurement","hhd"] +}, +{ + "name": "unit.teaspoon", + "symbol": "tsp", + "tags": ["volume","cooking measurement","tsp"] +}, +{ + "name": "unit.tablespoon", + "symbol": "tbsp", + "tags": ["volume","cooking measurement","tbsp"] +}, +{ + "name": "unit.cup", + "symbol": "cup", + "tags": ["volume","cooking measurement","cup"] +}, +{ + "name": "unit.celsius", + "symbol": "°C", + "tags": ["temperature","heat","cold","warmth","degrees","celsius","shipment condition","°C"] +}, +{ + "name": "unit.kelvin", + "symbol": "K", + "tags": ["temperature","heat","cold","warmth","degrees","kelvin","K","color quality","white balance","color temperature"] +}, +{ + "name": "unit.rankine", + "symbol": "°R", + "tags": ["temperature","heat","cold","warmth","Rankine","°R"] +}, +{ + "name": "unit.fahrenheit", + "symbol": "°F", + "tags": ["temperature","heat","cold","warmth","degrees","fahrenheit","°F"] +}, +{ + "name": "unit.meter-per-second", + "symbol": "m/s", + "tags": ["speed","velocity","pace","meter per second","m/s","peak","peak to peak","root mean square (RMS)", + "vibration","wind speed","weather"] +}, +{ + "name": "unit.kilometer-per-hour", + "symbol": "km/h", + "tags": ["speed","velocity","pace","kilometer per hour","km/h"] +}, +{ + "name": "unit.foot-per-second", + "symbol": "ft/s", + "tags": ["speed","velocity","pace","foot per second","ft/s"] +}, +{ + "name": "unit.mile-per-hour", + "symbol": "mph", + "tags": ["speed","velocity","pace","mile per hour","mph"] +}, +{ + "name": "unit.knot", + "symbol": "kt", + "tags": ["speed","velocity","pace","knot","knots","kt"] +}, +{ + "name": "unit.millimeters-per-minute", + "symbol": "mm/min", + "tags": ["feed rate","cutting feed rate","millimeters per minute","mm/min"] +}, +{ + "name": "unit.kilometer-per-hour-squared", + "symbol": "km/h²", + "tags": ["acceleration","rate of change of velocity","kilometer per hour squared","km/h²"] +}, +{ + "name": "unit.foot-per-second-squared", + "symbol": "ft/s²", + "tags": ["acceleration","rate of change of velocity","foot per second squared","ft/s²"] +}, +{ + "name": "unit.pascal", + "symbol": "Pa", + "tags": ["pressure","force","compression","tension","pascal","pascals","Pa","atmospheric pressure","air pressure", + "weather","altitude","flight"] +}, +{ + "name": "unit.kilopascal", + "symbol": "kPa", + "tags": ["pressure","force","compression","tension","kilopascal","kilopascals","kPa"] +}, +{ + "name": "unit.megapascal", + "symbol": "MPa", + "tags": ["pressure","force","compression","tension","megapascal","megapascals","MPa"] +}, +{ + "name": "unit.gigapascal", + "symbol": "GPa", + "tags": ["pressure","force","compression","tension","gigapascal","gigapascals","GPa"] +}, +{ + "name": "unit.millibar", + "symbol": "mbar", + "tags": ["pressure","force","compression","tension","millibar","millibars","mbar"] +}, +{ + "name": "unit.bar", + "symbol": "bar", + "tags": ["pressure","force","compression","tension","bar","bars"] +}, +{ + "name": "unit.kilobar", + "symbol": "kbar", + "tags": ["pressure","force","compression","tension","kilobar","kilobars","kbar"] +}, +{ + "name": "unit.newton", + "symbol": "N", + "tags": ["force","pressure","newton","newtons","N","push","pull","weight","gravity","N"] +}, +{ + "name": "unit.newton-meter", + "symbol": "Nm", + "tags": ["torque","rotational force","newton meter","Nm"] +}, +{ + "name": "unit.foot-pounds", + "symbol": "ft·lbf", + "tags": ["torque","rotational force","foot-pound","foot-pounds","ft·lbf"] +}, +{ + "name": "unit.inch-pounds", + "symbol": "in·lbf", + "tags": ["torque","rotational force","inch-pounds","inch-pound","in·lbf"] +}, +{ + "name": "unit.newton-per-meter", + "symbol": "N/m", + "tags": ["linear density","force per unit length","newton per meter","N/m"] +}, +{ + "name": "unit.atmospheres", + "symbol": "atm", + "tags": ["pressure","force","compression","tension","atmosphere","atmospheres","atmospheric pressure","atm"] +}, +{ + "name": "unit.pounds-per-square-inch", + "symbol": "psi", + "tags": ["pressure","force","compression","tension","pounds per square inch","psi"] +}, +{ + "name": "unit.torr", + "symbol": "Torr", + "tags": ["pressure","force","compression","tension","vacuum pressure","torr"] +}, +{ + "name": "unit.inches-of-mercury", + "symbol": "inHg", + "tags": ["pressure","force","compression","tension","vacuum pressure","inHg","atmospheric pressure","barometric pressure"] +}, +{ + "name": "unit.pascal-per-square-meter", + "symbol": "Pa/m²", + "tags": ["pressure","stress","mechanical strength","pascal per square meter","Pa/m²"] +}, +{ + "name": "unit.pound-per-square-inch", + "symbol": "psi/in²", + "tags": ["pressure","stress","mechanical strength","pound per square inch","psi/in²"] +}, +{ + "name": "unit.newton-per-square-meter", + "symbol": "N/m²", + "tags": ["pressure","stress","mechanical strength","newton per square meter","N/m²"] +}, +{ + "name": "unit.kilogram-force-per-square-meter", + "symbol": "kgf/m²", + "tags": ["pressure","stress","mechanical strength","kilogram-force per square meter","kgf/m²"] +}, +{ + "name": "unit.pascal-per-square-centimeter", + "symbol": "Pa/cm²", + "tags": ["pressure","stress","mechanical strength","pascal per square centimeter","Pa/cm²"] +}, +{ + "name": "unit.ton-force-per-square-inch", + "symbol": "tonf/in²", + "tags": ["pressure","stress","mechanical strength","ton-force per square inch","tonf/in²"] +}, +{ + "name": "unit.kilonewton-per-square-meter", + "symbol": "kN/m²", + "tags": ["stress","pressure","mechanical strength","kilonewton per square meter","kN/m²"] +}, +{ + "name": "unit.newton-per-square-millimeter", + "symbol": "N/mm²", + "tags": ["stress","pressure","mechanical strength","newton per square millimeter","N/mm²"] +}, +{ + "name": "unit.microjoule", + "symbol": "μJ", + "tags": ["energy","microjoule","microjoules","μJ"] +}, +{ + "name": "unit.millijoule", + "symbol": "mJ", + "tags": ["energy","millijoule","millijoules","mJ"] +}, +{ + "name": "unit.joule", + "symbol": "J", + "tags": ["joule","joules","energy","work done","heat","electricity","mechanical work"] +}, +{ + "name": "unit.kilojoule", + "symbol": "kJ", + "tags": ["energy","kilojoule","kilojoules","kJ"] +}, +{ + "name": "unit.megajoule", + "symbol": "MJ", + "tags": ["energy","megajoule","megajoules","MJ"] +}, +{ + "name": "unit.gigajoule", + "symbol": "GJ", + "tags": ["energy","gigajoule","gigajoules","GJ"] +}, +{ + "name": "unit.watt-hour", + "symbol": "Wh", + "tags": ["energy","watt-hour","watt-hours","energy usage","power consumption","energy consumption","electricity usage"] +}, +{ + "name": "unit.kilowatt-hour", + "symbol": "kWh", + "tags": ["energy","kilowatt-hour","kilowatt-hours","energy usage","power consumption","energy consumption","electricity usage"] +}, +{ + "name": "unit.electron-volts", + "symbol": "eV", + "tags": ["energy","subatomic particles","radiation"] +}, +{ + "name": "unit.joules-per-coulomb", + "symbol": "J/C", + "tags": ["electrical potential energy","voltage","joules per coulomb","J/C"] +}, +{ + "name": "unit.british-thermal-unit", + "symbol": "BTU", + "tags": ["energy","heat","work done","british thermal unit","british thermal units","BTU"] +}, +{ + "name": "unit.foot-pound", + "symbol": "ft·lb", + "tags": ["energy","foot-pound","foot-pounds","ft·lb","ft⋅lbf"] +}, +{ + "name": "unit.calorie", + "symbol": "Cal", + "tags": ["energy","food energy","Calorie","Calories","Cal"] +}, +{ + "name": "unit.small-calorie", + "symbol": "cal", + "tags": ["energy","small calorie","calories","cal"] +}, +{ + "name": "unit.kilocalorie", + "symbol": "kcal", + "tags": ["energy","small calorie","kilocalories","kcal"] +}, +{ + "name": "unit.joule-per-kelvin", + "symbol": "J/K", + "tags": ["specific heat capacity","heat capacity per unit temperature","joule per kelvin","J/K"] +}, +{ + "name": "unit.joule-per-kilogram-kelvin", + "symbol": "J/(kg·K)", + "tags": ["specific heat capacity","heat capacity per unit mass and temperature","joule per kilogram-kelvin","J/(kg·K)"] +}, +{ + "name": "unit.joule-per-kilogram", + "symbol": "J/kg", + "tags": ["specific energy","specific energy capacity","joule per kilogram","J/kg"] +}, +{ + "name": "unit.watt-per-meter-kelvin", + "symbol": "W/(m·K)", + "tags": ["thermal conductivity","watt per meter-kelvin","W/(m·K)"] +}, +{ + "name": "unit.joule-per-cubic-meter", + "symbol": "J/m³", + "tags": ["energy density","joule per cubic meter","J/m³"] +}, +{ + "name": "unit.therm", + "symbol": "thm", + "tags": ["energy","natural gas consumption","BTU","therm","thm"] +}, +{ + "name": "unit.electric-dipole-moment", + "symbol": "C·m", + "tags": ["electric dipole","dipole moment","coulomb meter","C·m"] +}, +{ + "name": "unit.magnetic-dipole-moment", + "symbol": "A·m²", + "tags": ["magnetic dipole","dipole moment","ampere square meter","A·m²"] +}, +{ + "name": "unit.debye", + "symbol": "D", + "tags": ["polarization","electric dipole moment","debye","D"] +}, +{ + "name": "unit.coulomb-per-square-meter-per-volt", + "symbol": "C·m²/V", + "tags": ["polarization","electric field","coulomb per square meter per volt","C·m²/V"] +}, +{ + "name": "unit.milliwatt", + "symbol": "mW", + "tags": ["power","horsepower","performance","milliwatt","milliwatts","electricity","mW"] +}, +{ + "name": "unit.microwatt", + "symbol": "μW", + "tags": ["power","horsepower","performance","microwatt","microwatts","electricity","μW"] +}, +{ + "name": "unit.watt", + "symbol": "W", + "tags": ["power","horsepower","performance","watt","watts","electricity","W"] +}, +{ + "name": "unit.kilowatt", + "symbol": "kW", + "tags": ["power","horsepower","performance","kilowatt","kilowatts","electricity","kW"] +}, +{ + "name": "unit.megawatt", + "symbol": "MW", + "tags": ["power","horsepower","performance","megawatt","megawatts","electricity","MW"] +}, +{ + "name": "unit.gigawatt", + "symbol": "GW", + "tags": ["power","horsepower","performance","gigawatt","gigawatts","electricity","GW"] +}, +{ + "name": "unit.metric-horsepower", + "symbol": "PS", + "tags": ["power","performance","metric horsepower","PS"] +}, +{ + "name": "unit.milliwatt-per-square-centimeter", + "symbol": "mW/cm²", + "tags": ["power density","radiation intensity","sunlight intensity","signal power","intensity", + "milliwatts per square centimeter","UV Intensity","mW/cm²"] +}, +{ + "name": "unit.watt-per-square-centimeter", + "symbol": "W/cm²", + "tags": ["power density","intensity of power","watts per square centimeter","W/cm²"] +}, +{ + "name": "unit.kilowatt-per-square-centimeter", + "symbol": "kW/cm²", + "tags": ["power density","intensity of power","kilowatts per square centimeter","kW/cm²"] +}, +{ + "name": "unit.milliwatt-per-square-meter", + "symbol": "mW/m²", + "tags": ["power density","intensity of power","milliwatts per square meter","mW/m²"] +}, +{ + "name": "unit.watt-per-square-meter", + "symbol": "W/m²", + "tags": ["power density","intensity of power","watts per square meter","W/m²"] +}, +{ + "name": "unit.kilowatt-per-square-meter", + "symbol": "kW/m²", + "tags": ["power density","intensity of power","kilowatts per square meter","kW/m²"] +}, +{ + "name": "unit.watt-per-square-inch", + "symbol": "W/in²", + "tags": ["power density","intensity of power","watts per square inch","W/in²"] +}, +{ + "name": "unit.kilowatt-per-square-inch", + "symbol": "kW/in²", + "tags": ["power density","intensity of power","kilowatts per square inch","kW/in²"] +}, +{ + "name": "unit.horsepower", + "symbol": "hp", + "tags": ["power","horsepower","performance","electricity","horsepowers","hp"] +}, +{ + "name": "unit.btu-per-hour", + "symbol": "BTU/h", + "tags": ["power","heat transfer","thermal energy","HVAC","BTU/h"] +}, +{ + "name": "unit.coulomb", + "symbol": "C", + "tags": ["charge","electricity","electrostatics","Coulomb","C"] +}, +{ + "name": "unit.millicoulomb", + "symbol": "mC", + "tags": ["charge","electricity","electrostatics","millicoulombs","mC"] +}, +{ + "name": "unit.microcoulomb", + "symbol": "µC", + "tags": ["charge","electricity","electrostatics","microcoulomb","µC"] +}, +{ + "name": "unit.picocoulomb", + "symbol": "pC", + "tags": ["charge","electricity","electrostatics","picocoulomb","pC"] +}, +{ + "name": "unit.coulomb-per-meter", + "symbol": "C/m", + "tags": ["electric displacement field per length","coulomb per meter","C/m"] +}, +{ + "name": "unit.coulomb-per-cubic-meter", + "symbol": "C/m³", + "tags": ["electric charge density","coulomb per cubic meter","C/m³"] +}, +{ + "name": "unit.coulomb-per-square-meter", + "symbol": "C/m²", + "tags": ["electric surface charge density","coulomb per square meter","C/m²"] +}, +{ + "name": "unit.square-millimeter", + "symbol": "mm²", + "tags": ["area","lot","zone","space","region","square millimeter","square millimeters","mm²","sq-mm"] +}, +{ + "name": "unit.square-centimeter", + "symbol": "cm²", + "tags": ["area","lot","zone","space","region","square centimeter","square centimeters","cm²","sq-cm"] +}, +{ + "name": "unit.square-meter", + "symbol": "m²", + "tags": ["area","lot","zone","space","region","square meter","square meters","m²","sq-m"] +}, +{ + "name": "unit.hectare", + "symbol": "ha", + "tags": ["area","lot","zone","space","region","hectare","hectares","ha"] +}, +{ + "name": "unit.square-kilometer", + "symbol": "km²", + "tags": ["area","lot","zone","space","region","square kilometer","square kilometers","km²","sq-km"] +}, +{ + "name": "unit.square-inch", + "symbol": "in²", + "tags": ["area","lot","zone","space","region","square inch","square inches","in²","sq-in"] +}, +{ + "name": "unit.square-foot", + "symbol": "ft²", + "tags": ["area","lot","zone","space","region","square foot","square feet","ft²","sq-ft"] +}, +{ + "name": "unit.square-yard", + "symbol": "yd²", + "tags": ["area","lot","zone","space","region","square yard","square yards","yd²","sq-yd"] +}, +{ + "name": "unit.acre", + "symbol": "a", + "tags": ["area","lot","zone","space","region","acre","acres","a"] +}, +{ + "name": "unit.square-mile", + "symbol": "ml²", + "tags": ["area","lot","zone","space","region","square mile","square miles","ml²","sq-mi"] +}, +{ + "name": "unit.are", + "symbol": "are", + "tags": ["area","land measurement","are"] +}, +{ + "name": "unit.barn", + "symbol": "barn", + "tags": ["cross-sectional area","particle physics","nuclear physics","barn"] +}, +{ + "name": "unit.circular-inch", + "symbol": "circin", + "tags": ["area","circular measurement","circular inch","circin"] +}, +{ + "name": "unit.milliampere-hour", + "symbol": "mAh", + "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity", + "electrical flow","milliampere-hour","milliampere-hours","mAh"] +}, +{ + "name": "unit.ampere-hours", + "symbol": "Ah", + "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity", + "electrical flow","ampere","ampere-hours","Ah"] +}, +{ + "name": "unit.kiloampere-hours", + "symbol": "kAh", + "tags": ["electric current","current flow","electric charge","current capacity","flow of electricity","electrical flow", + "kiloampere-hours","kiloampere-hour","kAh"] +}, +{ + "name": "unit.nanoampere", + "symbol": "nA", + "tags": ["current","amperes","nanoampere","nA"] +}, +{ + "name": "unit.picoampere", + "symbol": "pA", + "tags": ["current","amperes","picoampere","pA"] +}, +{ + "name": "unit.microampere", + "symbol": "μA", + "tags": ["electric current","microampere","microamperes","μA"] +}, +{ + "name": "unit.milliampere", + "symbol": "mA", + "tags": ["electric current","milliampere","milliamperes","mA"] +}, +{ + "name": "unit.ampere", + "symbol": "A", + "tags": ["electric current","current flow","flow of electricity","electrical flow","ampere","amperes","amperage","A"] +}, +{ + "name": "unit.kiloamperes", + "symbol": "kA", + "tags": ["electric current","current flow","kiloamperes","kA"] +}, +{ + "name": "unit.microampere-per-square-centimeter", + "symbol": "µA/cm²", + "tags": ["Current density","microampere per square centimeter","µA/cm²"] +}, +{ + "name": "unit.ampere-per-square-meter", + "symbol": "A/m²", + "tags": ["current density","current per unit area","ampere per square meter","A/m²"] +}, +{ + "name": "unit.ampere-per-meter", + "symbol": "A/m", + "tags": ["magnetic field strength","magnetic field intensity","ampere per meter","A/m"] +}, +{ + "name": "unit.oersted", + "symbol": "Oe", + "tags": ["magnetic field","oersted","Oe"] +}, +{ + "name": "unit.bohr-magneton", + "symbol": "μB", + "tags": ["atomic physics","magnetic moment","bohr magneton","μB"] +}, +{ + "name": "unit.ampere-meter-squared", + "symbol": "A·m²", + "tags": ["magnetic moment","dipole moment","ampere-meter squared","A·m²"] +}, +{ + "name": "unit.ampere-meter", + "symbol": "A·m", + "tags": ["magnetic field","current loop","ampere-meter","A·m"] +}, +{ + "name": "unit.nanovolt", + "symbol": "nV", + "tags": ["voltage","volts","nanovolt","nV"] +}, +{ + "name": "unit.picovolt", + "symbol": "pV", + "tags": ["voltage","volts","picovolt","pV"] +}, +{ + "name": "unit.millivolts", + "symbol": "mV", + "tags": ["electric potential","electric tension","voltage","millivolt","millivolts","mV"] +}, +{ + "name": "unit.microvolts", + "symbol": "μV", + "tags": ["electric potential","electric tension","voltage","microvolt","microvolts","μV"] +}, +{ + "name": "unit.volt", + "symbol": "V", + "tags": ["electric potential","electric tension","voltage","volt","volts","V","power source","battery","battery level"] +}, +{ + "name": "unit.kilovolts", + "symbol": "kV", + "tags": ["electric potential","electric tension","voltage","kilovolt","kilovolts","kV"] +}, +{ + "name": "unit.dbmV", + "symbol": "dBmV", + "tags": ["decibels millivolt","voltage level","signal","dBmV"] +}, +{ + "name": "unit.volt-meter", + "symbol": "V·m", + "tags": ["electric flux","volt-meter","V·m"] +}, +{ + "name": "unit.kilovolt-meter", + "symbol": "kV·m", + "tags": ["electric flux","kilovolt-meter","kV·m"] +}, +{ + "name": "unit.megavolt-meter", + "symbol": "MV·m", + "tags": ["electric flux","megavolt-meter","MV·m"] +}, +{ + "name": "unit.microvolt-meter", + "symbol": "µV·m", + "tags": ["electric flux","microvolt-meter","µV·m"] +}, +{ + "name": "unit.millivolt-meter", + "symbol": "mV·m", + "tags": ["electric flux","millivolt-meter","mV·m"] +}, +{ + "name": "unit.nanovolt-meter", + "symbol": "nV·m", + "tags": ["electric flux","nanovolt-meter","nV·m"] +}, +{ + "name": "unit.ohm", + "symbol": "Ω", + "tags": ["electrical resistance","resistance","impedance","ohm"] +}, +{ + "name": "unit.microohm", + "symbol": "μΩ", + "tags": ["electrical resistance","resistance","microohm","μΩ"] +}, +{ + "name": "unit.milliohm", + "symbol": "mΩ", + "tags": ["electrical resistance","resistance","milliohm","mΩ"] +}, +{ + "name": "unit.kilohm", + "symbol": "kΩ", + "tags": ["electrical resistance","resistance","kilohm","kΩ"] +}, +{ + "name": "unit.megohm", + "symbol": "MΩ", + "tags": ["electrical resistance","resistance","megohm","MΩ"] +}, +{ + "name": "unit.gigohm", + "symbol": "GΩ", + "tags": ["electrical resistance","resistance","gigohm","GΩ"] +}, +{ + "name": "unit.hertz", + "symbol": "Hz", + "tags": ["frequency","cycles per second","hertz","Hz"] +}, +{ + "name": "unit.kilohertz", + "symbol": "kHz", + "tags": ["frequency","cycles per second","kilohertz","kHz"] +}, +{ + "name": "unit.megahertz", + "symbol": "MHz", + "tags": ["frequency","cycles per second","megahertz","MHz"] +}, +{ + "name": "unit.gigahertz", + "symbol": "GHz", + "tags": ["frequency","cycles per second","gigahertz","GHz"] +}, +{ + "name": "unit.rpm", + "symbol": "RPM", + "tags": ["speed","velocity","cycle","engine","Revolutions Per Minute","RPM","angular velocity","rotation speed"] +}, +{ + "name": "unit.candela-per-square-meter", + "symbol": "cd/m²", + "tags": ["brightness","light level","Luminance","Candela per square meter","cd/m²"] +}, +{ + "name": "unit.candela", + "symbol": "cd", + "tags": ["light intensity","candle power","luminous intensity","Candela","cd"] +}, +{ + "name": "unit.lumen", + "symbol": "lm", + "tags": ["total light output","light power","luminous flux","Lumen","lm"] +}, +{ + "name": "unit.lux", + "symbol": "lx", + "tags": ["illumination","light level on a surface","illuminance","Lux","lx"] +}, +{ + "name": "unit.foot-candle", + "symbol": "fc", + "tags": ["illuminance","light level","foot-candle","fc"] +}, +{ + "name": "unit.lumen-per-square-meter", + "symbol": "lm/m²", + "tags": ["illuminance","light level","lumen per square meter","lm/m²"] +}, +{ + "name": "unit.lux-second", + "symbol": "lx·s", + "tags": ["light exposure","illumination time","light dosage","Lux second","lx·s"] +}, +{ + "name": "unit.lumen-second", + "symbol": "lm·s", + "tags": ["total light energy","luminous energy","Lumen second","lm·s"] +}, +{ + "name": "unit.lumens-per-watt", + "symbol": "lm/W", + "tags": ["lighting efficiency","light output per energy","luminous efficacy","Lumens per watt","lm/W"] +}, +{ + "name": "unit.absorbance", + "symbol": "AU", + "tags": ["optical density","light absorption","absorbance","AU"] +}, +{ + "name": "unit.mole", + "symbol": "mol", + "tags": ["amount of substance","substance quantity","mole","moles","mol"] +}, +{ + "name": "unit.nanomole", + "symbol": "nmol", + "tags": ["amount of substance","substance quantity","concentration","nanomole","nmol"] +}, +{ + "name": "unit.micromole", + "symbol": "μmol", + "tags": ["amount of substance","substance quantity","micromole","μmol"] +}, +{ + "name": "unit.millimole", + "symbol": "mmol", + "tags": ["amount of substance","substance quantity","millimole","mmol"] +}, +{ + "name": "unit.kilomole", + "symbol": "kmol", + "tags": ["amount of substance","substance quantity","kilomole","kmol"] +}, +{ + "name": "unit.mole-per-cubic-meter", + "symbol": "mol/m³", + "tags": ["concentration","amount of substance","mole per cubic meter","mol/m³"] +}, +{ + "name": "unit.percent", + "symbol": "%", + "tags": ["power source","state of charge (SoC)","battery","battery level","level","humidity","moisture","percentage", + "relative humidity","water content","soil moisture","irrigation","water in soil","soil water content","VWC", + "Volumetric Water Content","Total Harmonic Distortion","THD","power quality","UV Transmittance","%"] +}, +{ + "name": "unit.rssi", + "symbol": "rssi", + "tags": ["signal strength","signal level","received signal strength indicator","rssi","dBm"] +}, +{ + "name": "unit.ppm", + "symbol": "ppm", + "tags": ["carbon dioxide","co²","carbon monoxide","co","aqi","air quality","total volatile organic compounds","tvoc","ppm"] +}, +{ + "name": "unit.ppb", + "symbol": "ppb", + "tags": ["ozone","o³","nitrogen dioxide","no²","sulfur dioxide","so²","aqi","air quality","tvoc","ppb"] +}, +{ + "name": "unit.micrograms-per-cubic-meter", + "symbol": "µg/m³", + "tags": ["coarse particulate matter","pm10","fine particulate matter","pm2.5","aqi","air quality", + "total volatile organic compounds","tvoc","micrograms per cubic meter","µg/m³"] +}, +{ + "name": "unit.aqi", + "symbol": "aqi", + "tags": ["AQI","air quality index"] +}, +{ + "name": "unit.gram-per-cubic-meter", + "symbol": "g/m³", + "tags": ["humidity","moisture","absolute humidity","g/m³"] +}, +{ + "name": "unit.gram-per-kilogram", + "symbol": "g/kg", + "tags": ["humidity","moisture","specific humidity","g/kg"] +}, +{ + "name": "unit.millimeters-per-second", + "symbol": "mm/s", + "tags": ["velocity","speed","rate of motion","peak","peak to peak","root mean square (RMS)","vibration","mm/s"] +}, +{ + "name": "unit.neper", + "symbol": "Np", + "tags": ["logarithmic unit","ratio","gain","loss","attenuation","neper","Np"] +}, +{ + "name": "unit.bel", + "symbol": "B", + "tags": ["logarithmic unit","power ratio","intensity ratio","bel","B"] +}, +{ + "name": "unit.decibel", + "symbol": "dB", + "tags": ["noise level","sound level","volume","acoustics","decibel","dB"] +}, +{ + "name": "unit.meters-per-second-squared", + "symbol": "m/s²", + "tags": ["peak","peak to peak","root mean square (RMS)","vibration","meters per second squared","m/s²"] +}, +{ + "name": "unit.becquerel", + "symbol": "Bq", + "tags": ["radioactivity","radiation","becquerel","Bq"] +}, +{ + "name": "unit.curie", + "symbol": "Ci", + "tags": ["radioactivity","radiation","curie","Ci"] +}, +{ + "name": "unit.gray", + "symbol": "Gy", + "tags": ["radiation dose","gray","Gy"] +}, +{ + "name": "unit.sievert", + "symbol": "Sv", + "tags": ["radiation dose","sievert","radiation dose equivalent2","Sv"] +}, +{ + "name": "unit.roentgen", + "symbol": "R", + "tags": ["radiation exposure","roentgen","R"] +}, +{ + "name": "unit.cps", + "symbol": "cps", + "tags": ["radiation detection","counts per second","cps"] +}, +{ + "name": "unit.rad", + "symbol": "Rad", + "tags": ["radiation dose","rad"] +}, +{ + "name": "unit.rem", + "symbol": "Rem", + "tags": ["radiation dose equivalent","rem"] +}, +{ + "name": "unit.dps", + "symbol": "dps", + "tags": ["radioactive decay","radioactivity","disintegrations per second","dps"] +}, +{ + "name": "unit.rutherford", + "symbol": "Rd", + "tags": ["radioactive decay","radioactivity","rutherford","Rd"] +}, +{ + "name": "unit.coulombs-per-kilogram", + "symbol": "C/kg", + "tags": ["radiation exposure","dose","coulombs per kilogram","electric charge-to-mass ratio","C/kg"] +}, +{ + "name": "unit.becquerels-per-cubic-meter", + "symbol": "Bq/m³", + "tags": ["radioactivity","radiation","becquerels per cubic meter","Bq/m³"] +}, +{ + "name": "unit.curies-per-liter", + "symbol": "Ci/L", + "tags": ["radioactivity","radiation","curies per liter","Ci/L"] +}, +{ + "name": "unit.becquerels-per-second", + "symbol": "Bq/s", + "tags": ["radioactive decay rate","becquerels per second","Bq/s"] +}, +{ + "name": "unit.curies-per-second", + "symbol": "Ci/s", + "tags": ["radioactive decay rate","curies per second","Ci/s"] +}, +{ + "name": "unit.gy-per-second", + "symbol": "Gy/s", + "tags": ["absorbed dose rate","radiation dose rate","gray per second","Gy/s"] +}, +{ + "name": "unit.watt-per-steradian", + "symbol": "W/sr", + "tags": ["radiant intensity","power per unit solid angle","watt per steradian","W/sr"] +}, +{ + "name": "unit.watt-per-square-metre-steradian", + "symbol": "W/(m²·sr)", + "tags": ["radiance","radiant flux density","watt per square metre-steradian","W/(m²·sr)"] +}, +{ + "name": "unit.ph-level", + "symbol": "pH", + "tags": ["acidity","alkalinity","neutral","acid","base","pH","soil pH","water quality","water pH"] +}, +{ + "name": "unit.turbidity", + "symbol": "NTU", + "tags": ["water turbidity","water clarity","Nephelometric Turbidity Units","NTU"] +}, +{ + "name": "unit.mg-per-liter", + "symbol": "mg/L", + "tags": ["dissolved oxygen","water quality","mg/L"] +}, +{ + "name": "unit.microsiemens-per-centimeter", + "symbol": "µS/cm", + "tags": ["Electrical conductivity","water quality","soil quality","microsiemens per centimeter","µS/cm"] +}, +{ + "name": "unit.millisiemens-per-meter", + "symbol": "mS/m", + "tags": ["Electrical conductivity","water quality","soil quality","millisiemens per meter","mS/m"] +}, +{ + "name": "unit.siemens-per-meter", + "symbol": "S/m", + "tags": ["Electrical conductivity","water quality","soil quality","siemens per meter","S/m"] +}, +{ + "name": "unit.kilogram-per-cubic-meter", + "symbol": "kg/m³", + "tags": ["density","mass per unit volume","kg/m³"] +}, +{ + "name": "unit.gram-per-cubic-centimeter", + "symbol": "g/cm³", + "tags": ["density","mass per unit volume","g/cm³"] +}, +{ + "name": "unit.kilogram-per-square-meter", + "symbol": "kg/m²", + "tags": ["density","surface density","areal density","mass per unit area","kg/m²"] +}, +{ + "name": "unit.milligram-per-milliliter", + "symbol": "mg/mL", + "tags": ["concentration","mass per volume","mg/mL"] +}, +{ + "name": "unit.pound-per-cubic-foot", + "symbol": "lb/ft³", + "tags": ["Density","mass per unit volume","lb/ft³"] +}, +{ + "name": "unit.ounces-per-cubic-inch", + "symbol": "oz/in³", + "tags": ["density","mass per unit volume","oz/in³"] +}, +{ + "name": "unit.tons-per-cubic-yard", + "symbol": "ton/yd³", + "tags": ["density","mass per unit volume","ton/yd³"] +}, +{ + "name": "unit.particle-density", + "symbol": "particles/mL", + "tags": ["particle concentration","count","particles/mL"] +}, +{ + "name": "unit.kilometers-per-liter", + "symbol": "km/L", + "tags": ["fuel efficiency","km/L"] +}, +{ + "name": "unit.miles-per-gallon", + "symbol": "mpg", + "tags": ["fuel efficiency","mpg"] +}, +{ + "name": "unit.liters-per-100-km", + "symbol": "L/100km", + "tags": ["fuel efficiency","L/100km"] +}, +{ + "name": "unit.gallons-per-mile", + "symbol": "gal/mi", + "tags": ["fuel efficiency","gal/mi"] +}, +{ + "name": "unit.liters-per-hour", + "symbol": "L/hr", + "tags": ["fuel consumption","L/hr"] +}, +{ + "name": "unit.gallons-per-hour", + "symbol": "gal/hr", + "tags": ["fuel consumption","gal/hr"] +}, +{ + "name": "unit.beats-per-minute", + "symbol": "bpm", + "tags": ["heart rate","pulse","bpm"] +}, +{ + "name": "unit.millimeters-of-mercury", + "symbol": "mmHg", + "tags": ["blood pressure","systolic","diastolic","mmHg"] +}, +{ + "name": "unit.milligrams-per-deciliter", + "symbol": "mg/dL", + "tags": ["glucose","blood sugar","glucose level","mg/dL"] +}, +{ + "name": "unit.g-force", + "symbol": "G", + "tags": ["acceleration","gravity","force","g-load","G"] +}, +{ + "name": "unit.kilonewton", + "symbol": "kN", + "tags": ["force","kN"] +}, +{ + "name": "unit.kilogram-force", + "symbol": "kgf", + "tags": ["force","kgf"] +}, +{ + "name": "unit.pound-force", + "symbol": "lbf", + "tags": ["force","lbf"] +}, +{ + "name": "unit.kilopound-force", + "symbol": "klbf", + "tags": ["force","klbf"] +}, +{ + "name": "unit.dyne", + "symbol": "dyn", + "tags": ["force","dyn"] +}, +{ + "name": "unit.poundal", + "symbol": "pdl", + "tags": ["force","pdl"] +}, +{ + "name": "unit.kip", + "symbol": "kip", + "tags": ["force","kip"] +}, +{ + "name": "unit.gal", + "symbol": "Gal", + "tags": ["acceleration","gravity","g-force","Gal"] +}, +{ + "name": "unit.gravity", + "symbol": "gravity", + "tags": ["acceleration","gravity","g-force"] +}, +{ + "name": "unit.hectopascal", + "symbol": "hPa", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","hPa"] +}, +{ + "name": "unit.atmosphere", + "symbol": "atm", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","atm"] +}, +{ + "name": "unit.millibars", + "symbol": "mb", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","mb"] +}, +{ + "name": "unit.inch-of-mercury", + "symbol": "inHg", + "tags": ["atmospheric pressure","air pressure","weather","altitude","flight","inHg","richter"] +}, +{ + "name": "unit.richter-scale", + "symbol": "richter", + "tags": ["earthquake","seismic activity","richter"] +}, +{ + "name": "unit.second", + "symbol": "s", + "tags": ["time","duration","interval","angle","second","arcsecond","sec"] +}, +{ + "name": "unit.minute", + "symbol": "min", + "tags": ["time","duration","interval","angle","minute","arcminute","min"] +}, +{ + "name": "unit.hour", + "symbol": "h", + "tags": ["time","duration","interval","h"] +}, +{ + "name": "unit.day", + "symbol": "d", + "tags": ["time","duration","interval","d"] +}, +{ + "name": "unit.week", + "symbol": "wk", + "tags": ["time","duration","interval","wk"] +}, +{ + "name": "unit.month", + "symbol": "mo", + "tags": ["time","duration","interval","mo"] +}, +{ + "name": "unit.year", + "symbol": "yr", + "tags": ["time","duration","interval","yr"] +}, +{ + "name": "unit.cubic-foot-per-minute", + "symbol": "ft³/min", + "tags": ["airflow","ventilation","HVAC","gas flow rate","CFM","flow rate","fluid flow","cubic foot per minute","ft³/min"] +}, +{ + "name": "unit.cubic-meters-per-hour", + "symbol": "m³/hr", + "tags": ["airflow","ventilation","HVAC","gas flow rate","cubic meters per hour","m³/hr"] +}, +{ + "name": "unit.cubic-meters-per-second", + "symbol": "m³/s", + "tags": ["airflow","ventilation","HVAC","gas flow rate","cubic meters per second","m³/s"] +}, +{ + "name": "unit.liter-per-second", + "symbol": "L/s", + "tags": ["airflow","ventilation","HVAC","gas flow rate","liter per second","L/s"] +}, +{ + "name": "unit.liter-per-minute", + "symbol": "L/min", + "tags": ["airflow","ventilation","HVAC","gas flow rate","liter per minute","L/min"] +}, +{ + "name": "unit.gallons-per-minute", + "symbol": "GPM", + "tags": ["airflow","ventilation","HVAC","gas flow rate","gallons per minute","GPM"] +}, +{ + "name": "unit.cubic-foot-per-second", + "symbol": "ft³/s", + "tags": ["flow rate","fluid flow","cubic foot per second","cubic feet per second","ft³/s"] +}, +{ + "name": "unit.milliliters-per-minute", + "symbol": "mL/min", + "tags": ["Flow rate","fluid dynamics","milliliters per minute","mL/min"] +}, +{ + "name": "unit.bit", + "symbol": "bit", + "tags": ["data","binary digit","information","bit"] +}, +{ + "name": "unit.byte", + "symbol": "B", + "tags": ["data","byte","information","storage","memory","B"] +}, +{ + "name": "unit.kilobyte", + "symbol": "KB", + "tags": ["data","kilobyte","KB"] +}, +{ + "name": "unit.megabyte", + "symbol": "MB", + "tags": ["data","megabyte","MB"] +}, +{ + "name": "unit.gigabyte", + "symbol": "GB", + "tags": ["data","gigabyte","GB"] +}, +{ + "name": "unit.terabyte", + "symbol": "TB", + "tags": ["data","terabyte","TB"] +}, +{ + "name": "unit.petabyte", + "symbol": "PB", + "tags": ["data","petabyte","PB"] +}, +{ + "name": "unit.exabyte", + "symbol": "EB", + "tags": ["data","exabyte","EB"] +}, +{ + "name": "unit.zettabyte", + "symbol": "ZB", + "tags": ["data","zettabyte","ZB"] +}, +{ + "name": "unit.yottabyte", + "symbol": "YB", + "tags": ["data","yottabyte","YB"] +}, +{ + "name": "unit.bit-per-second", + "symbol": "bps", + "tags": ["data transfer rate","bps"] +}, +{ + "name": "unit.kilobit-per-second", + "symbol": "kbps", + "tags": ["data transfer rate","kbps"] +}, +{ + "name": "unit.megabit-per-second", + "symbol": "Mbps", + "tags": ["data transfer rate","Mbps"] +}, +{ + "name": "unit.gigabit-per-second", + "symbol": "Gbps", + "tags": ["data transfer rate","Gbps"] +}, +{ + "name": "unit.terabit-per-second", + "symbol": "Tbps", + "tags": ["data transfer rate","Tbps"] +}, +{ + "name": "unit.byte-per-second", + "symbol": "B/s", + "tags": ["data transfer rate","B/s"] +}, +{ + "name": "unit.kilobyte-per-second", + "symbol": "KB/s", + "tags": ["data transfer rate","KB/s"] +}, +{ + "name": "unit.megabyte-per-second", + "symbol": "MB/s", + "tags": ["data transfer rate","MB/s"] +}, +{ + "name": "unit.gigabyte-per-second", + "symbol": "GB/s", + "tags": ["data transfer rate","GB/s"] +}, +{ + "name": "unit.degree", + "symbol": "deg", + "tags": ["angle","degree","degrees","deg"] +}, +{ + "name": "unit.radian", + "symbol": "rad", + "tags": ["angle","radian","radians","rad"] +}, +{ + "name": "unit.gradian", + "symbol": "grad", + "tags": ["angle","gradian","grades","grad"] +}, +{ + "name": "unit.mil", + "symbol": "mil", + "tags": ["angle","military angle","angular mil","mil"] +}, +{ + "name": "unit.revolution", + "symbol": "rev", + "tags": ["angle","revolution","full circle","complete turn","rev"] +}, +{ + "name": "unit.siemens", + "symbol": "S", + "tags": ["electrical conductance","conductance","siemens","S"] +}, +{ + "name": "unit.millisiemens", + "symbol": "mS", + "tags": ["electrical conductance","conductance","millisiemens","mS"] +}, +{ + "name": "unit.microsiemens", + "symbol": "μS", + "tags": ["electrical conductance","conductance","microsiemens","μS"] +}, +{ + "name": "unit.kilosiemens", + "symbol": "kS", + "tags": ["electrical conductance","conductance","kilosiemens","kS"] +}, +{ + "name": "unit.megasiemens", + "symbol": "MS", + "tags": ["electrical conductance","conductance","megasiemens","MS"] +}, +{ + "name": "unit.gigasiemens", + "symbol": "GS", + "tags": ["electrical conductance","conductance","gigasiemens","GS"] +}, +{ + "name": "unit.farad", + "symbol": "F", + "tags": ["electric capacitance","capacitance","farad","F"] +}, +{ + "name": "unit.millifarad", + "symbol": "mF", + "tags": ["electric capacitance","capacitance","millifarad","mF"] +}, +{ + "name": "unit.microfarad", + "symbol": "μF", + "tags": ["electric capacitance","capacitance","microfarad","μF"] +}, +{ + "name": "unit.nanofarad", + "symbol": "nF", + "tags": ["electric capacitance","capacitance","nanofarad","nF"] +}, +{ + "name": "unit.picofarad", + "symbol": "pF", + "tags": ["electric capacitance","capacitance","picofarad","pF"] +}, +{ + "name": "unit.kilofarad", + "symbol": "kF", + "tags": ["electric capacitance","capacitance","kilofarad","kF"] +}, +{ + "name": "unit.megafarad", + "symbol": "MF", + "tags": ["electric capacitance","capacitance","megafarad","MF"] +}, +{ + "name": "unit.gigafarad", + "symbol": "GF", + "tags": ["electric capacitance","capacitance","gigafarad","GF"] +}, +{ + "name": "unit.terfarad", + "symbol": "TF", + "tags": ["electric capacitance","capacitance","terafarad","TF"] +}, +{ + "name": "unit.farad-per-meter", + "symbol": "F/m", + "tags": ["electric permittivity","farad per meter","F/m"] +}, +{ + "name": "unit.tesla", + "symbol": "T", + "tags": ["magnetic field","magnetic field strength","tesla","T","magnetic flux density"] +}, +{ + "name": "unit.gauss", + "symbol": "G", + "tags": ["magnetic field","magnetic field strength","gauss","G","magnetic flux density"] +}, +{ + "name": "unit.kilogauss", + "symbol": "kG", + "tags": ["magnetic field","magnetic field strength","kilogauss","kG","magnetic flux density"] +}, +{ + "name": "unit.millitesla", + "symbol": "mT", + "tags": ["magnetic field","magnetic field strength","millitesla","mT"] +}, +{ + "name": "unit.microtesla", + "symbol": "μT", + "tags": ["magnetic field","magnetic field strength","microtesla","μT"] +}, +{ + "name": "unit.nanotesla", + "symbol": "nT", + "tags": ["magnetic field","magnetic field strength","nanotesla","nT"] +}, +{ + "name": "unit.kilotesla", + "symbol": "kT", + "tags": ["magnetic field","magnetic field strength","kilotesla","kT"] +}, +{ + "name": "unit.megatesla", + "symbol": "MT", + "tags": ["magnetic field","magnetic field strength","megatesla","MT"] +}, +{ + "name": "unit.millitesla-square-meters", + "symbol": "millitesla square meters", + "tags": ["magnetic field","millitesla square meters"] +}, +{ + "name": "unit.gamma", + "symbol": "γ", + "tags": ["magnetic flux density","gamma","γ"] +}, +{ + "name": "unit.lambda", + "symbol": "λ", + "tags": ["wavelength","lambda","λ"] +}, +{ + "name": "unit.square-meter-per-second", + "symbol": "m²/s", + "tags": ["kinematic viscosity","m²/s"] +}, +{ + "name": "unit.square-centimeter-per-second", + "symbol": "cm²/s", + "tags": ["kinematic viscosity","cm²/s"] +}, +{ + "name": "unit.stoke", + "symbol": "St", + "tags": ["kinematic viscosity","stokes","St"] +}, +{ + "name": "unit.centistokes", + "symbol": "cSt", + "tags": ["kinematic viscosity","centistokes","cSt"] +}, +{ + "name": "unit.square-foot-per-second", + "symbol": "ft²/s", + "tags": ["kinematic viscosity","ft²/s"] +}, +{ + "name": "unit.square-inch-per-second", + "symbol": "in²/s", + "tags": ["kinematic viscosity","in²/s"] +}, +{ + "name": "unit.pascal-second", + "symbol": "Pa·s", + "tags": ["dynamic viscosity","viscosity","fluid mechanics","pascal-second","Pa·s"] +}, +{ + "name": "unit.centipoise", + "symbol": "cP", + "tags": ["viscosity","dynamic viscosity","fluid viscosity","centipoise","cP"] +}, +{ + "name": "unit.poise", + "symbol": "P", + "tags": ["viscosity","dynamic viscosity","fluid viscosity","poise","P"] +}, +{ + "name": "unit.reynolds", + "symbol": "Re", + "tags": ["fluid flow regime","fluid mechanics","reynolds","Re"] +}, +{ + "name": "unit.pound-per-foot-hour", + "symbol": "lb/(ft·h)", + "tags": ["pound per foot-hour","lb/(ft·h)"] +}, +{ + "name": "unit.newton-second-per-square-meter", + "symbol": "N·s/m²", + "tags": ["newton second per square meter","N·s/m²"] +}, +{ + "name": "unit.dyne-second-per-square-centimeter", + "symbol": "dyn·s/cm²", + "tags": ["dyne second per square centimeter","dyn·s/cm²"] +}, +{ + "name": "unit.kilogram-per-meter-second", + "symbol": "kg/(m·s)", + "tags": ["kilogram per meter-second","kg/(m·s)"] +}, +{ + "name": "unit.tesla-square-meters", + "symbol": "T/m²", + "tags": ["magnetic flux density","tesla square meters","T/m²"] +}, +{ + "name": "unit.maxwell", + "symbol": "Mx", + "tags": ["magnetic flux","magnetic field","maxwell","Mx"] +}, +{ + "name": "unit.tesla-per-meter", + "symbol": "T/m", + "tags": ["magnetic field","tesla per meter","T/m"] +}, +{ + "name": "unit.gauss-per-centimeter", + "symbol": "G/cm", + "tags": ["magnetic field","gauss per centimeter","G/cm"] +}, +{ + "name": "unit.weber", + "symbol": "Wb", + "tags": ["magnetic flux","weber","Wb"] +}, +{ + "name": "unit.microweber", + "symbol": "µWb", + "tags": ["magnetic flux","microweber","µWb"] +}, +{ + "name": "unit.milliweber", + "symbol": "mWb", + "tags": ["magnetic flux","milliweber","mWb"] +}, +{ + "name": "unit.gauss-square-centimeter", + "symbol": "G·cm²", + "tags": ["magnetic flux","gauss-square centimeter","G·cm²"] +}, +{ + "name": "unit.kilogauss-square-centimeter", + "symbol": "kG·cm²", + "tags": ["magnetic flux","kilogauss-square centimeter","kG·cm²"] +}, +{ + "name": "unit.henry", + "symbol": "H", + "tags": ["inductance","magnetic induction","H"] +}, +{ + "name": "unit.millihenry", + "symbol": "mH", + "tags": ["inductance","millihenry","mH"] +}, +{ + "name": "unit.microhenry", + "symbol": "µH", + "tags": ["inductance","microhenry","µH"] +}, +{ + "name": "unit.nanohenry", + "symbol": "nH", + "tags": ["inductance","nanohenry","nH"] +}, +{ + "name": "unit.henry-per-meter", + "symbol": "H/m", + "tags": ["magnetic permeability","henry per meter","H/m"] +}, +{ + "name": "unit.tesla-meter-per-ampere", + "symbol": "T·m/A", + "tags": ["magnetic field","Tesla Meter per Ampere","T·m/A","magnetic flux"] +}, +{ + "name": "unit.gauss-per-oersted", + "symbol": "G/Oe", + "tags": ["magnetic field","Gauss per Oersted","G/Oe"] +}, +{ + "name": "unit.kilogram-per-mole", + "symbol": "kg/mol", + "tags": ["molar mass","kilogram per mole","kg/mol"] +}, +{ + "name": "unit.gram-per-mole", + "symbol": "g/mol", + "tags": ["molar mass","gram per mole","g/mol"] +}, +{ + "name": "unit.milligram-per-mole", + "symbol": "mg/mol", + "tags": ["molar mass","milligram per mole","mg/mol"] +}, +{ + "name": "unit.joule-per-mole", + "symbol": "J/mol", + "tags": ["molar energy","joule per mole","J/mol"] +}, +{ + "name": "unit.joule-per-mole-kelvin", + "symbol": "J/(mol·K)", + "tags": ["molar heat capacity","joule per mole-kelvin","J/(mol·K)"] +}, +{ + "name": "unit.millivolts-per-meter", + "symbol": "mV/m", + "tags": ["electric field strength","millivolts per meter","mV/m"] +}, +{ + "name": "unit.volts-per-meter", + "symbol": "V/m", + "tags": ["electric field strength","volts per meter","V/m"] +}, +{ + "name": "unit.kilovolts-per-meter", + "symbol": "kV/m", + "tags": ["electric field strength","kilovolts per meter","kV/m"] +}, +{ + "name": "unit.radian-per-second", + "symbol": "rad/s", + "tags": ["angular velocity","rotation speed","rad/s"] +}, +{ + "name": "unit.radian-per-second-squared", + "symbol": "rad/s²", + "tags": ["angular acceleration","rotation rate of change","rad/s²"] +}, +{ + "name": "unit.revolutions-per-minute-per-second", + "symbol": "rpm/s", + "tags": ["angular acceleration","rotation rate of change","rpm/s"] +}, +{ + "name": "unit.revolutions-per-minute-per-second-squared", + "symbol": "rpm/s²", + "tags": ["angular acceleration","rotation rate of change","rpm/s²"] +}, +{ + "name": "unit.deg-per-second", + "symbol": "deg/s", + "tags": ["angular velocity","degrees per second","deg/s"] +}, +{ + "name": "unit.degrees-brix", + "symbol": "°Bx", + "tags": ["sugar content","fruit ripeness","Bx"] +}, +{ + "name": "unit.katal", + "symbol": "kat", + "tags": ["catalytic activity","enzyme activity","kat"] +}, +{ + "name": "unit.katal-per-cubic-metre", + "symbol": "kat/m³", + "tags": ["catalytic activity concentration","enzyme concentration","kat/m³"] +}] From 642066d9b03c4228748eacaa4c40ac970e0e68ed Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 20 Jul 2023 11:37:16 +0300 Subject: [PATCH 286/421] UI: Refactoring --- .../notification-setting-form.component.html | 2 +- .../notification-setting-form.component.ts | 11 ++++++----- .../notification-settings.component.html | 5 ++++- .../notification-settings.component.ts | 18 ++++++++++++++---- .../app/shared/models/notification.models.ts | 6 ------ 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html index 752ffa367a..284cd67fa1 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-setting-form.component.html @@ -27,7 +27,7 @@
-
+
{ + this.deliveryMethods.forEach(value => { deliveryMethod[value] = true; }); this.notificationSettingsFormGroup = this.fb.group( diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html index 8f7a421a82..c531f10d78 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.html @@ -62,7 +62,10 @@
- + +
diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts index 8ca3eea97a..8eac5d638d 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts @@ -25,7 +25,7 @@ import { ActivatedRoute } from '@angular/router'; import { deepClone, isDefinedAndNotNull } from '@core/utils'; import { NotificationDeliveryMethod, - NotificationDeliveryMethodTranslateMap, NotificationSettingsDeliveryMethod, + NotificationDeliveryMethodTranslateMap, NotificationUserSettings } from '@shared/models/notification.models'; import { NotificationService } from '@core/http/notification.service'; @@ -40,7 +40,7 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn notificationSettings: UntypedFormGroup; - notificationDeliveryMethods = Object.values(NotificationSettingsDeliveryMethod); + notificationDeliveryMethods: NotificationDeliveryMethod[]; notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap; allowNotificationDeliveryMethods: Array; @@ -55,6 +55,7 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn } ngOnInit() { + this.notificationDeliveryMethods = this.getNotificationDeliveryMethods(); this.notificationService.getAvailableDeliveryMethods({ignoreLoading: true}).subscribe(allowMethods => { this.allowNotificationDeliveryMethods = allowMethods; @@ -64,6 +65,15 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn this.patchNotificationSettings(this.route.snapshot.data.userSettings); } + private getNotificationDeliveryMethods(): NotificationDeliveryMethod[] { + const deliveryMethods = new Set([ + NotificationDeliveryMethod.WEB, + NotificationDeliveryMethod.SMS, + NotificationDeliveryMethod.EMAIL + ]); + return Object.values(NotificationDeliveryMethod).filter(type => deliveryMethods.has(type)); + } + private buildNotificationSettingsForm() { this.notificationSettings = this.fb.group({ prefs: this.fb.array([]) @@ -77,8 +87,8 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn preparedSettings = this.prepareNotificationSettings(settings.prefs); preparedSettings.forEach((setting) => { setting.enabledDeliveryMethods = Object.assign( - setting.enabledDeliveryMethods, - this.notificationDeliveryMethods.reduce((a, v) => ({ ...a, [v]: true}), {}) + this.notificationDeliveryMethods.reduce((a, v) => ({ ...a, [v]: true}), {}), + setting.enabledDeliveryMethods ); notificationSettingsControls.push(this.fb.control(setting, [Validators.required])); }); diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index c6a3253f1a..9cc3033ee7 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -598,9 +598,3 @@ export interface NotificationUserSetting { enabled: boolean; enabledDeliveryMethods: {[key: string]: boolean}; } - -export enum NotificationSettingsDeliveryMethod { - WEB = 'WEB', - SMS = 'SMS', - EMAIL = 'EMAIL' -} From 0a1b19ebf8908427db8aa2bc3df83129979a8f62 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 20 Jul 2023 11:46:00 +0300 Subject: [PATCH 287/421] UI: Refactoring get notification method --- .../settings/notification-settings.component.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts index 8eac5d638d..c28e030eec 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts @@ -67,11 +67,9 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn private getNotificationDeliveryMethods(): NotificationDeliveryMethod[] { const deliveryMethods = new Set([ - NotificationDeliveryMethod.WEB, - NotificationDeliveryMethod.SMS, - NotificationDeliveryMethod.EMAIL + NotificationDeliveryMethod.SLACK ]); - return Object.values(NotificationDeliveryMethod).filter(type => deliveryMethods.has(type)); + return Object.values(NotificationDeliveryMethod).filter(type => !deliveryMethods.has(type)); } private buildNotificationSettingsForm() { From 5e0a6667f51c726b20df38654d915d4999facdba Mon Sep 17 00:00:00 2001 From: deaflynx Date: Thu, 20 Jul 2023 12:30:50 +0300 Subject: [PATCH 288/421] EntitiesTableWidgetComponent rename rowPointer to hasRowAction --- .../widget/lib/entities-table-widget.component.html | 2 +- .../components/widget/lib/entities-table-widget.component.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html index 1844ab3ea5..4f941a0047 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html @@ -89,7 +89,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index 4a5a891703..b5e8d90b51 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -150,7 +150,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni public displayedColumns: string[] = []; public entityDatasource: EntityDatasource; public noDataDisplayMessageText: string; - public rowPointer: boolean; + public hasRowAction: boolean; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -279,7 +279,7 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.setCellButtonAction = !!this.ctx.actionsApi.getActionDescriptors('actionCellButton').length; - this.rowPointer = !!this.ctx.actionsApi.getActionDescriptors('rowClick').length || !!this.ctx.actionsApi.getActionDescriptors('rowDoubleClick').length; + this.hasRowAction = !!this.ctx.actionsApi.getActionDescriptors('rowClick').length || !!this.ctx.actionsApi.getActionDescriptors('rowDoubleClick').length; if (this.settings.entitiesTitle && this.settings.entitiesTitle.length) { this.entitiesTitlePattern = this.utils.customTranslation(this.settings.entitiesTitle, this.settings.entitiesTitle); From db46b7988da7cce2f75d4d1e4c18372f6c2cb3e7 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 20 Jul 2023 12:33:15 +0300 Subject: [PATCH 289/421] refactored code to take into account operating system --- .../server/controller/BaseController.java | 9 + .../controller/ControllerConstants.java | 2 + .../DeviceConnectivityController.java | 108 +++++ .../server/controller/DeviceController.java | 33 -- .../src/main/resources/thingsboard.yml | 2 +- .../DeviceConnectivityControllerTest.java | 398 ++++++++++++++++++ .../controller/DeviceControllerTest.java | 184 +------- .../dao/device/DeviceConnectivityService.java | 13 +- .../server/dao/device/DeviceService.java | 3 - .../dao/device/DeviceConnectivityInfo.java | 2 +- .../DeviceConnectivityMqttSslCertService.java | 53 --- .../server/dao/device/DeviceServiceImpl.java | 109 ----- .../DeviceСonnectivityServiceImpl.java | 224 ++++++++++ .../dao/util/DeviceConnectivityUtil.java | 51 ++- 14 files changed, 802 insertions(+), 389 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java create mode 100644 application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java rename dao/src/main/java/org/thingsboard/server/dao/device/TbDeviceConnectivitySslCertService.java => common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java (62%) delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 68a987a0bc..a03fcd36a4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -113,6 +113,7 @@ import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.ClaimDevicesService; +import org.thingsboard.server.dao.device.DeviceConnectivityService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; @@ -163,6 +164,7 @@ import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import javax.mail.MessagingException; import javax.servlet.http.HttpServletResponse; import javax.validation.ConstraintViolation; +import java.io.IOException; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -208,6 +210,9 @@ public abstract class BaseController { @Autowired protected DeviceService deviceService; + @Autowired + protected DeviceConnectivityService deviceConnectivityService; + @Autowired protected DeviceProfileService deviceProfileService; @@ -755,6 +760,10 @@ public abstract class BaseController { return checkEntityId(resourceId, resourceService::findResourceInfoById, operation); } + String checkSslServerPemFile(String protocol) throws ThingsboardException, IOException { + return checkNotNull(deviceConnectivityService.getSslServerChain(protocol), "Mqtt ssl server chain pem file is not found"); + } + OtaPackage checkOtaPackageId(OtaPackageId otaPackageId, Operation operation) throws ThingsboardException { return checkEntityId(otaPackageId, otaPackageService::findOtaPackageById, operation); } diff --git a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java index a6a49f6b3c..f31cebd258 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java +++ b/application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java @@ -24,6 +24,7 @@ public class ControllerConstants { protected static final String CUSTOMER_ID = "customerId"; protected static final String TENANT_ID = "tenantId"; protected static final String DEVICE_ID = "deviceId"; + protected static final String PROTOCOL = "protocol"; protected static final String EDGE_ID = "edgeId"; protected static final String RPC_ID = "rpcId"; protected static final String ENTITY_ID = "entityId"; @@ -34,6 +35,7 @@ public class ControllerConstants { protected static final String DASHBOARD_ID_PARAM_DESCRIPTION = "A string value representing the dashboard id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String RPC_ID_PARAM_DESCRIPTION = "A string value representing the rpc id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String DEVICE_ID_PARAM_DESCRIPTION = "A string value representing the device id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; + protected static final String PROTOCOL_PARAM_DESCRIPTION = "A string value representing the device connectivity protocol. Possible values: 'mqtt', 'mqtts', 'http', 'https', 'coap', 'coaps'"; protected static final String ENTITY_VIEW_ID_PARAM_DESCRIPTION = "A string value representing the entity view id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; protected static final String DEVICE_PROFILE_ID_PARAM_DESCRIPTION = "A string value representing the device profile id. For example, '784f394c-42b6-435a-983c-b7beff2784f9'"; diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java new file mode 100644 index 0000000000..bf745a2033 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java @@ -0,0 +1,108 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller; + +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.security.permission.Operation; +import org.thingsboard.server.service.security.system.SystemSecurityService; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Map; + +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID; +import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL; +import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL_PARAM_DESCRIPTION; +import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT_SSL_PEM_FILE_NAME; + +@RestController +@TbCoreComponent +@RequestMapping("/api") +@RequiredArgsConstructor +@Slf4j +public class DeviceConnectivityController extends BaseController { + + private final SystemSecurityService systemSecurityService; + + @ApiOperation(value = "Get commands to publish device telemetry (getDevicePublishTelemetryCommands)", + notes = "Fetch the list of commands to publish device telemetry based on device profile " + + "If the user has the authority of 'Tenant Administrator', the server checks that the device is owned by the same tenant. " + + "If the user has the authority of 'Customer User', the server checks that the device is assigned to the same customer. " + + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK", + examples = @io.swagger.annotations.Example( + value = { + @io.swagger.annotations.ExampleProperty( + mediaType="application/json", + value="{\"http\":\"curl -v -X POST http://localhost:8080/api/v1/0ySs4FTOn5WU15XLmal8/telemetry --header Content-Type:application/json --data {temperature:25}\"," + + "\"mqtt\":\"mosquitto_pub -d -q 1 -h localhost -t v1/devices/me/telemetry -i myClient1 -u myUsername1 -P myPassword -m {temperature:25}\"," + + "\"coap\":\"coap-client -m POST coap://localhost:5683/api/v1/0ySs4FTOn5WU15XLmal8/telemetry -t json -e {temperature:25}\"}")}))}) + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/device-connectivity/{deviceId}", method = RequestMethod.GET) + @ResponseBody + public JsonNode getDevicePublishTelemetryCommands(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) + @PathVariable(DEVICE_ID) String strDeviceId, HttpServletRequest request) throws ThingsboardException, URISyntaxException { + checkParameter(DEVICE_ID, strDeviceId); + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); + Device device = checkDeviceId(deviceId, Operation.READ_CREDENTIALS); + + String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request); + return deviceConnectivityService.findDevicePublishTelemetryCommands(baseUrl, device); + } + + @ApiOperation(value = "Download mqtt ssl certificate using file path defined in device.connectivity properties (downloadMqttServerCertificate)", notes = "Download Mqtt server certificate." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") + @RequestMapping(value = "/device-connectivity/{protocol}/certificate/download", method = RequestMethod.GET) + @ResponseBody + public ResponseEntity downloadMqttServerCertificate(@ApiParam(value = PROTOCOL_PARAM_DESCRIPTION) + @PathVariable(PROTOCOL) String protocol) throws ThingsboardException, IOException { + String certificate = checkSslServerPemFile(protocol); + + ByteArrayResource cert = new ByteArrayResource(certificate.getBytes()); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + MQTT_SSL_PEM_FILE_NAME) + .header("x-filename", MQTT_SSL_PEM_FILE_NAME) + .contentLength(cert.contentLength()) + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(cert); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index e080574d36..07adb1ef1c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -21,11 +21,8 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -79,12 +76,9 @@ import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.system.SystemSecurityService; import javax.annotation.Nullable; -import javax.servlet.http.HttpServletRequest; -import java.net.URISyntaxException; import javax.validation.Valid; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @@ -173,33 +167,6 @@ public class DeviceController extends BaseController { return checkDeviceInfoId(deviceId, Operation.READ); } - @ApiOperation(value = "Get commands to publish device telemetry (getDevicePublishTelemetryCommands)", - notes = "Fetch the list of commands to publish device telemetry based on device profile " + - "If the user has the authority of 'Tenant Administrator', the server checks that the device is owned by the same tenant. " + - "If the user has the authority of 'Customer User', the server checks that the device is assigned to the same customer. " + - TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH) - @ApiResponses(value = { - @ApiResponse(code = 200, message = "OK", - examples = @io.swagger.annotations.Example( - value = { - @io.swagger.annotations.ExampleProperty( - mediaType="application/json", - value="{\"http\":\"curl -v -X POST http://localhost:8080/api/v1/0ySs4FTOn5WU15XLmal8/telemetry --header Content-Type:application/json --data {temperature:25}\"," + - "\"mqtt\":\"mosquitto_pub -d -q 1 -h localhost -t v1/devices/me/telemetry -i myClient1 -u myUsername1 -P myPassword -m {temperature:25}\"," + - "\"coap\":\"coap-client -m POST coap://localhost:5683/api/v1/0ySs4FTOn5WU15XLmal8/telemetry -t json -e {temperature:25}\"}")}))}) - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/device/{deviceId}/commands", method = RequestMethod.GET) - @ResponseBody - public Map getDevicePublishTelemetryCommands(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION) - @PathVariable(DEVICE_ID) String strDeviceId, HttpServletRequest request) throws ThingsboardException, URISyntaxException { - checkParameter(DEVICE_ID, strDeviceId); - DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); - Device device = checkDeviceId(deviceId, Operation.READ_CREDENTIALS); - - String baseUrl = systemSecurityService.getBaseUrl(getTenantId(), getCurrentUser().getCustomerId(), request); - return deviceService.findDevicePublishTelemetryCommands(baseUrl, device); - } - @ApiOperation(value = "Create Or Update Device (saveDevice)", notes = "Create or update the Device. When creating device, platform generates Device Id as " + UUID_WIKI_LINK + "Device credentials are also generated if not provided in the 'accessToken' request parameter. " + diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 6eb0a3948c..5886e74ce4 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1004,7 +1004,7 @@ device: enabled: "${DEVICE_CONNECTIVITY_MQTTS_ENABLED:false}" host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:}" port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" - tb_server_chain_path: "${DEVICE_CONNECTIVITY_MQTTS_SERVER_CHAIN_PATH:}" + ssl_server_pem_path: "${DEVICE_CONNECTIVITY_MQTTS_SERVER_CHAIN_PATH:}" coap: enabled: "${DEVICE_CONNECTIVITY_COAP_ENABLED:true}" host: "${DEVICE_CONNECTIVITY_COAP_HOST:}" diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java new file mode 100644 index 0000000000..8e27857878 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -0,0 +1,398 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.controller; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.mockito.AdditionalAnswers; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.DeviceInfo; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.DeviceProfileType; +import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.EntitySubtype; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.OtaPackageInfo; +import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; +import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; +import org.thingsboard.server.common.data.device.profile.DeviceProfileData; +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DeviceCredentialsId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType; +import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest; +import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult; +import org.thingsboard.server.dao.device.DeviceDao; +import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; +import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.service.gateway_device.GatewayNotificationsService; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; +import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAP; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.LINUX; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.WINDOWS; + +@TestPropertySource(properties = { + "device.connectivity.https.enabled=true", + "device.connectivity.mqtts.enabled=true", + "device.connectivity.coaps.enabled=true", +}) +@ContextConfiguration(classes = {DeviceConnectivityControllerTest.Config.class}) +@DaoSqlTest +public class DeviceConnectivityControllerTest extends AbstractControllerTest { + static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() { + }; + + private static final String DEVICE_TELEMETRY_TOPIC = "v1/devices/customTopic"; + private static final String CHECK_DOCUMENTATION = "Check documentation"; + + ListeningExecutorService executor; + + private Tenant savedTenant; + private User tenantAdmin; + private DeviceProfileId mqttDeviceProfileId; + private DeviceProfileId coapDeviceProfileId; + + static class Config { + @Bean + @Primary + public DeviceDao deviceDao(DeviceDao deviceDao) { + return Mockito.mock(DeviceDao.class, AdditionalAnswers.delegatesTo(deviceDao)); + } + } + + @Before + public void beforeTest() throws Exception { + executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass())); + + loginSysAdmin(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); + Assert.assertNotNull(savedTenant); + + tenantAdmin = new User(); + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setEmail("tenant2@thingsboard.org"); + tenantAdmin.setFirstName("Joe"); + tenantAdmin.setLastName("Downs"); + + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + + DeviceProfile mqttProfile = new DeviceProfile(); + mqttProfile.setName("Mqtt device profile"); + mqttProfile.setType(DeviceProfileType.DEFAULT); + mqttProfile.setTransportType(DeviceTransportType.MQTT); + DeviceProfileData deviceProfileData = new DeviceProfileData(); + deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration()); + MqttDeviceProfileTransportConfiguration transportConfiguration = new MqttDeviceProfileTransportConfiguration(); + transportConfiguration.setDeviceTelemetryTopic(DEVICE_TELEMETRY_TOPIC); + deviceProfileData.setTransportConfiguration(transportConfiguration); + mqttProfile.setProfileData(deviceProfileData); + mqttProfile.setDefault(false); + mqttProfile.setDefaultRuleChainId(null); + + mqttDeviceProfileId = doPost("/api/deviceProfile", mqttProfile, DeviceProfile.class).getId(); + + DeviceProfile coapProfile = new DeviceProfile(); + coapProfile.setName("Coap device profile"); + coapProfile.setType(DeviceProfileType.DEFAULT); + coapProfile.setTransportType(DeviceTransportType.COAP); + DeviceProfileData deviceProfileData2 = new DeviceProfileData(); + deviceProfileData2.setConfiguration(new DefaultDeviceProfileConfiguration()); + deviceProfileData2.setTransportConfiguration(new CoapDeviceProfileTransportConfiguration()); + coapProfile.setProfileData(deviceProfileData); + coapProfile.setDefault(false); + coapProfile.setDefaultRuleChainId(null); + + coapDeviceProfileId = doPost("/api/deviceProfile", coapProfile, DeviceProfile.class).getId(); + } + + @After + public void afterTest() throws Exception { + executor.shutdownNow(); + + loginSysAdmin(); + + doDelete("/api/tenant/" + savedTenant.getId().getId()) + .andExpect(status().isOk()); + } + + @Test + public void testFetchPublishTelemetryCommandsForDefaultDevice() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setType("default"); + Device savedDevice = doPost("/api/device", device, Device.class); + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); + + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + + assertThat(commands).hasSize(3); + JsonNode httpCommands = commands.get(HTTP); + assertThat(httpCommands.get(HTTP).asText()).isEqualTo(String.format("curl -v -X POST http://localhost:8080/api/v1/%s/telemetry " + + "--header Content-Type:application/json --data \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(httpCommands.get(HTTPS).asText()).isEqualTo(String.format("curl -v -X POST https://localhost:443/api/v1/%s/telemetry " + + "--header Content-Type:application/json --data \"{temperature:25}\"", + credentials.getCredentialsId())); + + + JsonNode linuxMqttCommands = commands.get(MQTT).get(LINUX); + assertThat(linuxMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + + "-u %s -m \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(linuxMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile pathToFile/tb-server-chain.pem -h localhost -p 8883 " + + "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", + credentials.getCredentialsId())); + + JsonNode windowsMqttCommands = commands.get(MQTT).get(WINDOWS); + assertThat(windowsMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + + "-u %s -m \"{temperature:25}\"", + credentials.getCredentialsId())); + + + JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); + assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + + " -p 1883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --volume pathToFile/tb-server-chain.pem:/tmp/tb-server-chain.pem " + + "-it --rm thingsboard/mosquitto-clients pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", + credentials.getCredentialsId())); + + JsonNode linuxCoapCommands = commands.get(COAP).get(LINUX); + assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry " + + "-t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry" + + " -t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); + } + + @Test + public void testFetchPublishTelemetryCommandsForMqttDeviceWithAccessToken() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(mqttDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId() , new TypeReference<>() {}); + assertThat(commands).hasSize(1); + + JsonNode linuxMqttCommands = commands.get(MQTT).get(LINUX); + assertThat(linuxMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + + "-u %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + assertThat(linuxMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile pathToFile/tb-server-chain.pem -h localhost -p 8883 " + + "-t %s -u %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + + JsonNode windowsMqttCommands = commands.get(MQTT).get(WINDOWS); + assertThat(windowsMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + + "-u %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + + + JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); + assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + + " -p 1883 -t %s -u %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --volume pathToFile/tb-server-chain.pem:/tmp/tb-server-chain.pem " + + "-it --rm thingsboard/mosquitto-clients pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + } + + @Test + public void testFetchPublishTelemetryCommandsForDeviceWithMqttBasicCreds() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(mqttDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + credentials.setCredentialsId(null); + credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC); + BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials(); + String clientId = "testClientId"; + String userName = "testUsername"; + String password = "testPassword"; + basicMqttCredentials.setClientId(clientId); + basicMqttCredentials.setUserName(userName); + basicMqttCredentials.setPassword(password); + credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials)); + doPost("/api/device/credentials", credentials) + .andExpect(status().isOk()); + + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId() , new TypeReference<>() {}); + assertThat(commands).hasSize(1); + + JsonNode linuxMqttCommands = commands.get(MQTT).get(LINUX); + assertThat(linuxMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + + "-i %s -u %s -P %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + assertThat(linuxMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile pathToFile/tb-server-chain.pem -h localhost -p 8883 " + + "-t %s -i %s -u %s -P %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + + JsonNode windowsMqttCommands = commands.get(MQTT).get(WINDOWS); + assertThat(windowsMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + + "-i %s -u %s -P %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + + + JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); + assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + + " -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --volume pathToFile/tb-server-chain.pem:/tmp/tb-server-chain.pem " + + "-it --rm thingsboard/mosquitto-clients pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", + DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + } + + @Test + public void testFetchPublishTelemetryCommandsForDeviceWithX509Creds() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(mqttDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + credentials.setCredentialsId(null); + credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); + credentials.setCredentialsValue("testValue"); + doPost("/api/device/credentials", credentials) + .andExpect(status().isOk()); + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); + assertThat(commands).hasSize(1); + assertThat(commands.get(MQTT).get(LINUX).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); + assertThat(commands.get(MQTT).get(WINDOWS).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); + assertThat(commands.get(MQTT).get(DOCKER).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); + } + + @Test + public void testFetchPublishTelemetryCommandsForСoapDevice() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(coapDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); + assertThat(commands).hasSize(1); + + JsonNode linuxCommands = commands.get(COAP).get(LINUX); + assertThat(linuxCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); + assertThat(linuxCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", + credentials.getCredentialsId())); + } + + @Test + public void testFetchPublishTelemetryCommandsForСoapDeviceWithX509Creds() throws Exception { + Device device = new Device(); + device.setName("My device"); + device.setDeviceProfileId(coapDeviceProfileId); + + Device savedDevice = doPost("/api/device", device, Device.class); + DeviceCredentials credentials = + doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); + credentials.setCredentialsId(null); + credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); + credentials.setCredentialsValue("testValue"); + doPost("/api/device/credentials", credentials) + .andExpect(status().isOk()); + + JsonNode commands = + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); + assertThat(commands).hasSize(1); + assertThat(commands.get(COAP).get(LINUX).get(COAPS).asText()).isEqualTo(CHECK_DOCUMENTATION); + } +} diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java index 12fa4377f6..287e383317 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java @@ -93,27 +93,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAP; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; - -@TestPropertySource(properties = { - "device.connectivity.https.enabled=true", - "device.connectivity.mqtts.enabled=true", - "device.connectivity.coaps.enabled=true", -}) + @ContextConfiguration(classes = {DeviceControllerTest.Config.class}) @DaoSqlTest public class DeviceControllerTest extends AbstractControllerTest { static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() { }; - private static final String DEVICE_TELEMETRY_TOPIC = "v1/devices/customTopic"; - private static final String CHECK_DOCUMENTATION = "Check documentation"; - ListeningExecutorService executor; List> futures; @@ -121,8 +107,6 @@ public class DeviceControllerTest extends AbstractControllerTest { private Tenant savedTenant; private User tenantAdmin; - private DeviceProfileId mqttDeviceProfileId; - private DeviceProfileId coapDeviceProfileId; @SpyBean private GatewayNotificationsService gatewayNotificationsService; @@ -157,34 +141,6 @@ public class DeviceControllerTest extends AbstractControllerTest { tenantAdmin.setLastName("Downs"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); - - DeviceProfile mqttProfile = new DeviceProfile(); - mqttProfile.setName("Mqtt device profile"); - mqttProfile.setType(DeviceProfileType.DEFAULT); - mqttProfile.setTransportType(DeviceTransportType.MQTT); - DeviceProfileData deviceProfileData = new DeviceProfileData(); - deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration()); - MqttDeviceProfileTransportConfiguration transportConfiguration = new MqttDeviceProfileTransportConfiguration(); - transportConfiguration.setDeviceTelemetryTopic(DEVICE_TELEMETRY_TOPIC); - deviceProfileData.setTransportConfiguration(transportConfiguration); - mqttProfile.setProfileData(deviceProfileData); - mqttProfile.setDefault(false); - mqttProfile.setDefaultRuleChainId(null); - - mqttDeviceProfileId = doPost("/api/deviceProfile", mqttProfile, DeviceProfile.class).getId(); - - DeviceProfile coapProfile = new DeviceProfile(); - coapProfile.setName("Coap device profile"); - coapProfile.setType(DeviceProfileType.DEFAULT); - coapProfile.setTransportType(DeviceTransportType.COAP); - DeviceProfileData deviceProfileData2 = new DeviceProfileData(); - deviceProfileData2.setConfiguration(new DefaultDeviceProfileConfiguration()); - deviceProfileData2.setTransportConfiguration(new CoapDeviceProfileTransportConfiguration()); - coapProfile.setProfileData(deviceProfileData); - coapProfile.setDefault(false); - coapProfile.setDefaultRuleChainId(null); - - coapDeviceProfileId = doPost("/api/deviceProfile", coapProfile, DeviceProfile.class).getId(); } @After @@ -743,144 +699,6 @@ public class DeviceControllerTest extends AbstractControllerTest { Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); } - @Test - public void testFetchPublishTelemetryCommandsForDefaultDevice() throws Exception { - Device device = new Device(); - device.setName("My device"); - device.setType("default"); - Device savedDevice = doPost("/api/device", device, Device.class); - Map commands = - doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); - - DeviceCredentials credentials = - doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); - - assertThat(commands).hasSize(6); - assertThat(commands.get(HTTP)).isEqualTo(String.format("curl -v -X POST http://localhost:8080/api/v1/%s/telemetry --header Content-Type:application/json --data \"{temperature:25}\"", - credentials.getCredentialsId())); - assertThat(commands.get(HTTPS)).isEqualTo(String.format("curl -v -X POST https://localhost:443/api/v1/%s/telemetry --header Content-Type:application/json --data \"{temperature:25}\"", - credentials.getCredentialsId())); - assertThat(commands.get(MQTT)).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", - credentials.getCredentialsId())); - assertThat(commands.get(MQTTS)).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", - credentials.getCredentialsId())); - assertThat(commands.get(COAP)).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", - credentials.getCredentialsId())); - assertThat(commands.get(COAPS)).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", - credentials.getCredentialsId())); - } - - @Test - public void testFetchPublishTelemetryCommandsForMqttDeviceWithAccessToken() throws Exception { - Device device = new Device(); - device.setName("My device"); - device.setDeviceProfileId(mqttDeviceProfileId); - - Device savedDevice = doPost("/api/device", device, Device.class); - DeviceCredentials credentials = - doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); - - Map commands = - doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); - assertThat(commands).hasSize(2); - assertThat(commands.get(MQTT)).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s -u %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - assertThat(commands.get(MQTTS)).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - } - - @Test - public void testFetchPublishTelemetryCommandsForDeviceWithMqttBasicCreds() throws Exception { - Device device = new Device(); - device.setName("My device"); - device.setDeviceProfileId(mqttDeviceProfileId); - - Device savedDevice = doPost("/api/device", device, Device.class); - DeviceCredentials credentials = - doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); - credentials.setCredentialsId(null); - credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC); - BasicMqttCredentials basicMqttCredentials = new BasicMqttCredentials(); - String clientId = "testClientId"; - String userName = "testUsername"; - String password = "testPassword"; - basicMqttCredentials.setClientId(clientId); - basicMqttCredentials.setUserName(userName); - basicMqttCredentials.setPassword(password); - credentials.setCredentialsValue(JacksonUtil.toString(basicMqttCredentials)); - doPost("/api/device/credentials", credentials) - .andExpect(status().isOk()); - - Map commands = - doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); - assertThat(commands).hasSize(2); - assertThat(commands.get(MQTT)).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - assertThat(commands.get(MQTTS)).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - } - - @Test - public void testFetchPublishTelemetryCommandsForDeviceWithX509Creds() throws Exception { - Device device = new Device(); - device.setName("My device"); - device.setDeviceProfileId(mqttDeviceProfileId); - - Device savedDevice = doPost("/api/device", device, Device.class); - DeviceCredentials credentials = - doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); - credentials.setCredentialsId(null); - credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); - credentials.setCredentialsValue("testValue"); - doPost("/api/device/credentials", credentials) - .andExpect(status().isOk()); - - Map commands = - doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); - assertThat(commands).hasSize(1); - assertThat(commands.get(MQTTS)).isEqualTo(CHECK_DOCUMENTATION); - } - - @Test - public void testFetchPublishTelemetryCommandsForСoapDevice() throws Exception { - Device device = new Device(); - device.setName("My device"); - device.setDeviceProfileId(coapDeviceProfileId); - - Device savedDevice = doPost("/api/device", device, Device.class); - DeviceCredentials credentials = - doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); - - Map commands = - doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); - assertThat(commands).hasSize(2); - assertThat(commands.get(COAP)).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", - credentials.getCredentialsId())); - assertThat(commands.get(COAPS)).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", - credentials.getCredentialsId())); - } - - @Test - public void testFetchPublishTelemetryCommandsForСoapDeviceWithX509Creds() throws Exception { - Device device = new Device(); - device.setName("My device"); - device.setDeviceProfileId(coapDeviceProfileId); - - Device savedDevice = doPost("/api/device", device, Device.class); - DeviceCredentials credentials = - doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); - credentials.setCredentialsId(null); - credentials.setCredentialsType(DeviceCredentialsType.X509_CERTIFICATE); - credentials.setCredentialsValue("testValue"); - doPost("/api/device/credentials", credentials) - .andExpect(status().isOk()); - - Map commands = - doGetTyped("/api/device/" + savedDevice.getId().getId() + "/commands", new TypeReference<>() {}); - assertThat(commands).hasSize(1); - assertThat(commands.get(COAPS)).isEqualTo(CHECK_DOCUMENTATION); - } - @Test public void testSaveDeviceCredentials() throws Exception { Device device = new Device(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/TbDeviceConnectivitySslCertService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java similarity index 62% rename from dao/src/main/java/org/thingsboard/server/dao/device/TbDeviceConnectivitySslCertService.java rename to common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java index 43b7f39d30..83f35d5566 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/TbDeviceConnectivitySslCertService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java @@ -15,7 +15,16 @@ */ package org.thingsboard.server.dao.device; +import com.fasterxml.jackson.databind.JsonNode; +import org.thingsboard.server.common.data.Device; -public interface TbDeviceConnectivitySslCertService { - String getMqttSslCertificate(); +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Map; + +public interface DeviceConnectivityService { + + JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException; + + String getSslServerChain(String protocol) throws IOException; } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index a029f27309..510250d264 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.device; -import com.fasterxml.jackson.databind.JsonNode; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceIdInfo; @@ -46,8 +45,6 @@ public interface DeviceService extends EntityDaoService { DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId); - Map findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException; - Device findDeviceById(TenantId tenantId, DeviceId deviceId); ListenableFuture findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java index 5b169a6e79..fa5c61328b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java @@ -22,5 +22,5 @@ public class DeviceConnectivityInfo { private Boolean enabled; private String host; private String port; - private String sslCertPath; + private String sslServerPemPath; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java deleted file mode 100644 index e5851b43c4..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityMqttSslCertService.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright © 2016-2023 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.dao.device; - -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FileUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.ResourceUtils; - -import javax.annotation.PostConstruct; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; - -@Service -@Slf4j -public class DeviceConnectivityMqttSslCertService implements TbDeviceConnectivitySslCertService { - - private String certificate; - @Autowired - private DeviceConnectivityConfiguration deviceConnectivityConfiguration; - - @PostConstruct - private void postConstruct() throws IOException { - String sslCertPath = deviceConnectivityConfiguration.getConnectivity() - .get(MQTTS) - .getSslCertPath(); - if (sslCertPath != null && ResourceUtils.resourceExists(this, sslCertPath)) { - certificate = FileUtils.readFileToString(new File(sslCertPath), StandardCharsets.UTF_8); - } - } - - @Override - public String getMqttSslCertificate() { - return certificate; - } -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index f34c1fa99d..5a6caefd58 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -38,7 +38,6 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfiguration; @@ -48,7 +47,6 @@ import org.thingsboard.server.common.data.device.data.DeviceData; import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration; import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration; import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; @@ -76,13 +74,9 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; -import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Comparator; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -91,18 +85,6 @@ import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateIds; import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validateString; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAP; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.JSON_EXAMPLE_PAYLOAD; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CHECK_DOCUMENTATION; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.SERVER_CHAIN_PEM; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getCoapClientCommand; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getCurlCommand; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getMosquittoPublishCommand; @Service("DeviceDaoService") @Slf4j @@ -134,12 +116,6 @@ public class DeviceServiceImpl extends AbstractCachedEntityService findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException { - DeviceId deviceId = device.getId(); - log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId); - validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); - - String defaultHostname = new URI(baseUrl).getHost(); - DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); - DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); - DeviceTransportType transportType = deviceProfile.getTransportType(); - - Map commands = new HashMap<>(); - switch (transportType) { - case DEFAULT: - Optional.ofNullable(getHttpPublishCommand(HTTP, defaultHostname, creds)).ifPresent(v -> commands.put(HTTP, v)); - Optional.ofNullable(getHttpPublishCommand(HTTPS, defaultHostname, creds)).ifPresent(v -> commands.put(HTTPS, v)); - Optional.ofNullable(getMqttPublishCommand(MQTT, defaultHostname, creds)).ifPresent(v -> commands.put(MQTT, v)); - Optional.ofNullable(getMqttPublishCommand(MQTTS, defaultHostname, creds)).ifPresent(v -> commands.put(MQTTS, v)); - Optional.ofNullable(getCoapPublishCommand(COAP, defaultHostname, creds)).ifPresent(v -> commands.put(COAP, v)); - Optional.ofNullable(getCoapPublishCommand(COAPS, defaultHostname, creds)).ifPresent(v -> commands.put(COAPS, v)); - break; - case MQTT: - MqttDeviceProfileTransportConfiguration transportConfiguration = - (MqttDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); - String topicName = transportConfiguration.getDeviceTelemetryTopic(); - TransportPayloadType payloadType = transportConfiguration.getTransportPayloadTypeConfiguration().getTransportPayloadType(); - String payload = (payloadType == TransportPayloadType.PROTOBUF) ? " -f protobufFileName" : " -m " + JSON_EXAMPLE_PAYLOAD; - - Optional.ofNullable(getMqttPublishCommand(MQTT, defaultHostname, topicName, creds, payload)).ifPresent(v -> commands.put(MQTT, v)); - Optional.ofNullable(getMqttPublishCommand(MQTTS, defaultHostname, topicName, creds, payload)).ifPresent(v -> commands.put(MQTTS, v)); - break; - case COAP: - Optional.ofNullable(getCoapPublishCommand(COAP, defaultHostname, creds)).ifPresent(v -> commands.put(COAP, v)); - Optional.ofNullable(getCoapPublishCommand(COAPS, defaultHostname, creds)).ifPresent(v -> commands.put(COAPS, v)); - break; - default: - commands.put(transportType.name(), CHECK_DOCUMENTATION); - } - - if (commands.containsKey(MQTTS) && deviceConnectivityMqttSslCertService.getMqttSslCertificate() != null) { - commands.put(SERVER_CHAIN_PEM, deviceConnectivityMqttSslCertService.getMqttSslCertificate()); - } - return commands; - } - @Override public Device findDeviceById(TenantId tenantId, DeviceId deviceId) { log.trace("Executing findDeviceById [{}]", deviceId); @@ -747,44 +678,4 @@ public class DeviceServiceImpl extends AbstractCachedEntityService linuxMqttCommands.put(MQTT, v)); + Optional.ofNullable(getMqttPublishCommand(LINUX, MQTTS, defaultHostname, topic, deviceCredentials)) + .ifPresent(v -> linuxMqttCommands.put(MQTTS, v)); + + ObjectNode windowsMqttCommands = JacksonUtil.newObjectNode(); + Optional.ofNullable(getMqttPublishCommand(WINDOWS, MQTT, defaultHostname, topic, deviceCredentials)) + .ifPresent(v -> windowsMqttCommands.put(MQTT, v)); + Optional.ofNullable(getMqttPublishCommand(WINDOWS, MQTTS, defaultHostname, topic, deviceCredentials)) + .ifPresent(v -> windowsMqttCommands.put(MQTTS, v)); + + ObjectNode dockerMqttCommands = JacksonUtil.newObjectNode(); + Optional.ofNullable(getMqttPublishCommand(DOCKER, MQTT, defaultHostname, topic, deviceCredentials)) + .ifPresent(v -> dockerMqttCommands.put(MQTT, v)); + Optional.ofNullable(getMqttPublishCommand(DOCKER, MQTTS, defaultHostname, topic, deviceCredentials)) + .ifPresent(v -> dockerMqttCommands.put(MQTTS, v)); + + mqttCommands.set(LINUX, linuxMqttCommands); + mqttCommands.set(WINDOWS, windowsMqttCommands); + mqttCommands.set(DOCKER, dockerMqttCommands); + + return mqttCommands; + } + + private String getMqttPublishCommand(String os, String protocol, String defaultHostname, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { + if (MQTTS.equals(protocol) && deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { + return CHECK_DOCUMENTATION; + } + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + if (properties == null || !properties.getEnabled()) { + return null; + } + String mqttHost = properties.getHost().isEmpty() ? defaultHostname : properties.getHost(); + String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); + switch (os) { + case LINUX: + return getMosquittoPubPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + case WINDOWS: + return getMosquittoPubPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + case DOCKER: + return getDockerMosquittoClientsPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + default: + throw new IllegalArgumentException("Unsupported operating system: " + os); + } + } + + private JsonNode getCoapTransportPublishCommands(String defaultHostname, DeviceCredentials deviceCredentials) { + ObjectNode coapCommands = JacksonUtil.newObjectNode(); + + ObjectNode linuxCoapCommands = JacksonUtil.newObjectNode(); + Optional.ofNullable(getCoapPublishCommand(LINUX, COAP, defaultHostname, deviceCredentials)) + .ifPresent(v -> linuxCoapCommands.put(COAP, v)); + Optional.ofNullable(getCoapPublishCommand(LINUX, COAPS, defaultHostname, deviceCredentials)) + .ifPresent(v -> linuxCoapCommands.put(COAPS, v)); + + coapCommands.set(LINUX, linuxCoapCommands); + return coapCommands; + } + + private String getCoapPublishCommand(String os, String protocol, String defaultHostname, DeviceCredentials deviceCredentials) { + if (COAPS.equals(protocol) && deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { + return CHECK_DOCUMENTATION; + } + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + if (properties == null || !properties.getEnabled()) { + return null; + } + String hostName = properties.getHost().isEmpty() ? defaultHostname : properties.getHost(); + String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); + + switch (os) { + case LINUX: + return getCoapClientCommand(protocol, hostName, port, deviceCredentials); + default: + throw new IllegalArgumentException("Unsupported operating system: " + os); + } + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java index 3257ea13d6..72eac8bdea 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java @@ -24,10 +24,13 @@ public class DeviceConnectivityUtil { public static final String HTTP = "http"; public static final String HTTPS = "https"; public static final String MQTT = "mqtt"; + public static final String LINUX = "linux"; + public static final String WINDOWS = "windows"; + public static final String DOCKER = "docker"; public static final String MQTTS = "mqtts"; public static final String COAP = "coap"; public static final String COAPS = "coaps"; - public static final String SERVER_CHAIN_PEM = "serverChainPem"; + public static final String MQTT_SSL_PEM_FILE_NAME = "tb-server-chain.pem"; public static final String CHECK_DOCUMENTATION = "Check documentation"; public static final String JSON_EXAMPLE_PAYLOAD = "\"{temperature:25}\""; @@ -36,10 +39,10 @@ public class DeviceConnectivityUtil { protocol, host, port, deviceCredentials.getCredentialsId()); } - public static String getMosquittoPublishCommand(String protocol, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials, String payload) { + public static String getMosquittoPubPublishCommand(String protocol, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { StringBuilder command = new StringBuilder("mosquitto_pub -d -q 1"); if (MQTTS.equals(protocol)) { - command.append(" --cafile tb-server-chain.pem"); + command.append(" --cafile pathToFile/" + MQTT_SSL_PEM_FILE_NAME); } command.append(" -h ").append(host).append(port == null ? "" : " -p " + port); command.append(" -t ").append(deviceTelemetryTopic); @@ -68,7 +71,47 @@ public class DeviceConnectivityUtil { default: return null; } - command.append(payload); + command.append(" -m " + JSON_EXAMPLE_PAYLOAD); + return command.toString(); + } + + public static String getDockerMosquittoClientsPublishCommand(String protocol, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { + StringBuilder command = new StringBuilder("docker run"); + if (MQTTS.equals(protocol)) { + command.append(" --volume pathToFile/" + MQTT_SSL_PEM_FILE_NAME + ":/tmp/" + MQTT_SSL_PEM_FILE_NAME); + } + command.append(" -it --rm thingsboard/mosquitto-clients pub"); + if (MQTTS.equals(protocol)) { + command.append(" --cafile tmp/" + MQTT_SSL_PEM_FILE_NAME); + } + command.append(" -h ").append(host).append(port == null ? "" : " -p " + port); + command.append(" -t ").append(deviceTelemetryTopic); + + switch (deviceCredentials.getCredentialsType()) { + case ACCESS_TOKEN: + command.append(" -u ").append(deviceCredentials.getCredentialsId()); + break; + case MQTT_BASIC: + BasicMqttCredentials credentials = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), + BasicMqttCredentials.class); + if (credentials != null) { + if (credentials.getClientId() != null) { + command.append(" -i ").append(credentials.getClientId()); + } + if (credentials.getUserName() != null) { + command.append(" -u ").append(credentials.getUserName()); + } + if (credentials.getPassword() != null) { + command.append(" -P ").append(credentials.getPassword()); + } + } else { + return null; + } + break; + default: + return null; + } + command.append(" -m " + JSON_EXAMPLE_PAYLOAD); return command.toString(); } From 753258c1ba52aeba89d2ce5357c53a9c9a2fbcf6 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Thu, 20 Jul 2023 13:03:24 +0300 Subject: [PATCH 290/421] AlarmsTableWidgetComponent, TimeseriesTableWidgetComponent - show pointer cursor if widget has rowClick action --- .../components/widget/lib/alarms-table-widget.component.html | 3 ++- .../components/widget/lib/alarms-table-widget.component.ts | 2 ++ .../widget/lib/timeseries-table-widget.component.html | 3 ++- .../components/widget/lib/timeseries-table-widget.component.ts | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html index 9a23e86bf8..1c03a37bbd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html @@ -160,7 +160,8 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index db2d04ea88..5612499c64 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -180,6 +180,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, public displayedColumns: string[] = []; public alarmsDatasource: AlarmsDatasource; public noDataDisplayMessageText: string; + public hasRowAction: boolean; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -493,6 +494,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, } this.setCellButtonAction = !!(actionCellDescriptors.length + this.ctx.actionsApi.getActionDescriptors('actionCellButton').length); + this.hasRowAction = !!this.ctx.actionsApi.getActionDescriptors('rowClick').length; if (this.setCellButtonAction) { this.displayedColumns.push('actions'); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html index d0ca2f23d1..65c4fbe0ee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.html @@ -99,7 +99,8 @@ - diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts index 78f6203b1b..e6c3bc7e24 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/timeseries-table-widget.component.ts @@ -161,6 +161,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI public sources: TimeseriesTableSource[]; public sourceIndex: number; public noDataDisplayMessageText: string; + public hasRowAction: boolean; private setCellButtonAction: boolean; private cellContentCache: Array = []; @@ -300,6 +301,7 @@ export class TimeseriesTableWidgetComponent extends PageComponent implements OnI this.ctx.widgetActions = [this.searchAction, this.columnDisplayAction]; this.setCellButtonAction = !!this.ctx.actionsApi.getActionDescriptors('actionCellButton').length; + this.hasRowAction = !!this.ctx.actionsApi.getActionDescriptors('rowClick').length; this.searchAction.show = isDefined(this.settings.enableSearch) ? this.settings.enableSearch : true; this.columnDisplayAction.show = isDefined(this.settings.enableSelectColumnDisplay) ? this.settings.enableSelectColumnDisplay : true; From 9c9cac9bd1969499cac16c3f08227e6d7ce2b5c6 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 20 Jul 2023 13:54:31 +0300 Subject: [PATCH 291/421] fix entity view delete test --- .../server/controller/EntityViewControllerTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java index a65769f3f1..cb41019f6f 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java @@ -43,6 +43,7 @@ import org.springframework.test.web.servlet.ResultActions; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityViewInfo; import org.thingsboard.server.common.data.StringUtils; @@ -253,7 +254,7 @@ public class EntityViewControllerTest extends AbstractControllerTest { doGet("/api/entityView/" + entityIdStr) .andExpect(status().isNotFound()) - .andExpect(statusReason(containsString(msgErrorNoFound("Entity view",entityIdStr)))); + .andExpect(statusReason(containsString(msgErrorNoFound(EntityType.ENTITY_VIEW.getNormalName(), entityIdStr)))); } @Test @@ -425,12 +426,12 @@ public class EntityViewControllerTest extends AbstractControllerTest { testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(), tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.ADDED, ActionType.ADDED, cntEntity, 0, cntEntity*2, 0); + ActionType.ADDED, ActionType.ADDED, cntEntity, 0, cntEntity * 2, 0); testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ASSIGNED_TO_CUSTOMER, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, - cntEntity*2, 3); + cntEntity * 2, 3); } @Test From c913b08b53b863e5c7d249ebfc5cf61ece5880e8 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 20 Jul 2023 15:13:11 +0300 Subject: [PATCH 292/421] UI: Fixed entity select component --- .../components/entity/entity-select.component.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts index ccc4a0a079..9427c2ff73 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts @@ -125,16 +125,23 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte if (value.id === NULL_UUID) { value.id = null; } + if (value.entityType === AliasEntityType.CURRENT_TENANT + || value.entityType === AliasEntityType.CURRENT_USER + || value.entityType === AliasEntityType.CURRENT_USER_OWNER) { + value.id = NULL_UUID; + } else if (value.entityType === AliasEntityType.CURRENT_CUSTOMER && !value.id) { + this.modelValue.id = NULL_UUID; + } this.modelValue = value; - this.entitySelectFormGroup.get('entityType').patchValue(value.entityType, {emitEvent: true}); - this.entitySelectFormGroup.get('entityId').patchValue(value, {emitEvent: true}); + this.entitySelectFormGroup.get('entityType').patchValue(value.entityType, {emitEvent: false}); + this.entitySelectFormGroup.get('entityId').patchValue(value, {emitEvent: false}); } else { this.modelValue = { entityType: this.defaultEntityType, id: null }; - this.entitySelectFormGroup.get('entityType').patchValue(this.defaultEntityType, {emitEvent: true}); - this.entitySelectFormGroup.get('entityId').patchValue(null, {emitEvent: true}); + this.entitySelectFormGroup.get('entityType').patchValue(this.defaultEntityType, {emitEvent: false}); + this.entitySelectFormGroup.get('entityId').patchValue(null, {emitEvent: false}); } } From e3ef58c6038dd2e9e949ffaeb18a7d8991611f69 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 20 Jul 2023 15:33:02 +0300 Subject: [PATCH 293/421] added notnull check for http commands --- .../server/dao/device/DeviceСonnectivityServiceImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java index 7ae49276b8..e062441559 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java @@ -119,8 +119,10 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService private JsonNode getHttpTransportPublishCommands(String defaultHostname, DeviceCredentials deviceCredentials) { ObjectNode httpCommands = JacksonUtil.newObjectNode(); - httpCommands.put(HTTP, getHttpPublishCommand(HTTP, defaultHostname, deviceCredentials)); - httpCommands.put(HTTPS, getHttpPublishCommand(HTTPS, defaultHostname, deviceCredentials)); + Optional.ofNullable(getHttpPublishCommand(HTTP, defaultHostname, deviceCredentials)) + .ifPresent(v -> httpCommands.put(HTTP, v)); + Optional.ofNullable(getHttpPublishCommand(HTTPS, defaultHostname, deviceCredentials)) + .ifPresent(v -> httpCommands.put(HTTPS, v)); return httpCommands; } From 1c601a6e7ded514f791550c389441ef1ff66cb27 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 20 Jul 2023 16:39:44 +0300 Subject: [PATCH 294/421] UI: Change field label assign customer --- .../home/components/wizard/device-wizard-dialog.component.html | 2 +- ui-ngx/src/assets/locale/locale.constant-en_US.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index 8d55b4bc6a..08d71e1229 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -76,7 +76,7 @@
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 c5ec1fca40..5254d7b654 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -937,7 +937,8 @@ "search": "Search customers", "selected-customers": "{ count, plural, =1 {1 customer} other {# customers} } selected", "edges": "Customer edge instances", - "manage-edges": "Manage edges" + "manage-edges": "Manage edges", + "assign-customer": "Assign customer" }, "datetime": { "date-from": "Date from", From fc499c74e3599d49f1349479c02947f80efbeddc Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 20 Jul 2023 17:22:33 +0300 Subject: [PATCH 295/421] deleted redundant imports --- .../server/controller/DeviceController.java | 2 -- .../server/controller/DeviceControllerTest.java | 10 ---------- .../thingsboard/server/dao/device/DeviceService.java | 2 -- .../server/dao/device/DeviceServiceImpl.java | 1 - 4 files changed, 15 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 07adb1ef1c..3eb6202aea 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -73,7 +73,6 @@ import org.thingsboard.server.service.entitiy.device.TbDeviceService; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; -import org.thingsboard.server.service.security.system.SystemSecurityService; import javax.annotation.Nullable; import javax.validation.Valid; @@ -135,7 +134,6 @@ public class DeviceController extends BaseController { private final TbDeviceService tbDeviceService; - private final SystemSecurityService systemSecurityService; @ApiOperation(value = "Get Device (getDeviceById)", notes = "Fetch the Device object based on the provided Device Id. " + diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java index 287e383317..9ab5f7fde8 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java @@ -34,15 +34,12 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceInfo; import org.thingsboard.server.common.data.DeviceProfile; -import org.thingsboard.server.common.data.DeviceProfileType; -import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.OtaPackageInfo; @@ -52,16 +49,10 @@ import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; -import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; -import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; -import org.thingsboard.server.common.data.device.profile.DeviceProfileData; -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceCredentialsId; import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -93,7 +84,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; - @ContextConfiguration(classes = {DeviceControllerTest.Config.class}) @DaoSqlTest public class DeviceControllerTest extends AbstractControllerTest { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index 510250d264..a90ea9a572 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -36,9 +36,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.dao.device.provision.ProvisionRequest; import org.thingsboard.server.dao.entity.EntityDaoService; -import java.net.URISyntaxException; import java.util.List; -import java.util.Map; import java.util.UUID; public interface DeviceService extends EntityDaoService { diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 5a6caefd58..3f9ee12dda 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -96,7 +96,6 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Thu, 20 Jul 2023 17:36:55 +0300 Subject: [PATCH 296/421] Fix for update JSON attribute widget required time-series data key instead attribute key --- .../src/main/data/json/system/widget_bundles/input_widgets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_bundles/input_widgets.json b/application/src/main/data/json/system/widget_bundles/input_widgets.json index ca2e16e4dd..e8856b5d97 100644 --- a/application/src/main/data/json/system/widget_bundles/input_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/input_widgets.json @@ -498,7 +498,7 @@ "settingsSchema": "", "dataKeySettingsSchema": "{}", "settingsDirective": "tb-update-json-attribute-widget-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"attributeScope\":\"SERVER_SCOPE\",\"showLabel\":true,\"attributeRequired\":true,\"showResultMessage\":true},\"title\":\"Update JSON attribute\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"widgetMode\":\"ATTRIBUTE\",\"attributeScope\":\"SERVER_SCOPE\",\"showLabel\":true,\"attributeRequired\":true,\"showResultMessage\":true},\"title\":\"Update JSON attribute\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" } } ] From 36574f32306f6038a6d3a30c8c436b5b960dcd1a Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 21 Jul 2023 10:32:08 +0300 Subject: [PATCH 297/421] UI: Remove translate --- ui-ngx/src/assets/locale/locale.constant-ca_ES.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-cs_CZ.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-da_DK.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-en_US.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-es_ES.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-fr_FR.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-ko_KR.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-sl_SI.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-tr_TR.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-zh_CN.json | 3 +-- ui-ngx/src/assets/locale/locale.constant-zh_TW.json | 3 +-- 11 files changed, 11 insertions(+), 22 deletions(-) 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 349d13da2c..77edc26187 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -1376,8 +1376,7 @@ "device-configuration": "Configuració del dispositiu", "transport-configuration": "Configuració del transport", "wizard": { - "device-details": "Detalls del dispositiu", - "customer-to-assign-device": "Client al que assignar el dispositiu" + "device-details": "Detalls del dispositiu" }, "unassign-devices-from-edge-title": "Està segur de que desitja desassignar {count, plural, =1 {1 dispositivo} other {# dispositivos} }?", "unassign-devices-from-edge-text": "Després de la confirmació, tots els dispositius seleccionats quedaran sense assignar i la vora no podrà accedir a ells." 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 52873b4d70..d89971cd0c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -1018,8 +1018,7 @@ "device-configuration": "Konfigurace zařízení", "transport-configuration": "Konfigurace přenosu", "wizard": { - "device-details": "Detail zařízení", - "customer-to-assign-device": "Přiřadit zařízení zákazníkovi" + "device-details": "Detail zařízení" }, "unassign-devices-from-edge-title": "Jste se jisti, že chcete odebrat { count, plural, =1 {1 zařízení} other {# zařízení} }?", "unassign-devices-from-edge-text": "Po potvrzení budou všechna vybraná zařízení odebrána a nebudou pro edge dostupná." diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 2c1df70902..4e3b3ca779 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -1095,8 +1095,7 @@ "device-configuration": "Enhedskonfiguration", "transport-configuration": "Transportkonfiguration", "wizard": { - "device-details": "Enhedsoplysninger", - "customer-to-assign-device": "Kunden skal tildele enheden" + "device-details": "Enhedsoplysninger" } }, "device-profile": { 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 5254d7b654..e0c07480cf 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1375,8 +1375,7 @@ "device-configuration": "Device configuration", "transport-configuration": "Transport configuration", "wizard": { - "device-details": "Device details", - "customer-to-assign-device": "Customer to assign the device" + "device-details": "Device details" }, "unassign-devices-from-edge-title": "Are you sure you want to unassign { count, plural, =1 {1 device} other {# devices} }?", "unassign-devices-from-edge-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the edge." 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 6518e03f58..d579de1a1f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -1325,8 +1325,7 @@ "device-configuration": "Configuración del dispositivo", "transport-configuration": "Configuración del transporte", "wizard": { - "device-details": "Detalles del dispositivo", - "customer-to-assign-device": "Cliente al que asignar el dispositivo" + "device-details": "Detalles del dispositivo" }, "unassign-devices-from-edge-title": "¿Está seguro de que desea desasignar {count, plural, =1 {1 dispositivo} other {# dispositivos} }?", "unassign-devices-from-edge-text": "Después de la confirmación, todos los dispositivos seleccionados quedarán sin asignar y el Edge no podrá acceder a ellos." 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 19f92e5a7c..56712eeeb5 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -1053,8 +1053,7 @@ "device-configuration": "Configuration du dipositif", "transport-configuration": "Configuration du transport", "wizard": { - "device-details": "Détails du dispositif", - "customer-to-assign-device": "Client auquel assigner le dispositif" + "device-details": "Détails du dispositif" } }, "device-profile": { diff --git a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json index 758482f578..0fd1ba039d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -913,8 +913,7 @@ "device-configuration": "장치 설정", "transport-configuration": "전송 설정", "wizard": { - "device-details": "장치 상세 정보", - "customer-to-assign-device": "장치에 할당할 커스터머" + "device-details": "장치 상세 정보" } }, "device-profile": { diff --git a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json index 8aced0ddc6..fcc2f6f867 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -913,8 +913,7 @@ "device-configuration": "Device configuration", "transport-configuration": "Transport configuration", "wizard": { - "device-details": "Device details", - "customer-to-assign-device": "Customer to assign the device" + "device-details": "Device details" } }, "device-profile": { 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 b175a2d51a..cd7e31e97f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -1021,8 +1021,7 @@ "device-configuration": "Cihaz yapılandırması", "transport-configuration": "Aktarım yapılandırması", "wizard": { - "device-details": "Cihaz ayrıntıları", - "customer-to-assign-device": "Cihazı atamak için kullanıcı grubu" + "device-details": "Cihaz ayrıntıları" }, "unassign-devices-from-edge-title": "{ count, plural, =1 {1 cihazın} other {# cihazın} } atamasını kaldırmak istediğinizden emin misiniz?", "unassign-devices-from-edge-text": "Onaydan sonra, seçilen tüm cihazların ataması kaldırılacak ve uç tarafından erişilemeyecek." 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 b39e10e46c..2a9645f982 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -1221,8 +1221,7 @@ "device-configuration": "设备配置", "transport-configuration": "传输配置", "wizard": { - "device-details": "设备详细信息", - "customer-to-assign-device": "客户分配设备" + "device-details": "设备详细信息" }, "unassign-devices-from-edge-title": "确定要取消分配 { count, plural, =1 {1 个设备} other {# 个设备} } 吗?", "unassign-devices-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。" 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 f2cce81824..3bc75f062c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -1134,8 +1134,7 @@ "device-configuration": "設備配置", "transport-configuration": "傳輸配置", "wizard": { - "device-details": "設備詳情", - "customer-to-assign-device": "客戶指定設備" + "device-details": "設備詳情" }, "unassign-devices-from-edge-title": "您確定要解除邊緣設備 { count, plural, =1 {1 device} other {# devices} }的指定嗎?", "unassign-devices-from-edge-text": "確認後邊緣指定設備將解除指定及其所有相關資料將無法恢復。" From d99c08fbbbde10a151b19668fc27e9bcfbb39d72 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Fri, 21 Jul 2023 12:52:15 +0300 Subject: [PATCH 298/421] changed response data structure --- .../DeviceConnectivityControllerTest.java | 38 +++------- .../DeviceСonnectivityServiceImpl.java | 75 +++++++++---------- 2 files changed, 45 insertions(+), 68 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index 8e27857878..3b10695e62 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -213,7 +213,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { credentials.getCredentialsId())); - JsonNode linuxMqttCommands = commands.get(MQTT).get(LINUX); + JsonNode linuxMqttCommands = commands.get(MQTT); assertThat(linuxMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + "-u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); @@ -221,11 +221,6 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); - JsonNode windowsMqttCommands = commands.get(MQTT).get(WINDOWS); - assertThat(windowsMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + - "-u %s -m \"{temperature:25}\"", - credentials.getCredentialsId())); - JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + @@ -235,13 +230,11 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { "-it --rm thingsboard/mosquitto-clients pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); - JsonNode linuxCoapCommands = commands.get(COAP).get(LINUX); + JsonNode linuxCoapCommands = commands.get(COAP); assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry " + - "-t json -e \"{temperature:25}\"", - credentials.getCredentialsId())); + "-t json -e \"{temperature:25}\"", credentials.getCredentialsId())); assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry" + - " -t json -e \"{temperature:25}\"", - credentials.getCredentialsId())); + " -t json -e \"{temperature:25}\"", credentials.getCredentialsId())); } @Test @@ -258,7 +251,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId() , new TypeReference<>() {}); assertThat(commands).hasSize(1); - JsonNode linuxMqttCommands = commands.get(MQTT).get(LINUX); + JsonNode linuxMqttCommands = commands.get(MQTT); assertThat(linuxMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + "-u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); @@ -266,11 +259,6 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { "-t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - JsonNode windowsMqttCommands = commands.get(MQTT).get(WINDOWS); - assertThat(windowsMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + - "-u %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + @@ -303,12 +291,11 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { doPost("/api/device/credentials", credentials) .andExpect(status().isOk()); - JsonNode commands = doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId() , new TypeReference<>() {}); assertThat(commands).hasSize(1); - JsonNode linuxMqttCommands = commands.get(MQTT).get(LINUX); + JsonNode linuxMqttCommands = commands.get(MQTT); assertThat(linuxMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + "-i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); @@ -316,12 +303,6 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { "-t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - JsonNode windowsMqttCommands = commands.get(MQTT).get(WINDOWS); - assertThat(windowsMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + - "-i %s -u %s -P %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - - JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + " -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", @@ -349,8 +330,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { JsonNode commands = doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); assertThat(commands).hasSize(1); - assertThat(commands.get(MQTT).get(LINUX).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); - assertThat(commands.get(MQTT).get(WINDOWS).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); + assertThat(commands.get(MQTT).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); assertThat(commands.get(MQTT).get(DOCKER).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); } @@ -368,7 +348,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); assertThat(commands).hasSize(1); - JsonNode linuxCommands = commands.get(COAP).get(LINUX); + JsonNode linuxCommands = commands.get(COAP); assertThat(linuxCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", credentials.getCredentialsId())); assertThat(linuxCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry -t json -e \"{temperature:25}\"", @@ -393,6 +373,6 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { JsonNode commands = doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); assertThat(commands).hasSize(1); - assertThat(commands.get(COAP).get(LINUX).get(COAPS).asText()).isEqualTo(CHECK_DOCUMENTATION); + assertThat(commands.get(COAP).get(COAPS).asText()).isEqualTo(CHECK_DOCUMENTATION); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java index e062441559..694f1cb8ee 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java @@ -85,22 +85,27 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService ObjectNode commands = JacksonUtil.newObjectNode(); switch (transportType) { case DEFAULT: - commands.set(HTTP, getHttpTransportPublishCommands(defaultHostname, creds)); - commands.set(MQTT, getMqttTransportPublishCommands(defaultHostname, creds)); - commands.set(COAP, getCoapTransportPublishCommands(defaultHostname, creds)); + Optional.ofNullable(getHttpTransportPublishCommands(defaultHostname, creds)) + .ifPresent(v -> commands.set(HTTP, v)); + Optional.ofNullable(getMqttTransportPublishCommands(defaultHostname, creds)) + .ifPresent(v -> commands.set(MQTT, v)); + Optional.ofNullable(getCoapTransportPublishCommands(defaultHostname, creds)) + .ifPresent(v -> commands.set(COAP, v)); break; case MQTT: MqttDeviceProfileTransportConfiguration transportConfiguration = (MqttDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); String topicName = transportConfiguration.getDeviceTelemetryTopic(); - commands.set(MQTT, getMqttTransportPublishCommands(defaultHostname, topicName, creds)); + Optional.ofNullable(getMqttTransportPublishCommands(defaultHostname, topicName, creds)) + .ifPresent(v -> commands.set(MQTT, v)); break; case COAP: - commands.set(COAP, getCoapTransportPublishCommands(defaultHostname, creds)); + Optional.ofNullable(getCoapTransportPublishCommands(defaultHostname, creds)) + .ifPresent(v -> commands.set(COAP, v)); break; default: - commands.set(transportType.name(), JacksonUtil.toJsonNode(CHECK_DOCUMENTATION)); + commands.put(transportType.name(), CHECK_DOCUMENTATION); } return commands; } @@ -123,7 +128,7 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService .ifPresent(v -> httpCommands.put(HTTP, v)); Optional.ofNullable(getHttpPublishCommand(HTTPS, defaultHostname, deviceCredentials)) .ifPresent(v -> httpCommands.put(HTTPS, v)); - return httpCommands; + return httpCommands.isEmpty() ? null : httpCommands; } private String getHttpPublishCommand(String protocol, String defaultHostname, DeviceCredentials deviceCredentials) { @@ -145,32 +150,22 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService private JsonNode getMqttTransportPublishCommands(String defaultHostname, String topic, DeviceCredentials deviceCredentials) { ObjectNode mqttCommands = JacksonUtil.newObjectNode(); - ObjectNode linuxMqttCommands = JacksonUtil.newObjectNode(); - Optional.ofNullable(getMqttPublishCommand(LINUX, MQTT, defaultHostname, topic, deviceCredentials)) - .ifPresent(v -> linuxMqttCommands.put(MQTT, v)); - Optional.ofNullable(getMqttPublishCommand(LINUX, MQTTS, defaultHostname, topic, deviceCredentials)) - .ifPresent(v -> linuxMqttCommands.put(MQTTS, v)); - - ObjectNode windowsMqttCommands = JacksonUtil.newObjectNode(); - Optional.ofNullable(getMqttPublishCommand(WINDOWS, MQTT, defaultHostname, topic, deviceCredentials)) - .ifPresent(v -> windowsMqttCommands.put(MQTT, v)); - Optional.ofNullable(getMqttPublishCommand(WINDOWS, MQTTS, defaultHostname, topic, deviceCredentials)) - .ifPresent(v -> windowsMqttCommands.put(MQTTS, v)); + Optional.ofNullable(getMqttPublishCommand(MQTT, defaultHostname, topic, deviceCredentials)) + .ifPresent(v -> mqttCommands.put(MQTT, v)); + Optional.ofNullable(getMqttPublishCommand(MQTTS, defaultHostname, topic, deviceCredentials)) + .ifPresent(v -> mqttCommands.put(MQTTS, v)); ObjectNode dockerMqttCommands = JacksonUtil.newObjectNode(); - Optional.ofNullable(getMqttPublishCommand(DOCKER, MQTT, defaultHostname, topic, deviceCredentials)) + Optional.ofNullable(getDockerMqttPublishCommand(MQTT, defaultHostname, topic, deviceCredentials)) .ifPresent(v -> dockerMqttCommands.put(MQTT, v)); - Optional.ofNullable(getMqttPublishCommand(DOCKER, MQTTS, defaultHostname, topic, deviceCredentials)) + Optional.ofNullable(getDockerMqttPublishCommand(MQTTS, defaultHostname, topic, deviceCredentials)) .ifPresent(v -> dockerMqttCommands.put(MQTTS, v)); - mqttCommands.set(LINUX, linuxMqttCommands); - mqttCommands.set(WINDOWS, windowsMqttCommands); mqttCommands.set(DOCKER, dockerMqttCommands); - - return mqttCommands; + return mqttCommands.isEmpty() ? null : mqttCommands; } - private String getMqttPublishCommand(String os, String protocol, String defaultHostname, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { + private String getMqttPublishCommand(String protocol, String defaultHostname, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { if (MQTTS.equals(protocol) && deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { return CHECK_DOCUMENTATION; } @@ -180,29 +175,31 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService } String mqttHost = properties.getHost().isEmpty() ? defaultHostname : properties.getHost(); String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); - switch (os) { - case LINUX: - return getMosquittoPubPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); - case WINDOWS: - return getMosquittoPubPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); - case DOCKER: - return getDockerMosquittoClientsPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); - default: - throw new IllegalArgumentException("Unsupported operating system: " + os); + return getMosquittoPubPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + } + + private String getDockerMqttPublishCommand(String protocol, String defaultHostname, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { + if (MQTTS.equals(protocol) && deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { + return CHECK_DOCUMENTATION; + } + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + if (properties == null || !properties.getEnabled()) { + return null; } + String mqttHost = properties.getHost().isEmpty() ? defaultHostname : properties.getHost(); + String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); + return getDockerMosquittoClientsPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); } private JsonNode getCoapTransportPublishCommands(String defaultHostname, DeviceCredentials deviceCredentials) { ObjectNode coapCommands = JacksonUtil.newObjectNode(); - ObjectNode linuxCoapCommands = JacksonUtil.newObjectNode(); Optional.ofNullable(getCoapPublishCommand(LINUX, COAP, defaultHostname, deviceCredentials)) - .ifPresent(v -> linuxCoapCommands.put(COAP, v)); + .ifPresent(v -> coapCommands.put(COAP, v)); Optional.ofNullable(getCoapPublishCommand(LINUX, COAPS, defaultHostname, deviceCredentials)) - .ifPresent(v -> linuxCoapCommands.put(COAPS, v)); + .ifPresent(v -> coapCommands.put(COAPS, v)); - coapCommands.set(LINUX, linuxCoapCommands); - return coapCommands; + return coapCommands.isEmpty() ? null : coapCommands; } private String getCoapPublishCommand(String os, String protocol, String defaultHostname, DeviceCredentials deviceCredentials) { From 2ad30336ea214307e9c5dc86d43b64bf17987877 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Fri, 21 Jul 2023 13:51:49 +0300 Subject: [PATCH 299/421] deleted valur for mqqtt docker command when creds are X509 --- .../controller/DeviceConnectivityControllerTest.java | 8 ++++---- .../server/dao/device/DeviceСonnectivityServiceImpl.java | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index 3b10695e62..b138778025 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -213,11 +213,11 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { credentials.getCredentialsId())); - JsonNode linuxMqttCommands = commands.get(MQTT); - assertThat(linuxMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + + JsonNode mqttCommands = commands.get(MQTT); + assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + "-u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); - assertThat(linuxMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile pathToFile/tb-server-chain.pem -h localhost -p 8883 " + + assertThat(mqttCommands.get(MQTTS).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile pathToFile/tb-server-chain.pem -h localhost -p 8883 " + "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); @@ -331,7 +331,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); assertThat(commands).hasSize(1); assertThat(commands.get(MQTT).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); - assertThat(commands.get(MQTT).get(DOCKER).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); + assertThat(commands.get(MQTT).get(DOCKER)).isNull(); } @Test diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java index 694f1cb8ee..284115ffb2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java @@ -161,7 +161,9 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService Optional.ofNullable(getDockerMqttPublishCommand(MQTTS, defaultHostname, topic, deviceCredentials)) .ifPresent(v -> dockerMqttCommands.put(MQTTS, v)); - mqttCommands.set(DOCKER, dockerMqttCommands); + if (!dockerMqttCommands.isEmpty()) { + mqttCommands.set(DOCKER, dockerMqttCommands); + } return mqttCommands.isEmpty() ? null : mqttCommands; } @@ -179,9 +181,6 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService } private String getDockerMqttPublishCommand(String protocol, String defaultHostname, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { - if (MQTTS.equals(protocol) && deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { - return CHECK_DOCUMENTATION; - } DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); if (properties == null || !properties.getEnabled()) { return null; From 9d20fa7d9e2c4857a1102a90ef3e5c5521df60e1 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 21 Jul 2023 16:12:34 +0300 Subject: [PATCH 300/421] added additional validation to ActionTypeTest and TbMsgTypeTest --- .../thingsboard/server/common/data/audit/ActionTypeTest.java | 2 ++ .../org/thingsboard/server/common/data/msg/TbMsgTypeTest.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java index b76b0fc2b7..8c602c3cff 100644 --- a/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java +++ b/common/data/src/test/java/org/thingsboard/server/common/data/audit/ActionTypeTest.java @@ -56,6 +56,8 @@ class ActionTypeTest { for (var type : types) { if (typesWithNullRuleEngineMsgType.contains(type)) { assertThat(type.getRuleEngineMsgType()).isEmpty(); + } else { + assertThat(type.getRuleEngineMsgType()).isPresent(); } } } diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java index 1323b7359d..a37eb31d72 100644 --- a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java +++ b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java @@ -62,6 +62,8 @@ class TbMsgTypeTest { for (var type : tbMsgTypes) { if (typesWithNullRuleNodeConnection.contains(type)) { assertThat(type.getRuleNodeConnection()).isNull(); + } else { + assertThat(type.getRuleNodeConnection()).isNotNull(); } } } From d52b67cc1b6c569fea2aa6f046971345fbb6a10b Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 21 Jul 2023 16:29:04 +0300 Subject: [PATCH 301/421] UI: Refactoring --- .../components/entity/entity-select.component.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts index 9427c2ff73..93452e4620 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts @@ -122,16 +122,6 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte writeValue(value: EntityId | null): void { if (value != null) { - if (value.id === NULL_UUID) { - value.id = null; - } - if (value.entityType === AliasEntityType.CURRENT_TENANT - || value.entityType === AliasEntityType.CURRENT_USER - || value.entityType === AliasEntityType.CURRENT_USER_OWNER) { - value.id = NULL_UUID; - } else if (value.entityType === AliasEntityType.CURRENT_CUSTOMER && !value.id) { - this.modelValue.id = NULL_UUID; - } this.modelValue = value; this.entitySelectFormGroup.get('entityType').patchValue(value.entityType, {emitEvent: false}); this.entitySelectFormGroup.get('entityId').patchValue(value, {emitEvent: false}); @@ -156,8 +146,6 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte || this.modelValue.entityType === AliasEntityType.CURRENT_USER || this.modelValue.entityType === AliasEntityType.CURRENT_USER_OWNER) { this.modelValue.id = NULL_UUID; - } else if (this.modelValue.entityType === AliasEntityType.CURRENT_CUSTOMER && !this.modelValue.id) { - this.modelValue.id = NULL_UUID; } if (this.modelValue.entityType && this.modelValue.id) { From 26044fc0358e11de99ad9cededc5ef5e1f87adec Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 21 Jul 2023 17:53:21 +0300 Subject: [PATCH 302/421] UI: Updated show device connectivity commands and detect operating system from user --- ui-ngx/src/app/app.component.ts | 5 + ui-ngx/src/app/core/http/device.service.ts | 10 +- ui-ngx/src/app/core/utils.ts | 26 +- ...e-check-connectivity-dialog.component.html | 363 +++++++++++++----- ...e-check-connectivity-dialog.component.scss | 19 +- ...ice-check-connectivity-dialog.component.ts | 89 ++++- ui-ngx/src/app/shared/models/device.models.ts | 25 ++ ui-ngx/src/assets/docker.svg | 1 + .../help/en_US/device/install_coap_client.md | 40 -- .../assets/help/en_US/device/install_curl.md | 34 -- .../help/en_US/device/install_mqtt_client.md | 38 -- ui-ngx/src/assets/linux.svg | 1 + .../assets/locale/locale.constant-en_US.json | 15 +- ui-ngx/src/assets/macos.svg | 1 + ui-ngx/src/assets/windows.svg | 1 + ui-ngx/src/form.scss | 7 + 16 files changed, 435 insertions(+), 240 deletions(-) create mode 100644 ui-ngx/src/assets/docker.svg delete mode 100644 ui-ngx/src/assets/help/en_US/device/install_coap_client.md delete mode 100644 ui-ngx/src/assets/help/en_US/device/install_curl.md delete mode 100644 ui-ngx/src/assets/help/en_US/device/install_mqtt_client.md create mode 100644 ui-ngx/src/assets/linux.svg create mode 100644 ui-ngx/src/assets/macos.svg create mode 100644 ui-ngx/src/assets/windows.svg diff --git a/ui-ngx/src/app/app.component.ts b/ui-ngx/src/app/app.component.ts index 8f612da5a1..627fc53608 100644 --- a/ui-ngx/src/app/app.component.ts +++ b/ui-ngx/src/app/app.component.ts @@ -94,6 +94,11 @@ export class AppComponent implements OnInit { ) ); + this.matIconRegistry.addSvgIcon('windows', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/windows.svg')); + this.matIconRegistry.addSvgIcon('macos', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/macos.svg')); + this.matIconRegistry.addSvgIcon('linux', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/linux.svg')); + this.matIconRegistry.addSvgIcon('docker', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/docker.svg')); + this.storageService.testLocalStorage(); this.setupTranslate(); diff --git a/ui-ngx/src/app/core/http/device.service.ts b/ui-ngx/src/app/core/http/device.service.ts index 44e91e43f8..8dff1e7ebc 100644 --- a/ui-ngx/src/app/core/http/device.service.ts +++ b/ui-ngx/src/app/core/http/device.service.ts @@ -25,8 +25,10 @@ import { ClaimResult, Device, DeviceCredentials, - DeviceInfo, DeviceInfoQuery, - DeviceSearchQuery + DeviceInfo, + DeviceInfoQuery, + DeviceSearchQuery, + PublishTelemetryCommand } from '@app/shared/models/device.models'; import { EntitySubtype } from '@app/shared/models/entity-type.models'; import { AuthService } from '@core/auth/auth.service'; @@ -208,8 +210,8 @@ export class DeviceService { return this.http.post('/api/device/bulk_import', entitiesData, defaultHttpOptionsFromConfig(config)); } - public getDevicePublishTelemetryCommands(deviceId: string, config?: RequestConfig): Observable<{[key: string]: string}> { - return this.http.get<{[key: string]: string}>(`/api/device/${deviceId}/commands`, defaultHttpOptionsFromConfig(config)); + public getDevicePublishTelemetryCommands(deviceId: string, config?: RequestConfig): Observable { + return this.http.get(`/api/device-connectivity/${deviceId}`, defaultHttpOptionsFromConfig(config)); } } diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index d6a3c3c6e3..c823c2bfea 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -355,9 +355,7 @@ const SNAKE_CASE_REGEXP = /[A-Z]/g; export function snakeCase(name: string, separator: string): string { separator = separator || '_'; - return name.replace(SNAKE_CASE_REGEXP, (letter, pos) => { - return (pos ? separator : '') + letter.toLowerCase(); - }); + return name.replace(SNAKE_CASE_REGEXP, (letter, pos) => (pos ? separator : '') + letter.toLowerCase()); } export function getDescendantProp(obj: any, path: string): any { @@ -776,3 +774,25 @@ export function genNextLabel(name: string, datasources: Datasource[]): string { } return label; } + +export const getOS = (): string => { + const userAgent = window.navigator.userAgent.toLowerCase(); + const macosPlatforms = /(macintosh|macintel|macppc|mac68k|macos|mac_powerpc)/i; + const windowsPlatforms = /(win32|win64|windows|wince)/i; + const iosPlatforms = /(iphone|ipad|ipod|darwin|ios)/i; + let os = null; + + if (macosPlatforms.test(userAgent)) { + os = 'macos'; + } else if (iosPlatforms.test(userAgent)) { + os = 'ios'; + } else if (windowsPlatforms.test(userAgent)) { + os = 'windows'; + } else if (/android/.test(userAgent)) { + os = 'android'; + } else if (/linux/.test(userAgent)) { + os = 'linux'; + } + + return os; +}; diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html index a0991570eb..a595487521 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html @@ -59,121 +59,235 @@ {{ deviceTransportTypeTranslationMap.get(DeviceTransportType.LWM2M) | translate }} -
+
-
device.connectivity.use-following-instructions
-
- device.connectivity.install-curl - -
-
-
device.connectivity.http-command
- -
-
-
device.connectivity.https-command
- -
+
device.connectivity.use-following-instructions
+ + + + + Windows + + +
+
+
device.connectivity.install-necessary-client-tools
+
device.connectivity.install-curl-windows
+
+ + +
+
+
+ + + + MacOS + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+ + + + Linux + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+
-
-
device.connectivity.use-following-instructions
-
- device.connectivity.install-mqtt-client - -
-
-
-
device.connectivity.mqtt-command
- -
-
-
-
device.connectivity.mqtts-command
- -
- -
device.connectivity.mqtts-x509-command
- -
-
+
device.connectivity.use-following-instructions
+ + + + + Windows + + +
+
+
device.connectivity.install-necessary-client-tools
+
Coming Soon!!!!
+
+ + +
+
+
+ + + + MacOS + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+ + + + Linux + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+ + + + Docker + + +
+ + +
+
+
+
-
-
device.connectivity.use-following-instructions
-
- device.connectivity.install-coap-cli - -
-
-
-
device.connectivity.coap-command
- -
-
-
-
device.connectivity.coaps-command
- -
- -
device.connectivity.coaps-x509-command
- -
-
+
device.connectivity.use-following-instructions
+ + + + + MacOS + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+ + + + Linux + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ + +
+
+
+ + + + Docker + + +
+ + +
+
+
+
-
device.connectivity.snmp-command
-
- - - {{ 'action.see-documentation' | translate }} - open_in_new - - +
+ +
-
device.connectivity.lwm2m-command
-
- - - {{ 'action.see-documentation' | translate }} - open_in_new - - +
+ +
@@ -224,3 +338,44 @@
attribute.no-latest-telemetry
+ + +
+
+
device.connectivity.execute-following-command
+ + {{ cmd.noSecLabel }} + {{ cmd.secLabel }} + +
+ + + + + +
+ +
+ + + + +
+
+
+
+ + + + diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss index e7c88bb2cb..1a95da0a14 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss @@ -68,6 +68,10 @@ font-size: 14px; } + .tb-flex-1 { + flex: 1; + } + .tb-form-table-body { max-height: 88px; overflow-y: auto; @@ -84,6 +88,10 @@ } } + .tb-install-windows { + min-height: 42px; + } + @media #{$mat-sm} { width: 470px; } @@ -112,12 +120,13 @@ .code-wrapper { padding: 0; pre[class*=language-] { + margin: 0; background: #F3F6FA; border-color: #305680; } } button.clipboard-btn { - right: 0; + right: -2px; p { color: #305680; } @@ -148,4 +157,12 @@ box-sizing: initial; } } + + .tabs-icon { + margin-right: 8px; + } + + .tb-form-panel.tb-tab-body { + padding: 16px 0 0; + } } diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts index 8a427512aa..f185d88c6a 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts @@ -38,16 +38,19 @@ import { BasicTransportType, DeviceTransportType, deviceTransportTypeTranslationMap, - NetworkTransportType + NetworkTransportType, + PublishTelemetryCommand } from '@shared/models/device.models'; import { UserSettingsService } from '@core/http/user-settings.service'; import { ActionPreferencesUpdateUserSettings } from '@core/auth/auth.actions'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { getOS } from '@core/utils'; export interface DeviceCheckConnectivityDialogData { deviceId: EntityId; afterAdd: boolean; } + @Component({ selector: 'tb-device-check-connectivity-dialog', templateUrl: './device-check-connectivity-dialog.component.html', @@ -62,7 +65,7 @@ export class DeviceCheckConnectivityDialogComponent extends latestTelemetry: Array = []; - commands: {[key: string]: string}; + commands: PublishTelemetryCommand; allowTransportType = new Set(); selectTransportType: NetworkTransportType; @@ -77,6 +80,45 @@ export class DeviceCheckConnectivityDialogComponent extends notShowAgain = false; + httpTabIndex = 0; + mqttTabIndex = 0; + coapTabIndex = 0; + + readonly installCoap = '```bash\n' + + 'git clone https://github.com/obgm/libcoap --recursive\n' + + '{:copy-code}\n' + + '```\n' + + '
\n' + + '\n' + + '```bash\n' + + 'cd libcoap\n' + + '{:copy-code}\n' + + '```\n' + + '
\n' + + '\n' + + '```bash\n' + + './autogen.sh\n' + + '{:copy-code}\n' + + '```\n' + + '
\n' + + '\n' + + '```bash\n' + + './configure --with-openssl --disable-doxygen --disable-manpages --disable-shared\n' + + '{:copy-code}\n' + + '```\n' + + '
\n' + + '\n' + + '```bash\n' + + 'make\n' + + '{:copy-code}\n' + + '```\n' + + '
\n' + + '\n' + + '```bash\n' + + 'sudo make install\n' + + '{:copy-code}\n' + + '```'; + private telemetrySubscriber: TelemetrySubscriber; private currentTime = Date.now(); @@ -125,11 +167,21 @@ export class DeviceCheckConnectivityDialogComponent extends } } - createMarkDownCommand(command: string): string { + createMarkDownCommand(commands: string | string[]): string { + if (Array.isArray(commands)) { + const formatCommands: Array = []; + commands.forEach(command => formatCommands.push(this.createMarkDownSingleCommand(command))); + return formatCommands.join('
\n'); + } else { + return this.createMarkDownSingleCommand(commands); + } + } + + private createMarkDownSingleCommand(command: string): string { return '```bash\n' + - command + - '{:copy-code}\n' + - '```'; + command + + '{:copy-code}\n' + + '```'; } private loadCommands() { @@ -144,6 +196,7 @@ export class DeviceCheckConnectivityDialogComponent extends } }); this.selectTransportType = this.allowTransportType.values().next().value; + this.selectTabIndexForUserOS(); this.loadedCommand = true; } ); @@ -180,4 +233,28 @@ export class DeviceCheckConnectivityDialogComponent extends }); } + private selectTabIndexForUserOS() { + const currentOS = getOS(); + switch (currentOS) { + case 'linux': + case 'android': + this.httpTabIndex = 2; + this.mqttTabIndex = 2; + this.coapTabIndex = 1; + break; + case 'macos': + case 'ios': + this.httpTabIndex = 1; + this.mqttTabIndex = 1; + break; + case 'windows': + this.httpTabIndex = 0; + this.mqttTabIndex = 0; + break; + default: + this.mqttTabIndex = this.commands.mqtt?.docker ? 3 : 0; + this.coapTabIndex = this.commands.coap?.docker ? 2 : 1; + } + } + } diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index b371c131df..e5dd1e9efc 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -837,6 +837,31 @@ export interface ClaimResult { response: ClaimResponse; } +export interface PublishTelemetryCommand { + http?: { + http?: string; + https?: string; + }; + mqtt: { + mqtt?: string; + mqtts?: string | Array; + docker?: { + mqtt?: string; + mqtts?: string | Array; + }; + }; + coap: { + coap?: string; + coaps?: string | Array; + docker?: { + coap?: string; + coaps?: string | Array; + }; + }; + lwm2m?: string; + snmp?: string; +} + export const dayOfWeekTranslations = new Array( 'device-profile.schedule-day.monday', 'device-profile.schedule-day.tuesday', diff --git a/ui-ngx/src/assets/docker.svg b/ui-ngx/src/assets/docker.svg new file mode 100644 index 0000000000..f152739de6 --- /dev/null +++ b/ui-ngx/src/assets/docker.svg @@ -0,0 +1 @@ + diff --git a/ui-ngx/src/assets/help/en_US/device/install_coap_client.md b/ui-ngx/src/assets/help/en_US/device/install_coap_client.md deleted file mode 100644 index 0612acad26..0000000000 --- a/ui-ngx/src/assets/help/en_US/device/install_coap_client.md +++ /dev/null @@ -1,40 +0,0 @@ - #### CoAP installation instructions ---- -
- -Install coap client tool on your **Linux/macOS**: - -```bash -git clone https://github.com/obgm/libcoap --recursive -{:copy-code} -``` -
- -```bash -cd libcoap -{:copy-code} -``` -
- -```bash -./autogen.sh -{:copy-code} -``` -
- -```bash -./configure --with-openssl --disable-doxygen --disable-manpages --disable-shared -{:copy-code} -``` -
- -```bash -make -{:copy-code} -``` -
- -```bash -sudo make install -{:copy-code} -``` diff --git a/ui-ngx/src/assets/help/en_US/device/install_curl.md b/ui-ngx/src/assets/help/en_US/device/install_curl.md deleted file mode 100644 index 0ba60fc590..0000000000 --- a/ui-ngx/src/assets/help/en_US/device/install_curl.md +++ /dev/null @@ -1,34 +0,0 @@ -#### cURL installation instructions ---- -
-
- - Ubuntu - MacOS - Windows - -
- - -

Install cURL tool:

- -
- -

Install cURL tool:

- -
- -
Starting Windows 10 b17063, cURL is available by default.
-
-
-
diff --git a/ui-ngx/src/assets/help/en_US/device/install_mqtt_client.md b/ui-ngx/src/assets/help/en_US/device/install_mqtt_client.md deleted file mode 100644 index 941dce7ab4..0000000000 --- a/ui-ngx/src/assets/help/en_US/device/install_mqtt_client.md +++ /dev/null @@ -1,38 +0,0 @@ - #### MQTT client tool installation instructions ---- -
-
- - Ubuntu - MacOS - Windows - -
- - -

Install mqtt client tool:

- -
- -

Install mqtt client tool:

- -
- -

Install mqtt client tool:

- - descriptionHow to install MQTT Box -
-
-
diff --git a/ui-ngx/src/assets/linux.svg b/ui-ngx/src/assets/linux.svg new file mode 100644 index 0000000000..66f505437f --- /dev/null +++ b/ui-ngx/src/assets/linux.svg @@ -0,0 +1 @@ + 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 3374338761..8e254a655c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -880,7 +880,8 @@ "loading": "Loading...", "proceed": "Proceed", "open-details-page": "Open details page", - "not-found": "Not found" + "not-found": "Not found", + "documentation": "Documentation" }, "content-type": { "json": "Json", @@ -1389,16 +1390,10 @@ "device-created-check-connectivity": "Device created. Let's check connectivity!", "loading-check-connectivity-command": "Loading check connectivity commands...", "use-following-instructions": "Use the following instructions for sending telemetry on behalf of the device using shell", - "install-curl": "Install cURL tool.", - "install-mqtt-client": "Install mgtt client tool.", - "install-coap-cli": "Install coap-cli tool.", - "http-command": "HTTP (Linux, macOS or Windows)", - "https-command": "HTTPS (Linux, macOS or Windows)", - "mqtt-command": "MQTT (Linux, macOS)", - "mqtts-command": "MQTT over SSL (Linux, macOS)", + "execute-following-command": "Executive the following command", + "install-curl-windows": "Starting Windows 10 b17063, cURL is available by default", + "install-necessary-client-tools": "Install necessary client tools", "mqtts-x509-command": "Use the following documentation to connect the device via MQTT with authorization X509", - "coap-command": "CoAP (Linux, macOS)", - "coaps-command": "CoAP over DTLS (Linux, macOS)", "coaps-x509-command": "Use the following documentation to connect the device via CoAP over DTLS with authorization X509", "snmp-command": "Use the following documentation to connect the device through the SNMP.", "lwm2m-command": "Use the following documentation to connect the device through the LWM2M." diff --git a/ui-ngx/src/assets/macos.svg b/ui-ngx/src/assets/macos.svg new file mode 100644 index 0000000000..c3bac982fb --- /dev/null +++ b/ui-ngx/src/assets/macos.svg @@ -0,0 +1 @@ + diff --git a/ui-ngx/src/assets/windows.svg b/ui-ngx/src/assets/windows.svg new file mode 100644 index 0000000000..1f168c099e --- /dev/null +++ b/ui-ngx/src/assets/windows.svg @@ -0,0 +1 @@ + diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index a01c157e4c..a0d09d42c4 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -144,6 +144,13 @@ &.space-between { justify-content: space-between; } + &.no-border { + border: none; + border-radius: 0; + } + &.no-padding { + padding: 0; + } .mat-divider-vertical { height: 56px; margin-top: -7px; From 9d8a9943bf229216099fc1a7c4e29d4e223ab925 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 21 Jul 2023 18:26:14 +0300 Subject: [PATCH 303/421] UI: Add value card widget. Introduce tb-icon component to handle both font and svg (mdi) icons. --- .../json/system/widget_bundles/cards.json | 42 + ui-ngx/src/app/app.component.ts | 47 +- ui-ngx/src/app/core/services/menu.models.ts | 2 - ui-ngx/src/app/core/services/menu.service.ts | 52 +- ui-ngx/src/app/modules/common/modules-map.ts | 2 + .../add-widget-dialog.component.html | 63 +- .../add-widget-dialog.component.scss | 29 + .../add-widget-dialog.component.ts | 7 +- .../dashboard-page/edit-widget.component.html | 4 +- .../entity/entities-table.component.html | 3 +- .../components/event/event-table-config.ts | 1 - .../components/router-tabs.component.html | 3 +- .../components/router-tabs.component.scss | 2 +- .../manage-widget-actions.component.html | 2 +- .../basic/basic-widget-config.module.ts | 8 +- .../simple-card-basic-config.component.ts | 28 +- .../value-card-basic-config.component.html | 59 + .../value-card-basic-config.component.ts | 254 + .../widget-actions-panel.component.html | 2 +- .../widget/config/data-keys.component.html | 2 +- .../widget/config/widget-settings.models.ts | 263 + .../cards/value-card-widget.component.html | 70 + .../cards/value-card-widget.component.scss | 70 + .../lib/cards/value-card-widget.component.ts | 144 + .../lib/cards/value-card-widget.models.ts | 127 + .../add-doc-link-dialog.component.html | 2 +- .../add-quick-link-dialog.component.html | 2 +- .../lib/home-page/doc-link.component.html | 10 +- .../home-page/doc-links-widget.component.html | 6 +- .../edit-links-dialog.component.html | 6 +- .../widget/lib/home-page/home-page.scss | 1 + .../lib/home-page/quick-link.component.html | 19 +- .../quick-links-widget.component.html | 7 +- .../lib/multiple-input-widget.component.html | 8 +- .../lib/navigation-card-widget.component.html | 2 +- .../navigation-cards-widget.component.html | 3 +- .../navigation-cards-widget.component.scss | 2 +- .../lib/rpc/persistent-table.component.html | 6 +- .../color-settings-panel.component.html | 105 + .../color-settings-panel.component.scss | 85 + .../common/color-settings-panel.component.ts | 131 + .../common/color-settings.component.html | 30 + .../common/color-settings.component.ts | 124 + .../common/font-settings-panel.component.html | 95 + .../common/font-settings-panel.component.scss | 51 + .../common/font-settings-panel.component.ts | 136 + .../common/font-settings.component.html | 25 + .../common/font-settings.component.ts | 102 + .../common/image-cards-select.component.html | 43 + .../common/image-cards-select.component.scss | 116 + .../common/image-cards-select.component.ts | 190 + .../lib/settings/widget-settings.module.ts | 26 +- .../widget/widget-component.service.ts | 6 + .../widget/widget-components.module.ts | 7 +- .../widget/widget-container.component.html | 14 +- .../widget/widget-container.component.scss | 2 +- .../widget/widget-container.component.ts | 7 +- .../widget/widget-preview.component.html | 2 + .../widget/widget-preview.component.scss | 9 +- .../widget/widget-preview.component.ts | 6 + .../home/menu/menu-link.component.html | 3 +- .../home/menu/menu-toggle.component.html | 3 +- .../home/models/dashboard-component.models.ts | 3 + .../entity/entities-table-config.models.ts | 1 - .../home/models/widget-component.models.ts | 1 + .../home/pages/admin/admin-routing.module.ts | 3 +- .../home-links/home-links.component.html | 3 +- .../home-links/home-links.component.scss | 2 +- .../select-widget-type-dialog.component.html | 8 +- .../select-widget-type-dialog.component.scss | 2 +- .../components/breadcrumb.component.html | 6 +- .../shared/components/breadcrumb.component.ts | 2 - .../src/app/shared/components/breadcrumb.ts | 1 - .../components/color-input.component.html | 4 +- .../components/color-input.component.scss | 6 - .../app/shared/components/icon.component.ts | 281 + .../material-icon-select.component.html | 8 +- .../material-icon-select.component.scss | 18 - .../components/material-icons.component.html | 4 +- .../notification/notification.component.html | 8 +- .../src/app/shared/components/public-api.ts | 1 + ui-ngx/src/app/shared/models/icon.models.ts | 63 +- ui-ngx/src/app/shared/models/widget.models.ts | 4 +- ui-ngx/src/app/shared/shared.module.ts | 7 +- .../en_US/widget/lib/card/value_color_fn.md | 40 + .../help/en_US/widget/lib/map/color_fn.md | 2 +- .../en_US/widget/lib/map/path_color_fn.md | 2 +- .../widget/lib/map/path_point_color_fn.md | 2 +- .../en_US/widget/lib/map/polygon_color_fn.md | 2 +- .../assets/locale/locale.constant-en_US.json | 25 +- .../src/assets/metadata/material-icons.json | 6368 +---------------- .../widget/value-card/centered-layout.svg | 21 + .../widget/value-card/horizontal-layout.svg | 21 + .../value-card/horizontal-reversed-layout.svg | 21 + .../widget/value-card/simplified-layout.svg | 19 + .../widget/value-card/square-layout.svg | 24 + .../widget/value-card/vertical-layout.svg | 20 + ui-ngx/src/form.scss | 42 +- ui-ngx/src/styles.scss | 26 +- 99 files changed, 3099 insertions(+), 6650 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts create mode 100644 ui-ngx/src/app/shared/components/icon.component.ts create mode 100644 ui-ngx/src/assets/help/en_US/widget/lib/card/value_color_fn.md create mode 100644 ui-ngx/src/assets/widget/value-card/centered-layout.svg create mode 100644 ui-ngx/src/assets/widget/value-card/horizontal-layout.svg create mode 100644 ui-ngx/src/assets/widget/value-card/horizontal-reversed-layout.svg create mode 100644 ui-ngx/src/assets/widget/value-card/simplified-layout.svg create mode 100644 ui-ngx/src/assets/widget/value-card/square-layout.svg create mode 100644 ui-ngx/src/assets/widget/value-card/vertical-layout.svg diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 473d3d215b..cc2c74c359 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -225,6 +225,48 @@ "settingsDirective": "tb-dashboard-state-widget-settings", "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"syncParentStateParams\":true,\"defaultAutofillLayout\":true,\"defaultMargin\":0,\"defaultBackgroundColor\":\"#fff\"},\"title\":\"Dashboard state widget\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"widgetCss\":\"\",\"noDataDisplayMessage\":\"\",\"showLegend\":false}" } + }, + { + "alias": "value_card", + "name": "Value card", + "image": null, + "description": "Designed to display single value of the selected attribute or timeseries data. Widget styles are customizable.", + "descriptor": { + "type": "latest", + "sizeX": 2.5, + "sizeY": 2.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px'\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\"}" + } + }, + { + "alias": "horizontal_value_card", + "name": "Horizontal value card", + "image": null, + "description": "Designed to display single value of the selected attribute or timeseries data. Widget styles are customizable.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px'\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\"}" + } } ] } \ No newline at end of file diff --git a/ui-ngx/src/app/app.component.ts b/ui-ngx/src/app/app.component.ts index 8f612da5a1..6ad217e20f 100644 --- a/ui-ngx/src/app/app.component.ts +++ b/ui-ngx/src/app/app.component.ts @@ -30,6 +30,7 @@ import { combineLatest } from 'rxjs'; import { selectIsAuthenticated, selectIsUserLoaded } from '@core/auth/auth.selectors'; import { distinctUntilChanged, filter, map, skip } from 'rxjs/operators'; import { AuthService } from '@core/auth/auth.service'; +import { svgIcons } from '@shared/models/icon.models'; @Component({ selector: 'tb-root', @@ -55,44 +56,14 @@ export class AppComponent implements OnInit { } }); - this.matIconRegistry.addSvgIconLiteral( - 'google-logo', - this.domSanitizer.bypassSecurityTrustHtml( - '' - ) - ); - - this.matIconRegistry.addSvgIconLiteral( - 'github-logo', - this.domSanitizer.bypassSecurityTrustHtml( - '' - ) - ); - - this.matIconRegistry.addSvgIconLiteral( - 'facebook-logo', - this.domSanitizer.bypassSecurityTrustHtml( - '' - ) - ); - - this.matIconRegistry.addSvgIconLiteral( - 'apple-logo', - this.domSanitizer.bypassSecurityTrustHtml( - '' - ) - ); - - this.matIconRegistry.addSvgIconLiteral( - 'queues-list', - this.domSanitizer.bypassSecurityTrustHtml( - '' + - '' + - '' + - '' + - '' - ) - ); + for (const svgIcon of Object.keys(svgIcons)) { + this.matIconRegistry.addSvgIconLiteral( + svgIcon, + this.domSanitizer.bypassSecurityTrustHtml( + svgIcons[svgIcon] + ) + ); + } this.storageService.testLocalStorage(); diff --git a/ui-ngx/src/app/core/services/menu.models.ts b/ui-ngx/src/app/core/services/menu.models.ts index 2043eeadea..47072943be 100644 --- a/ui-ngx/src/app/core/services/menu.models.ts +++ b/ui-ngx/src/app/core/services/menu.models.ts @@ -24,7 +24,6 @@ export interface MenuSection extends HasUUID{ type: MenuSectionType; path: string; icon: string; - isMdiIcon?: boolean; pages?: Array; opened?: boolean; disabled?: boolean; @@ -39,6 +38,5 @@ export interface HomeSection { export interface HomeSectionPlace { name: string; icon: string; - isMdiIcon?: boolean; path: string; } diff --git a/ui-ngx/src/app/core/services/menu.service.ts b/ui-ngx/src/app/core/services/menu.service.ts index b33c552eb1..0de3346af9 100644 --- a/ui-ngx/src/app/core/services/menu.service.ts +++ b/ui-ngx/src/app/core/services/menu.service.ts @@ -111,8 +111,7 @@ export class MenuService { name: 'tenant-profile.tenant-profiles', type: 'link', path: '/tenantProfiles', - icon: 'mdi:alpha-t-box', - isMdiIcon: true + icon: 'mdi:alpha-t-box' }, { id: 'resources', @@ -133,8 +132,7 @@ export class MenuService { name: 'resource.resources-library', type: 'link', path: '/resources/resources-library', - icon: 'mdi:rhombus-split', - isMdiIcon: true + icon: 'mdi:rhombus-split' } ] }, @@ -144,7 +142,6 @@ export class MenuService { type: 'link', path: '/notification', icon: 'mdi:message-badge', - isMdiIcon: true, pages: [ { id: 'notification_inbox', @@ -176,8 +173,7 @@ export class MenuService { fullName: 'notification.notification-templates', type: 'link', path: '/notification/templates', - icon: 'mdi:message-draw', - isMdiIcon: true + icon: 'mdi:message-draw' }, { id: 'notification_rules', @@ -185,8 +181,7 @@ export class MenuService { fullName: 'notification.notification-rules', type: 'link', path: '/notification/rules', - icon: 'mdi:message-cog', - isMdiIcon: true + icon: 'mdi:message-cog' } ] }, @@ -218,8 +213,7 @@ export class MenuService { fullName: 'admin.notifications-settings', type: 'link', path: '/settings/notifications', - icon: 'mdi:message-badge', - isMdiIcon: true + icon: 'mdi:message-badge' }, { id: 'queues', @@ -250,16 +244,14 @@ export class MenuService { name: 'admin.2fa.2fa', type: 'link', path: '/security-settings/2fa', - icon: 'mdi:two-factor-authentication', - isMdiIcon: true + icon: 'mdi:two-factor-authentication' }, { id: 'oauth2', name: 'admin.oauth2.oauth2', type: 'link', path: '/security-settings/oauth2', - icon: 'mdi:shield-account', - isMdiIcon: true + icon: 'mdi:shield-account' } ] } @@ -281,7 +273,6 @@ export class MenuService { { name: 'tenant-profile.tenant-profiles', icon: 'mdi:alpha-t-box', - isMdiIcon: true, path: '/tenantProfiles' }, ] @@ -327,7 +318,6 @@ export class MenuService { { name: 'admin.2fa.2fa', icon: 'mdi:two-factor-authentication', - isMdiIcon: true, path: '/settings/2fa' }, { @@ -361,8 +351,7 @@ export class MenuService { name: 'alarm.alarms', type: 'link', path: '/alarms', - icon: 'mdi:alert-outline', - isMdiIcon: true + icon: 'mdi:alert-outline' }, { id: 'dashboards', @@ -413,16 +402,14 @@ export class MenuService { name: 'device-profile.device-profiles', type: 'link', path: '/profiles/deviceProfiles', - icon: 'mdi:alpha-d-box', - isMdiIcon: true + icon: 'mdi:alpha-d-box' }, { id: 'asset_profiles', name: 'asset-profile.asset-profiles', type: 'link', path: '/profiles/assetProfiles', - icon: 'mdi:alpha-a-box', - isMdiIcon: true + icon: 'mdi:alpha-a-box' } ] }, @@ -513,8 +500,7 @@ export class MenuService { name: 'resource.resources-library', type: 'link', path: '/resources/resources-library', - icon: 'mdi:rhombus-split', - isMdiIcon: true + icon: 'mdi:rhombus-split' } ] }, @@ -524,7 +510,6 @@ export class MenuService { type: 'link', path: '/notification', icon: 'mdi:message-badge', - isMdiIcon: true, pages: [ { id: 'notification_inbox', @@ -556,8 +541,7 @@ export class MenuService { fullName: 'notification.notification-templates', type: 'link', path: '/notification/templates', - icon: 'mdi:message-draw', - isMdiIcon: true + icon: 'mdi:message-draw' }, { id: 'notification_rules', @@ -565,8 +549,7 @@ export class MenuService { fullName: 'notification.notification-rules', type: 'link', path: '/notification/rules', - icon: 'mdi:message-cog', - isMdiIcon: true + icon: 'mdi:message-cog' } ] }, @@ -598,8 +581,7 @@ export class MenuService { fullName: 'admin.notifications-settings', type: 'link', path: '/settings/notifications', - icon: 'mdi:message-badge', - isMdiIcon: true + icon: 'mdi:message-badge' }, { id: 'repository_settings', @@ -673,7 +655,6 @@ export class MenuService { { name: 'asset-profile.asset-profiles', icon: 'mdi:alpha-a-box', - isMdiIcon: true, path: '/profiles/assetProfiles' } ] @@ -689,7 +670,6 @@ export class MenuService { { name: 'device-profile.device-profiles', icon: 'mdi:alpha-d-box', - isMdiIcon: true, path: '/profiles/deviceProfiles' }, { @@ -814,8 +794,7 @@ export class MenuService { name: 'alarm.alarms', type: 'link', path: '/alarms', - icon: 'mdi:alert-outline', - isMdiIcon: true + icon: 'mdi:alert-outline' }, { id: 'dashboards', @@ -874,7 +853,6 @@ export class MenuService { type: 'link', path: '/notification', icon: 'mdi:message-badge', - isMdiIcon: true, pages: [ { id: 'notification_inbox', diff --git a/ui-ngx/src/app/modules/common/modules-map.ts b/ui-ngx/src/app/modules/common/modules-map.ts index 767633a3ce..eab8bcf5d5 100644 --- a/ui-ngx/src/app/modules/common/modules-map.ts +++ b/ui-ngx/src/app/modules/common/modules-map.ts @@ -182,6 +182,7 @@ import * as ToggleHeaderComponent from '@shared/components/toggle-header.compone import * as ToggleSelectComponent from '@shared/components/toggle-select.component'; import * as UnitInputComponent from '@shared/components/unit-input.component'; import * as MaterialIconsComponent from '@shared/components/material-icons.component'; +import * as TbIconComponent from '@shared/components/icon.component'; import * as AddEntityDialogComponent from '@home/components/entity/add-entity-dialog.component'; import * as EntitiesTableComponent from '@home/components/entity/entities-table.component'; @@ -484,6 +485,7 @@ class ModulesMap implements IModulesMap { '@shared/components/toggle-select.component': ToggleSelectComponent, '@shared/components/unit-input.component': UnitInputComponent, '@shared/components/material-icons.component': MaterialIconsComponent, + '@shared/components/icon.component': TbIconComponent, '@home/components/entity/add-entity-dialog.component': AddEntityDialogComponent, '@home/components/entity/entities-table.component': EntitiesTableComponent, diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html index ad08c0c89e..7a17157b31 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+

widget.add

: {{data.widgetInfo.widgetName}} @@ -32,40 +32,37 @@ close
- - -
-
- - - -
- -
-
-
+
+ + + +
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss new file mode 100644 index 0000000000..6c3b90da84 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss @@ -0,0 +1,29 @@ +/** + * Copyright © 2016-2023 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-add-widget-dialog { + .mat-mdc-dialog-content { + padding: 0; + position: relative; + } + @media #{$mat-gt-xs} { + width: 1200px; + .mat-mdc-dialog-content { + height: 600px; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts index ada22bba94..67c1551d9d 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.ts @@ -14,12 +14,12 @@ /// limitations under the License. /// -import { Component, Inject, OnInit, SkipSelf } from '@angular/core'; +import { Component, Inject, OnInit, SkipSelf, ViewEncapsulation } 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 { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, FormGroupDirective, NgForm } from '@angular/forms'; +import { FormGroupDirective, NgForm, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { DialogComponent } from '@app/shared/components/dialog.component'; import { Widget, WidgetConfigMode, widgetTypesData } from '@shared/models/widget.models'; @@ -41,7 +41,8 @@ export interface AddWidgetDialogData { selector: 'tb-add-widget-dialog', templateUrl: './add-widget-dialog.component.html', providers: [/*{provide: ErrorStateMatcher, useExisting: AddWidgetDialogComponent}*/], - styleUrls: [] + styleUrls: ['./add-widget-dialog.component.scss'], + encapsulation: ViewEncapsulation.None }) export class AddWidgetDialogComponent extends DialogComponent implements OnInit, ErrorStateMatcher { diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html index db9af1ba06..a1c8ee6ade 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html @@ -60,7 +60,9 @@ [stateController]="stateController" [dashboardTimewindow]="dashboard.configuration.timewindow" [widget]="widget" - [widgetConfig]="widgetFormGroup.get('widgetConfig').value.config"> + [widgetConfig]="widgetFormGroup.get('widgetConfig').value.config" + [previewWidth]="widgetConfig.typeParameters.previewWidth" + [previewHeight]="widgetConfig.typeParameters.previewHeight">
diff --git a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html index 65f4bed2ae..aced3e1fd0 100644 --- a/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/entities-table.component.html @@ -86,8 +86,7 @@ matTooltip="{{ actionDescriptor.name }}" matTooltipPosition="above" (click)="actionDescriptor.onAction($event)"> - - {{actionDescriptor.icon}} + {{actionDescriptor.icon}}
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-quick-link-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-quick-link-dialog.component.html index 6eaf4ca205..75d60e046f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-quick-link-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/add-quick-link-dialog.component.html @@ -22,7 +22,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-link.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-link.component.html index 2d6ea9b3fa..52e6b54519 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-link.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-link.component.html @@ -38,8 +38,8 @@
- - + +
@@ -47,7 +47,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html index 1ccc2e8b24..e4b56e491b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/doc-links-widget.component.html @@ -23,7 +23,7 @@ matTooltipPosition="above" mat-icon-button (click)="edit()"> - edit + edit
@@ -32,7 +32,7 @@ [href]="docLink.link" target="_blank"> @@ -43,7 +43,7 @@ matTooltip="{{ 'widgets.documentation.add-link' | translate }}" matTooltipPosition="above" (click)="addLink()"> - add + add
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-links-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-links-dialog.component.html index e70e8cd5c2..baddc057c2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-links-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/edit-links-dialog.component.html @@ -22,7 +22,7 @@
@@ -60,7 +60,7 @@ matTooltip="{{ 'action.drag' | translate }}" matTooltipPosition="above" class="tb-drag-handle"> - drag_indicator + drag_indicator
@@ -71,7 +71,7 @@ matTooltip="{{ (mode === 'docs' ? 'widgets.documentation.add-link' : 'widgets.quick-links.add-link') | translate }}" matTooltipPosition="above" (click)="addLink()"> - add + add
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page.scss b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page.scss index a488d77c6e..4adf70d97d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/home-page.scss @@ -23,6 +23,7 @@ letter-spacing: 0.2px; color: rgba(0, 0, 0, 0.76); .mat-icon { + vertical-align: bottom; margin-right: 10px; color: rgba(0, 0, 0, 0.54); font-size: 20px; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-link.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-link.component.html index 0dec41e71d..da1e9977a1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-link.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-link.component.html @@ -25,21 +25,19 @@ (focusin)="onFocus()" required [matAutocomplete]="linkAutocomplete"> - {{ quickLink.icon }} - + {{ quickLink.icon }} - {{ link.icon }} - + {{ link.icon }} @@ -58,8 +56,8 @@
- - + +
@@ -67,8 +65,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-links-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-links-widget.component.html index 95c2818f1c..58d3d98ee3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-links-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/home-page/quick-links-widget.component.html @@ -23,7 +23,7 @@ matTooltipPosition="above" mat-icon-button (click)="edit()"> - edit + edit
@@ -32,8 +32,7 @@ [routerLink]="quickLink.path"> @@ -44,7 +43,7 @@ matTooltip="{{ 'widgets.quick-links.add-link' | translate }}" matTooltipPosition="above" (click)="addLink()"> - add + add
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 0a757fd34f..dec2a70864 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -38,7 +38,7 @@ (focus)="key.isFocused = true; focusInputElement($event)" (blur)="key.isFocused = false; inputChanged(source, key)"> - {{key.settings.icon}} + {{key.settings.icon}} icon @@ -63,7 +63,7 @@ (focus)="key.isFocused = true; focusInputElement($event)" (blur)="key.isFocused = false; inputChanged(source, key)"> - {{key.settings.icon}} + {{key.settings.icon}} icon @@ -99,7 +99,7 @@ (blur)="key.isFocused = false; inputChanged(source, key)" /> - {{key.settings.icon}} + {{key.settings.icon}} icon @@ -123,7 +123,7 @@ [labelPosition]="key.settings.slideToggleLabelPosition" (change)="inputChanged(source, key)"> - {{key.settings.icon}} + {{key.settings.icon}} icon diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.html index 0d33c487b7..dadf3317d8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.html @@ -16,6 +16,6 @@ --> - {{settings.icon}} + {{settings.icon}} {{translatedName}} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html index dbd4d50981..d63a4ef76f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.html @@ -25,8 +25,7 @@ - {{place.icon}} - + {{place.icon}} {{place.name}} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss index f3710fbc81..7d41450655 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-cards-widget.component.scss @@ -55,7 +55,7 @@ display: flex; flex-direction: column; align-items: center; - mat-icon { + .mat-icon { margin: auto; } span.mdc-button__label { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html index 93b0742930..66f19f717a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html @@ -80,7 +80,7 @@ matTooltip="{{ actionDescriptor.displayName }}" matTooltipPosition="above" (click)="onActionButtonClick($event, column, actionDescriptor)"> - {{ actionDescriptor.icon }} + {{ actionDescriptor.icon }}
@@ -88,14 +88,14 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.html new file mode 100644 index 0000000000..cd8cf1bc06 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.html @@ -0,0 +1,105 @@ + +
+
widgets.color.color-settings
+
+ + + {{ colorTypeTranslationsMap.get(type) | translate }} + + +
+
+
widgets.color.color
+ + +
+
+
+
+ +
+
+ +
+
+ + +
+
+ + +
+
widgets.color.value-range
+
+
+
+
+
widgets.color.from
+ + + +
widgets.color.to
+ + + + + +
+ +
+
+
+ +
+
+ +
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.scss new file mode 100644 index 0000000000..0036723b92 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.scss @@ -0,0 +1,85 @@ +/** + * Copyright © 2016-2023 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-color-settings-panel { + width: 500px; + height: 470px; + display: flex; + flex-direction: column; + gap: 16px; + @media #{$mat-xs} { + width: 90vw; + } + .tb-color-settings-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-color-ranges-panel { + flex: 1; + min-height: 0; + gap: 16px; + display: flex; + flex-direction: column; + } + .tb-color-ranges { + flex: 1; + gap: 12px; + display: flex; + flex-direction: column; + overflow: auto; + } + .tb-form-row { + height: auto; + .tb-value-range-text { + width: 64px; + font-size: 14px; + color: rgba(0, 0, 0, 0.38); + @media #{$mat-xs} { + width: auto; + } + &.tb-value-range-text-to { + text-align: center; + } + } + } + button.mat-mdc-button-base.tb-add-color-range { + &:not(:disabled) { + color: rgba(0, 0, 0, 0.54); + } + &:disabled { + color: rgba(0, 0, 0, 0.12); + } + } + .tb-color-settings-panel-body { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; + } + .tb-color-settings-panel-buttons { + height: 40px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts new file mode 100644 index 0000000000..c20abd8d84 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts @@ -0,0 +1,131 @@ +/// +/// Copyright © 2016-2023 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, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { + ColorRange, + ColorSettings, + ColorType, + colorTypeTranslations +} from '@home/components/widget/config/widget-settings.models'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { + AbstractControl, + FormControl, + FormGroup, + UntypedFormArray, + UntypedFormBuilder, + UntypedFormGroup +} from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Datasource, DatasourceType } from '@shared/models/widget.models'; +import { deepClone } from '@core/utils'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { WidgetService } from '@core/http/widget.service'; + +@Component({ + selector: 'tb-color-settings-panel', + templateUrl: './color-settings-panel.component.html', + providers: [], + styleUrls: ['./color-settings-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ColorSettingsPanelComponent extends PageComponent implements OnInit { + + @Input() + colorSettings: ColorSettings; + + @Input() + popover: TbPopoverComponent; + + @Output() + colorSettingsApplied = new EventEmitter(); + + colorType = ColorType; + + colorTypes = Object.keys(ColorType) as ColorType[]; + + colorTypeTranslationsMap = colorTypeTranslations; + + colorSettingsFormGroup: UntypedFormGroup; + + functionScopeVariables = this.widgetService.getWidgetScopeVariables(); + + constructor(private fb: UntypedFormBuilder, + private widgetService: WidgetService, + protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.colorSettingsFormGroup = this.fb.group( + { + type: [this.colorSettings?.type, []], + color: [this.colorSettings?.color, []], + rangeList: this.fb.array((this.colorSettings?.rangeList || []).map(r => this.colorRangeControl(r))), + colorFunction: [this.colorSettings?.colorFunction, []] + } + ); + this.colorSettingsFormGroup.get('type').valueChanges.subscribe(() => { + setTimeout(() => {this.popover?.updatePosition();}, 0); + }); + } + + private colorRangeControl(range: ColorRange): AbstractControl { + return this.fb.group({ + from: [range?.from, []], + to: [range?.to, []], + color: [range?.color, []] + }); + } + + get rangeListFormArray(): UntypedFormArray { + return this.colorSettingsFormGroup.get('rangeList') as UntypedFormArray; + } + + get rangeListFormGroups(): FormGroup[] { + return this.rangeListFormArray.controls as FormGroup[]; + } + + trackByRange(index: number, rangeControl: AbstractControl): any { + return rangeControl; + } + + removeRange(index: number) { + this.rangeListFormArray.removeAt(index); + setTimeout(() => {this.popover?.updatePosition();}, 0); + } + + addRange() { + const newRange: ColorRange = { + color: 'rgba(0,0,0,0.87)' + }; + this.rangeListFormArray.push(this.colorRangeControl(newRange), {emitEvent: true}); + setTimeout(() => {this.popover?.updatePosition();}, 0); + } + + cancel() { + this.popover?.hide(); + } + + applyColorSettings() { + const colorSettings = this.colorSettingsFormGroup.value; + this.colorSettingsApplied.emit(colorSettings); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.html new file mode 100644 index 0000000000..3c058113e1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.html @@ -0,0 +1,30 @@ + + + +
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts new file mode 100644 index 0000000000..bffad41080 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts @@ -0,0 +1,124 @@ +/// +/// Copyright © 2016-2023 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, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ColorSettings, ColorType, ComponentStyle } from '@home/components/widget/config/widget-settings.models'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { + ColorSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/color-settings-panel.component'; + +@Component({ + selector: 'tb-color-settings', + templateUrl: './color-settings.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ColorSettingsComponent), + multi: true + } + ] +}) +export class ColorSettingsComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + colorType = ColorType; + + modelValue: ColorSettings; + + colorStyle: ComponentStyle = {}; + + private propagateChange = null; + + constructor(private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + this.updateColorStyle(); + } + + writeValue(value: ColorSettings): void { + this.modelValue = value; + this.updateColorStyle(); + } + + openColorSettingsPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + colorSettings: this.modelValue + }; + const colorSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, ColorSettingsPanelComponent, 'left', true, null, + ctx, + {}, + {}, {}, true); + colorSettingsPanelPopover.tbComponentRef.instance.popover = colorSettingsPanelPopover; + colorSettingsPanelPopover.tbComponentRef.instance.colorSettingsApplied.subscribe((colorSettings) => { + colorSettingsPanelPopover.hide(); + this.modelValue = colorSettings; + this.updateColorStyle(); + this.propagateChange(this.modelValue); + }); + } + } + + private updateColorStyle() { + if (!this.disabled) { + let colors: string[] = [this.modelValue.color]; + if (this.modelValue.type === ColorType.range && this.modelValue.rangeList?.length) { + const rangeColors = this.modelValue.rangeList.slice(0, Math.min(2, this.modelValue.rangeList.length)).map(r => r.color); + colors = colors.concat(rangeColors); + } + if (colors.length === 1) { + this.colorStyle = {backgroundColor: colors[0]}; + } else { + const gradientValues: string[] = []; + const step = 100 / colors.length; + for (let i = 0; i < colors.length; i++) { + gradientValues.push(`${colors[i]} ${step*i}%`); + gradientValues.push(`${colors[i]} ${step*(i+1)}%`); + } + this.colorStyle = {background: `linear-gradient(90deg, ${gradientValues.join(', ')})`}; + } + } else { + this.colorStyle = {}; + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html new file mode 100644 index 0000000000..8cf2e4e9e3 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html @@ -0,0 +1,95 @@ + +
+
widgets.widget-font.font-settings
+
+
widgets.widget-font.size
+
+ + + + + + {{ cssUnit }} + + +
+
+
+
widgets.widget-font.font-family
+ + + + + + + + + +
+
+
widgets.widget-font.font-weight
+ + + + {{ fontWeightTranslationsMap.has(weight) ? (fontWeightTranslationsMap.get(weight) | translate) : weight }} + + + +
+
+
widgets.widget-font.font-style
+ + + + {{ fontStyleTranslationsMap.get(style) | translate }} + + + +
+ +
+
widgets.widget-font.preview
+
{{ previewText }}
+
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.scss new file mode 100644 index 0000000000..3475a14e8c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.scss @@ -0,0 +1,51 @@ +/** + * Copyright © 2016-2023 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. + */ +.tb-font-settings-panel { + width: 100%; + display: flex; + flex-direction: column; + gap: 16px; + .tb-font-settings-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-form-row { + .fixed-title-width { + min-width: 120px; + } + &.font-preview { + align-items: flex-start; + .preview-text { + max-height: 300px; + max-width: 400px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + } + .tb-font-settings-panel-buttons { + height: 60px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts new file mode 100644 index 0000000000..9369167746 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts @@ -0,0 +1,136 @@ +/// +/// Copyright © 2016-2023 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, + ElementRef, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { + commonFonts, + ComponentStyle, + cssUnits, + Font, + fontStyles, + fontStyleTranslations, + fontWeights, + fontWeightTranslations, + textStyle +} from '@home/components/widget/config/widget-settings.models'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { Observable } from 'rxjs'; +import { map, startWith, tap } from 'rxjs/operators'; + +@Component({ + selector: 'tb-font-settings-panel', + templateUrl: './font-settings-panel.component.html', + providers: [], + styleUrls: ['./font-settings-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class FontSettingsPanelComponent extends PageComponent implements OnInit { + + @Input() + font: Font; + + @Input() + previewText = 'AaBbCcDd'; + + @Input() + popover: TbPopoverComponent; + + @Output() + fontApplied = new EventEmitter(); + + @ViewChild('familyInput', {static: true}) familyInput: ElementRef; + + cssUnitsList = cssUnits; + + fontWeightsList = fontWeights; + + fontWeightTranslationsMap = fontWeightTranslations; + + fontStylesList = fontStyles; + + fontStyleTranslationsMap = fontStyleTranslations; + + fontFormGroup: UntypedFormGroup; + + filteredFontFamilies: Observable>; + + familySearchText = ''; + + previewStyle: ComponentStyle = {}; + + constructor(private fb: UntypedFormBuilder, + protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.fontFormGroup = this.fb.group( + { + size: [this.font?.size, [Validators.required, Validators.min(0)]], + sizeUnit: [this.font?.sizeUnit, [Validators.required]], + family: [this.font?.family, [Validators.required]], + weight: [this.font?.weight, [Validators.required]], + style: [this.font?.style, [Validators.required]] + } + ); + if (this.font) { + this.previewStyle = textStyle(this.font, '1'); + } + this.fontFormGroup.valueChanges.subscribe((value: Font) => { + if (this.fontFormGroup.valid) { + this.previewStyle = textStyle(value, '1'); + setTimeout(() => {this.popover?.updatePosition();}, 0); + } + }); + this.filteredFontFamilies = this.fontFormGroup.get('family').valueChanges + .pipe( + startWith(''), + tap((searchText) => { this.familySearchText = searchText || ''; }), + map(() => commonFonts.filter(f => f.toUpperCase().includes(this.familySearchText.toUpperCase()))) + ); + } + + clearFamily() { + this.fontFormGroup.get('family').patchValue(null, {emitEvent: true}); + setTimeout(() => { + this.familyInput.nativeElement.blur(); + this.familyInput.nativeElement.focus(); + }, 0); + } + + cancel() { + this.popover?.hide(); + } + + applyFont() { + const font = this.fontFormGroup.value; + this.fontApplied.emit(font); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.html new file mode 100644 index 0000000000..574ce98c1d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.html @@ -0,0 +1,25 @@ + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts new file mode 100644 index 0000000000..fdeccb1f15 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts @@ -0,0 +1,102 @@ +/// +/// Copyright © 2016-2023 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, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Font } from '@home/components/widget/config/widget-settings.models'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { FontSettingsPanelComponent } from '@home/components/widget/lib/settings/common/font-settings-panel.component'; +import { isDefinedAndNotNull } from '@core/utils'; + +@Component({ + selector: 'tb-font-settings', + templateUrl: './font-settings.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => FontSettingsComponent), + multi: true + } + ] +}) +export class FontSettingsComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + @Input() + previewText: string | (() => string); + + private modelValue: Font; + + private propagateChange = null; + + constructor(private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + writeValue(value: Font): void { + this.modelValue = value; + } + + openFontSettingsPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + font: this.modelValue + }; + if (isDefinedAndNotNull(this.previewText)) { + const previewText = typeof this.previewText === 'string' ? this.previewText : this.previewText(); + if (previewText) { + ctx.previewText = previewText; + } + } + const fontSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, FontSettingsPanelComponent, 'left', true, null, + ctx, + {}, + {}, {}, true); + fontSettingsPanelPopover.tbComponentRef.instance.popover = fontSettingsPanelPopover; + fontSettingsPanelPopover.tbComponentRef.instance.fontApplied.subscribe((font) => { + fontSettingsPanelPopover.hide(); + this.modelValue = font; + this.propagateChange(this.modelValue); + }); + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html new file mode 100644 index 0000000000..eb2bbd6711 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html @@ -0,0 +1,43 @@ + +
+ + +
+
{{ label }}
+ + + {{ expanded ? 'expand_less' : 'expand_more' }} + +
+
+ + + +
+
+
{{ option.name }}
+
+ +
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.scss new file mode 100644 index 0000000000..37c06ed239 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.scss @@ -0,0 +1,116 @@ +/** + * Copyright © 2016-2023 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. + */ +.tb-image-cards-select.tb-form-panel { + .tb-form-row { + transition: all .3s; + &.expanded { + padding: 11px 7px 11px 16px; + } + } + .tb-image-cards-value-field { + cursor: pointer; + user-select: none; + input { + cursor: pointer; + pointer-events: none; + } + } + .mat-expansion-panel { + &.tb-settings { + > .mat-expansion-panel-header { + height: auto; + .mat-content { + margin: 0; + } + .tb-form-row { + font-weight: normal; + font-size: 16px; + color: rgba(0, 0, 0, 0.87); + } + .mat-expansion-indicator { + display: none; + } + } + > .mat-expansion-panel-content { + > .mat-expansion-panel-body { + padding: 0 16px 16px !important; + } + } + } + } + .tb-image-cards-option { + width: 100%; + height: 100%; + cursor: pointer; + padding: 8px 12px 12px 12px; + display: flex; + flex-direction: column; + gap: 8px; + align-items: start; + position: relative; + .tb-image-cards-option-background { + border-radius: 4px; + position: absolute; + top: 1px; + left: 1px; + right: 1px; + bottom: 1px; + background: rgba(0, 0, 0, 0.04); + } + &:before { + content: unset; + border-radius: 4px; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + .tb-image-cards-option-title { + z-index: 1; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.54); + } + .tb-image-cards-option-image-container { + z-index: 1; + flex: 1; + width: 100%; + min-height: 0; + display: flex; + justify-content: center; + } + &.selected { + .tb-image-cards-option-background { + background: #305680; + opacity: 0.04; + } + &:before { + content: ""; + border: 1px solid #305680; + opacity: 0.32; + } + .tb-image-cards-option-title { + font-size: 13px; + font-weight: 500; + color: #305680; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts new file mode 100644 index 0000000000..e538653703 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts @@ -0,0 +1,190 @@ +/// +/// Copyright © 2016-2023 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 { + AfterContentInit, + Component, + ContentChildren, + Directive, + ElementRef, + forwardRef, + Input, + OnDestroy, OnInit, + QueryList, + ViewEncapsulation +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { Observable, Subject } from 'rxjs'; +import { map, share, startWith, takeUntil } from 'rxjs/operators'; +import { BreakpointObserver } from '@angular/cdk/layout'; +import { MediaBreakpoints } from '@shared/models/constants'; + +export interface ImageCardsSelectOption { + name: string; + value: any; + image: string; +} + +@Directive( + { + // eslint-disable-next-line @angular-eslint/directive-selector + selector: 'tb-image-cards-select-option', + } +) +export class ImageCardsSelectOptionDirective { + + @Input() value: any; + + @Input() image: string; + + get viewValue(): string { + return (this._element?.nativeElement.textContent || '').trim(); + } + + constructor( + private _element: ElementRef + ) {} +} + +@Component({ + selector: 'tb-image-cards-select', + templateUrl: './image-cards-select.component.html', + styleUrls: ['./image-cards-select.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => ImageCardsSelectComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None +}) +export class ImageCardsSelectComponent implements ControlValueAccessor, OnInit, AfterContentInit, OnDestroy { + + @ContentChildren(ImageCardsSelectOptionDirective) imageCardsSelectOptions: QueryList; + + @Input() + @coerceBoolean() + disabled: boolean; + + @Input() + cols = 4; + + @Input() + colsLtMd = 2; + + @Input() + rowHeight = '9:5'; + + @Input() + label: string; + + valueFormControl: UntypedFormControl; + + options: ImageCardsSelectOption[] = []; + + modelValue: any; + + expanded = false; + + cols$: Observable; + + private propagateChange = null; + + private _destroyed = new Subject(); + + constructor(private breakpointObserver: BreakpointObserver) { + this.valueFormControl = new UntypedFormControl(''); + } + + ngOnInit(): void { + const gridColumns = this.breakpointObserver.isMatched(MediaBreakpoints['lt-md']) ? this.colsLtMd : this.cols; + this.cols$ = this.breakpointObserver + .observe(MediaBreakpoints['lt-md']).pipe( + map((state) => state.matches ? this.colsLtMd : this.cols), + startWith(gridColumns), + share() + ); + } + + ngAfterContentInit(): void { + this.imageCardsSelectOptions.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => { + this.syncImageCardsSelectOptions(); + }); + } + + ngOnDestroy() { + this._destroyed.next(); + this._destroyed.complete(); + } + + private syncImageCardsSelectOptions() { + if (this.imageCardsSelectOptions?.length) { + this.options.length = 0; + this.imageCardsSelectOptions.forEach(option => { + this.options.push( + { name: option.viewValue, + value: option.value, + image: option.image + } + ); + }); + this.updateDisplayValue(); + } + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.valueFormControl.disable(); + } else { + this.valueFormControl.enable(); + } + } + + writeValue(value: any): void { + this.modelValue = value; + this.updateDisplayValue(); + } + + updateModel(value: any) { + this.modelValue = value; + this.updateDisplayValue(); + this.propagateChange(this.modelValue); + this.expanded = false; + } + + toggleSelectPanel($event: Event) { + $event.stopPropagation(); + if (!this.disabled) { + this.expanded = !this.expanded; + } + } + + private updateDisplayValue() { + const currentOption = this.options.find(o => o.value === this.modelValue); + const displayValue = currentOption ? currentOption.name : ''; + this.valueFormControl.patchValue(displayValue, {emitEvent: false}); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index 2dae32a922..1a9834dd91 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -266,6 +266,16 @@ import { QuickLinksWidgetSettingsComponent } from '@home/components/widget/lib/settings/home-page/quick-links-widget-settings.component'; import { LegendConfigComponent } from '@home/components/widget/lib/settings/common/legend-config.component'; +import { + ImageCardsSelectOptionDirective, + ImageCardsSelectComponent +} from '@home/components/widget/lib/settings/common/image-cards-select.component'; +import { FontSettingsComponent } from '@home/components/widget/lib/settings/common/font-settings.component'; +import { FontSettingsPanelComponent } from '@home/components/widget/lib/settings/common/font-settings-panel.component'; +import { ColorSettingsComponent } from '@home/components/widget/lib/settings/common/color-settings.component'; +import { + ColorSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/color-settings-panel.component'; @NgModule({ declarations: [ @@ -367,7 +377,13 @@ import { LegendConfigComponent } from '@home/components/widget/lib/settings/comm RouteMapWidgetSettingsComponent, TripAnimationWidgetSettingsComponent, DocLinksWidgetSettingsComponent, - QuickLinksWidgetSettingsComponent + QuickLinksWidgetSettingsComponent, + ImageCardsSelectOptionDirective, + ImageCardsSelectComponent, + FontSettingsComponent, + FontSettingsPanelComponent, + ColorSettingsComponent, + ColorSettingsPanelComponent ], imports: [ CommonModule, @@ -473,7 +489,13 @@ import { LegendConfigComponent } from '@home/components/widget/lib/settings/comm RouteMapWidgetSettingsComponent, TripAnimationWidgetSettingsComponent, DocLinksWidgetSettingsComponent, - QuickLinksWidgetSettingsComponent + QuickLinksWidgetSettingsComponent, + ImageCardsSelectOptionDirective, + ImageCardsSelectComponent, + FontSettingsComponent, + FontSettingsPanelComponent, + ColorSettingsComponent, + ColorSettingsPanelComponent ] }) export class WidgetSettingsModule { 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 e3ff270197..b622aeaa83 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 @@ -540,6 +540,12 @@ export class WidgetComponentService { if (isUndefined(result.typeParameters.processNoDataByWidget)) { result.typeParameters.processNoDataByWidget = false; } + if (isUndefined(result.typeParameters.previewWidth)) { + result.typeParameters.previewWidth = '100%'; + } + if (isUndefined(result.typeParameters.previewHeight)) { + result.typeParameters.previewHeight = '70%'; + } if (isFunction(widgetTypeInstance.actionSources)) { result.actionSources = widgetTypeInstance.actionSources(); } else { 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 ce2e7055cc..9b53bd96a4 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 @@ -43,6 +43,7 @@ import { HomePageWidgetsModule } from '@home/components/widget/lib/home-page/hom import { WIDGET_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; import { FlotWidgetComponent } from '@home/components/widget/lib/flot-widget.component'; import { LegendComponent } from '@home/components/widget/lib/legend.component'; +import { ValueCardWidgetComponent } from '@home/components/widget/lib/cards/value-card-widget.component'; @NgModule({ declarations: @@ -66,7 +67,8 @@ import { LegendComponent } from '@home/components/widget/lib/legend.component'; MarkdownWidgetComponent, SelectEntityDialogComponent, LegendComponent, - FlotWidgetComponent + FlotWidgetComponent, + ValueCardWidgetComponent ], imports: [ CommonModule, @@ -94,7 +96,8 @@ import { LegendComponent } from '@home/components/widget/lib/legend.component'; QrCodeWidgetComponent, MarkdownWidgetComponent, LegendComponent, - FlotWidgetComponent + FlotWidgetComponent, + ValueCardWidgetComponent ], providers: [ {provide: WIDGET_COMPONENTS_MODULE_TOKEN, useValue: WidgetComponentsModule } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html index 23082a121b..6601aa96db 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html @@ -41,7 +41,7 @@ matTooltipClass="tb-tooltip-multiline" matTooltipPosition="above" class="mat-subtitle-1 title"> - {{widget.titleIcon}} + {{widget.titleIcon}} {{widget.customTranslatedTitle}} - {{ action.icon }} + {{ action.icon }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss index 4c7264ce29..a364189372 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss @@ -82,7 +82,7 @@ div.tb-widget { margin: 0 !important; line-height: 20px; - mat-icon { + .mat-icon { width: 20px; min-width: 20px; height: 20px; diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts index bf7042d233..c022015c8f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts @@ -15,6 +15,7 @@ /// import { + AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, @@ -62,7 +63,7 @@ export class WidgetComponentAction { encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush }) -export class WidgetContainerComponent extends PageComponent implements OnInit, OnDestroy { +export class WidgetContainerComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy { @HostBinding('class') widgetContainerClass = 'tb-widget-container'; @@ -131,6 +132,10 @@ export class WidgetContainerComponent extends PageComponent implements OnInit, O } } + ngAfterViewInit(): void { + this.widget.widgetContext.$widgetElement = $(this.tbWidgetElement.nativeElement); + } + ngOnDestroy(): void { if (this.cssClass) { const el = this.document.getElementById(this.cssClass); diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html index 9b6c683953..74ba76bae1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.html @@ -16,6 +16,8 @@ --> ) { diff --git a/ui-ngx/src/app/modules/home/menu/menu-link.component.html b/ui-ngx/src/app/modules/home/menu/menu-link.component.html index ab5b1faa27..0efc34a31c 100644 --- a/ui-ngx/src/app/modules/home/menu/menu-link.component.html +++ b/ui-ngx/src/app/modules/home/menu/menu-link.component.html @@ -16,7 +16,6 @@ --> - {{section.icon}} - + {{section.icon}} {{section.name | translate}} diff --git a/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html b/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html index de4f16b163..448c67a513 100644 --- a/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html +++ b/ui-ngx/src/app/modules/home/menu/menu-toggle.component.html @@ -16,8 +16,7 @@ --> - {{section.icon}} - + {{section.icon}} {{section.name | translate}} diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index e9787260bb..5f994e4fdc 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -446,7 +446,10 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { this.titleIconStyle.color = this.widget.config.iconColor; } if (this.widget.config.iconSize) { + this.titleIconStyle.width = this.widget.config.iconSize; + this.titleIconStyle.height = this.widget.config.iconSize; this.titleIconStyle.fontSize = this.widget.config.iconSize; + this.titleIconStyle.lineHeight = this.widget.config.iconSize; } this.dropShadow = isDefined(this.widget.config.dropShadow) ? this.widget.config.dropShadow : true; diff --git a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts index e9fb01c54a..bcd8e793b3 100644 --- a/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts +++ b/ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts @@ -75,7 +75,6 @@ export interface GroupActionDescriptor> { export interface HeaderActionDescriptor { name: string; icon: string; - isMdiIcon?: boolean; isEnabled: () => boolean; onAction: ($event: MouseEvent) => void; } diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index c00d0a8e82..b16e880e02 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -243,6 +243,7 @@ export class WidgetContext { formatValue }; + $widgetElement: JQuery; $container: JQuery; $containerParent: JQuery; width: number; diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts index adc87a7886..5748cc63a6 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts @@ -319,8 +319,7 @@ const routes: Routes = [ title: 'admin.2fa.2fa', breadcrumb: { label: 'admin.2fa.2fa', - icon: 'mdi:two-factor-authentication', - isMdiIcon: true + icon: 'mdi:two-factor-authentication' } } }, diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html index 23619e2632..521f54f53d 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html +++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.html @@ -27,8 +27,7 @@ - {{place.icon}} - + {{place.icon}} {{place.name}} diff --git a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.scss b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.scss index a30605652b..9acc1490ba 100644 --- a/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.scss +++ b/ui-ngx/src/app/modules/home/pages/home-links/home-links.component.scss @@ -55,7 +55,7 @@ display: flex; flex-direction: column; align-items: center; - mat-icon { + .mat-icon { margin: auto; } span.mdc-button__label { diff --git a/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.html b/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.html index d15e8fbe1f..531d9d3cfe 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.html @@ -34,13 +34,9 @@
diff --git a/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.scss index 7de71586fa..d289574f15 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/widget/select-widget-type-dialog.component.scss @@ -21,7 +21,7 @@ display: flex; flex-direction: column; align-items: center; - mat-icon { + .mat-icon { margin: auto; } span.mdc-button__label { diff --git a/ui-ngx/src/app/shared/components/breadcrumb.component.html b/ui-ngx/src/app/shared/components/breadcrumb.component.html index be7f1e6b16..594578465f 100644 --- a/ui-ngx/src/app/shared/components/breadcrumb.component.html +++ b/ui-ngx/src/app/shared/components/breadcrumb.component.html @@ -37,11 +37,9 @@
- - - + {{ breadcrumb.icon }} - + {{ breadcrumb.ignoreTranslate ? (breadcrumb.labelFunction ? breadcrumb.labelFunction() : utils.customTranslation(breadcrumb.label, breadcrumb.label)) : (breadcrumb.label | translate) }} diff --git a/ui-ngx/src/app/shared/components/breadcrumb.component.ts b/ui-ngx/src/app/shared/components/breadcrumb.component.ts index 2542f58871..380ddc59ce 100644 --- a/ui-ngx/src/app/shared/components/breadcrumb.component.ts +++ b/ui-ngx/src/app/shared/components/breadcrumb.component.ts @@ -117,7 +117,6 @@ export class BreadcrumbComponent implements OnInit, OnDestroy { ignoreTranslate = false; } const icon = breadcrumbConfig.icon || 'home'; - const isMdiIcon = icon.startsWith('mdi:'); const link = [ route.pathFromRoot.map(v => v.url.map(segment => segment.toString()).join('/')).join('/') ]; const breadcrumb = { id: guid(), @@ -125,7 +124,6 @@ export class BreadcrumbComponent implements OnInit, OnDestroy { labelFunction, ignoreTranslate, icon, - isMdiIcon, link, queryParams: null }; diff --git a/ui-ngx/src/app/shared/components/breadcrumb.ts b/ui-ngx/src/app/shared/components/breadcrumb.ts index 599f8b85e8..77a832dbed 100644 --- a/ui-ngx/src/app/shared/components/breadcrumb.ts +++ b/ui-ngx/src/app/shared/components/breadcrumb.ts @@ -23,7 +23,6 @@ export interface BreadCrumb extends HasUUID{ labelFunction?: () => string; ignoreTranslate: boolean; icon: string; - isMdiIcon: boolean; link: any[]; queryParams: Params; } diff --git a/ui-ngx/src/app/shared/components/color-input.component.html b/ui-ngx/src/app/shared/components/color-input.component.html index c027104c6e..68ec5854f2 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.html +++ b/ui-ngx/src/app/shared/components/color-input.component.html @@ -37,12 +37,12 @@ diff --git a/ui-ngx/src/app/shared/components/color-input.component.scss b/ui-ngx/src/app/shared/components/color-input.component.scss index b81ac0fdf8..2660c16dc8 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.scss +++ b/ui-ngx/src/app/shared/components/color-input.component.scss @@ -32,10 +32,4 @@ margin: 0; } } - button.mat-mdc-button-base.color-box { - width: 40px; - min-width: 40px; - height: 40px; - padding: 7px; - } } diff --git a/ui-ngx/src/app/shared/components/icon.component.ts b/ui-ngx/src/app/shared/components/icon.component.ts new file mode 100644 index 0000000000..d1e2c6ddcd --- /dev/null +++ b/ui-ngx/src/app/shared/components/icon.component.ts @@ -0,0 +1,281 @@ +/// +/// Copyright © 2016-2023 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 { CanColor, mixinColor } from '@angular/material/core'; +import { + AfterContentInit, + AfterViewChecked, + ChangeDetectionStrategy, + Component, + ElementRef, + ErrorHandler, + Inject, + OnDestroy, + Renderer2, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { MAT_ICON_LOCATION, MatIconLocation, MatIconRegistry } from '@angular/material/icon'; +import { Subscription } from 'rxjs'; +import { take } from 'rxjs/operators'; +import { isSvgIcon, splitIconName } from '@shared/models/icon.models'; +import { ContentObserver } from '@angular/cdk/observers'; + +const _TbIconBase = mixinColor( + class { + constructor(public _elementRef: ElementRef) {} + }, +); + +const funcIriAttributes = [ + 'clip-path', + 'color-profile', + 'src', + 'cursor', + 'fill', + 'filter', + 'marker', + 'marker-start', + 'marker-mid', + 'marker-end', + 'mask', + 'stroke', +]; + +const funcIriAttributeSelector = funcIriAttributes.map(attr => `[${attr}]`).join(', '); + +const funcIriPattern = /^url\(['"]?#(.*?)['"]?\)$/; + +@Component({ + template: '', + selector: 'tb-icon', + exportAs: 'tbIcon', + styleUrls: [], + // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property + inputs: ['color'], + // eslint-disable-next-line @angular-eslint/no-host-metadata-property + host: { + role: 'img', + class: 'mat-icon notranslate', + '[attr.data-mat-icon-type]': '!_useSvgIcon ? "font" : "svg"', + '[attr.data-mat-icon-name]': '_svgName', + '[attr.data-mat-icon-namespace]': '_svgNamespace', + '[class.mat-icon-no-color]': 'color !== "primary" && color !== "accent" && color !== "warn"', + }, + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TbIconComponent extends _TbIconBase + implements AfterContentInit, AfterViewChecked, CanColor, OnDestroy { + + @ViewChild('iconNameContent', {static: true}) + _iconNameContent: ElementRef; + + private icon: string; + + get viewValue(): string { + return (this._iconNameContent?.nativeElement.textContent || '').trim(); + } + + private _contentChanges: Subscription = null; + private _previousFontSetClass: string[] = []; + + _useSvgIcon = false; + _svgName: string | null; + _svgNamespace: string | null; + + private _textElement = null; + + private _previousPath?: string; + + private _elementsWithExternalReferences?: Map; + + private _currentIconFetch = Subscription.EMPTY; + + constructor(elementRef: ElementRef, + private contentObserver: ContentObserver, + private renderer: Renderer2, + private _iconRegistry: MatIconRegistry, + @Inject(MAT_ICON_LOCATION) private _location: MatIconLocation, + private readonly _errorHandler: ErrorHandler) { + super(elementRef); + } + + ngAfterContentInit(): void { + this.icon = this.viewValue; + this._updateIcon(); + this._contentChanges = this.contentObserver.observe(this._iconNameContent.nativeElement) + .subscribe(() => { + const content = this.viewValue; + if (content && this.icon !== content) { + this.icon = content; + this._updateIcon(); + } + }); + } + + ngAfterViewChecked() { + const cachedElements = this._elementsWithExternalReferences; + if (cachedElements && cachedElements.size) { + const newPath = this._location.getPathname(); + if (newPath !== this._previousPath) { + this._previousPath = newPath; + this._prependPathToReferences(newPath); + } + } + } + + ngOnDestroy() { + this._contentChanges.unsubscribe(); + this._currentIconFetch.unsubscribe(); + if (this._elementsWithExternalReferences) { + this._elementsWithExternalReferences.clear(); + } + } + + private _updateIcon() { + const useSvgIcon = isSvgIcon(this.icon); + if (this._useSvgIcon !== useSvgIcon) { + this._useSvgIcon = useSvgIcon; + if (!this._useSvgIcon) { + this._updateSvgIcon(undefined); + } else { + this._updateFontIcon(undefined); + } + } + if (this._useSvgIcon) { + this._updateSvgIcon(this.icon); + } else { + this._updateFontIcon(this.icon); + } + } + + private _updateFontIcon(rawName: string | undefined) { + if (rawName) { + this._clearFontIcon(); + const iconName = splitIconName(rawName)[1]; + this._textElement = this.renderer.createText(iconName); + const elem: HTMLElement = this._elementRef.nativeElement; + this.renderer.insertBefore(elem, this._textElement, this._iconNameContent.nativeElement); + const fontSetClasses = ( + this._iconRegistry.getDefaultFontSetClass() + ).filter(className => className.length > 0); + fontSetClasses.forEach(className => elem.classList.add(className)); + this._previousFontSetClass = fontSetClasses; + } else { + this._clearFontIcon(); + } + } + + private _clearFontIcon() { + const elem: HTMLElement = this._elementRef.nativeElement; + if (this._textElement !== null) { + this.renderer.removeChild(elem, this._textElement); + this._textElement = null; + } + this._previousFontSetClass.forEach(className => elem.classList.remove(className)); + this._previousFontSetClass = []; + } + + private _updateSvgIcon(rawName: string | undefined) { + this._svgNamespace = null; + this._svgName = null; + this._currentIconFetch.unsubscribe(); + + if (rawName) { + const [namespace, iconName] = splitIconName(rawName); + if (namespace) { + this._svgNamespace = namespace; + } + if (iconName) { + this._svgName = iconName; + } + this._iconRegistry.getDefaultFontSetClass(); + this._currentIconFetch = this._iconRegistry + .getNamedSvgIcon(iconName, namespace) + .pipe(take(1)) + .subscribe({ + next: (svg) => this._setSvgElement(svg), + error: (err: Error) => { + const errorMessage = `Error retrieving icon ${namespace}:${iconName}! ${err.message}`; + this._errorHandler.handleError(new Error(errorMessage)); + } + }); + } else { + this._clearSvgElement(); + } + } + + private _setSvgElement(svg: SVGElement) { + this._clearSvgElement(); + const path = this._location.getPathname(); + this._previousPath = path; + this._cacheChildrenWithExternalReferences(svg); + this._prependPathToReferences(path); + this.renderer.insertBefore(this._elementRef.nativeElement, svg, this._iconNameContent.nativeElement); + } + + private _clearSvgElement() { + const layoutElement: HTMLElement = this._elementRef.nativeElement; + let childCount = layoutElement.childNodes.length; + if (this._elementsWithExternalReferences) { + this._elementsWithExternalReferences.clear(); + } + while (childCount--) { + const child = layoutElement.childNodes[childCount]; + if (child.nodeType !== 1 || child.nodeName.toLowerCase() === 'svg') { + child.remove(); + } + } + } + + private _cacheChildrenWithExternalReferences(element: SVGElement) { + const elementsWithFuncIri = element.querySelectorAll(funcIriAttributeSelector); + const elements = (this._elementsWithExternalReferences = this._elementsWithExternalReferences || new Map()); + elementsWithFuncIri.forEach( + (elementWithFuncIri) => { + funcIriAttributes.forEach(attr => { + const elementWithReference = elementWithFuncIri; + const value = elementWithReference.getAttribute(attr); + const match = value ? value.match(funcIriPattern) : null; + + if (match) { + let attributes = elements.get(elementWithReference); + + if (!attributes) { + attributes = []; + elements.set(elementWithReference, attributes); + } + + attributes.push({name: attr, value: match[1]}); + } + }); + } + ); + } + + private _prependPathToReferences(path: string) { + const elements = this._elementsWithExternalReferences; + if (elements) { + elements.forEach((attrs, element) => { + attrs.forEach(attr => { + element.setAttribute(attr.name, `url('${path}#${attr.value}')`); + }); + }); + } + } + +} diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.html b/ui-ngx/src/app/shared/components/material-icon-select.component.html index 8bae8c3435..8f7aa303f9 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.html +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.html @@ -16,7 +16,7 @@ -->
- {{materialIconFormGroup.get('icon').value}} + {{materialIconFormGroup.get('icon').value}} {{ label }} @@ -24,18 +24,18 @@ type="button" matSuffix mat-icon-button aria-label="Clear" (click)="clear()"> - close + close
diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.scss b/ui-ngx/src/app/shared/components/material-icon-select.component.scss index b008fc6838..78e4d235cf 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.scss +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.scss @@ -24,21 +24,3 @@ } } } - -:host ::ng-deep { - button.mat-mdc-button-base.icon-box { - width: 40px; - min-width: 40px; - height: 40px; - padding: 7px; - &:not(:disabled) { - color: rgba(0, 0, 0, 0.87); - } - > .mat-icon { - width: 24px; - height: 24px; - font-size: 24px; - margin: 0; - } - } -} diff --git a/ui-ngx/src/app/shared/components/material-icons.component.html b/ui-ngx/src/app/shared/components/material-icons.component.html index 39404a9998..d31a73ddb5 100644 --- a/ui-ngx/src/app/shared/components/material-icons.component.html +++ b/ui-ngx/src/app/shared/components/material-icons.component.html @@ -39,7 +39,7 @@ matTooltip="{{ icon.displayName }}" matTooltipPosition="above" type="button"> - {{icon.name}} + {{icon.name}}
diff --git a/ui-ngx/src/app/shared/components/notification/notification.component.html b/ui-ngx/src/app/shared/components/notification/notification.component.html index b9ce3a840f..ba6091eebc 100644 --- a/ui-ngx/src/app/shared/components/notification/notification.component.html +++ b/ui-ngx/src/app/shared/components/notification/notification.component.html @@ -18,14 +18,14 @@
- + {{ notification.additionalConfig.icon.icon }} - +
- + {{ notificationTypeIcons.get(notification.type) }} - +
diff --git a/ui-ngx/src/app/shared/components/public-api.ts b/ui-ngx/src/app/shared/components/public-api.ts index 04508266e9..35ab83900e 100644 --- a/ui-ngx/src/app/shared/components/public-api.ts +++ b/ui-ngx/src/app/shared/components/public-api.ts @@ -27,3 +27,4 @@ export * from './toggle-header.component'; export * from './toggle-select.component'; export * from './unit-input.component'; export * from './material-icons.component'; +export * from './icon.component'; diff --git a/ui-ngx/src/app/shared/models/icon.models.ts b/ui-ngx/src/app/shared/models/icon.models.ts index 48b643d235..8d7d4f65bd 100644 --- a/ui-ngx/src/app/shared/models/icon.models.ts +++ b/ui-ngx/src/app/shared/models/icon.models.ts @@ -19,6 +19,66 @@ import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { isNotEmptyStr } from '@core/utils'; +export const svgIcons: {[key: string]: string} = { + 'google-logo': '', + 'github-logo': '', + 'facebook-logo': '', + 'apple-logo': '', + 'queues-list': '' + + '' + + '' + + '' + + '' +}; + +const svgIconNamespaces: string[] = ['mdi']; +const svgIconNames = Object.keys(svgIcons); + +export const splitIconName = (iconName: string): [string, string] => { + if (!iconName) { + return ['', '']; + } + const parts = iconName.split(':'); + switch (parts.length) { + case 1: + return ['', parts[0]]; + case 2: + return parts as [string, string]; + default: + throw Error(`Invalid icon name: "${iconName}"`); + } +}; + +export const isSvgIcon = (icon: string): boolean => { + const [namespace, iconName] = splitIconName(icon); + return svgIconNamespaces.includes(namespace) || svgIconNames.includes(iconName); +}; + export interface MaterialIcon { name: string; displayName?: string; @@ -43,7 +103,8 @@ export const getMaterialIcons = (resourcesService: ResourcesService, chunkSize resourcesService.loadJsonResource>('/assets/metadata/material-icons.json', (icons) => { for (const icon of icons) { - const words = icon.name.replace(/_/g, ' ').split(' '); + const iconName = splitIconName(icon.name)[1]; + const words = iconName.replace(/[_\-]/g, ' ').split(' '); for (let i = 0; i < words.length; i++) { words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1); } diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index de4c5332f7..716a4cf8b4 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -57,7 +57,6 @@ export interface WidgetTypeTemplate { export interface WidgetTypeData { name: string; icon: string; - isMdiIcon?: boolean; configHelpLinkId: string; template: WidgetTypeTemplate; } @@ -94,7 +93,6 @@ export const widgetTypesData = new Map( name: 'widget.rpc', icon: 'mdi:developer-board', configHelpLinkId: 'widgetsConfigRpc', - isMdiIcon: true, template: { bundleAlias: 'gpio_widgets', alias: 'basic_gpio_control' @@ -182,6 +180,8 @@ export interface WidgetTypeParameters { warnOnPageDataOverflow?: boolean; ignoreDataUpdateOnIntervalTick?: boolean; processNoDataByWidget?: boolean; + previewWidth?: string; + previewHeight?: string; } export interface WidgetControllerDescriptor { diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 11c4b4effb..88d21fd0c5 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -197,6 +197,7 @@ import { ToggleSelectComponent } from '@shared/components/toggle-select.componen import { UnitInputComponent } from '@shared/components/unit-input.component'; import { MaterialIconsComponent } from '@shared/components/material-icons.component'; import { ColorPickerPanelComponent } from '@shared/components/color-picker/color-picker-panel.component'; +import { TbIconComponent } from '@shared/components/icon.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -373,7 +374,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ToggleSelectComponent, UnitInputComponent, MaterialIconsComponent, - RuleChainSelectComponent + RuleChainSelectComponent, + TbIconComponent ], imports: [ CommonModule, @@ -606,7 +608,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ToggleSelectComponent, UnitInputComponent, MaterialIconsComponent, - RuleChainSelectComponent + RuleChainSelectComponent, + TbIconComponent ] }) export class SharedModule { } diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/card/value_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/card/value_color_fn.md new file mode 100644 index 0000000000..639043bfbc --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/card/value_color_fn.md @@ -0,0 +1,40 @@ +#### Color function + +
+
+ +*function (value): string* + +A JavaScript function used to compute a color. + +**Parameters:** + +
    +
  • value: primitive (number/string/boolean) - A value of the current datapoint. +
  • +
+ +**Returns:** + +Should return string value presenting color. + +In case no data is returned, color value from **Color** settings field will be used. + +
+ +##### Examples + +* Calculate color depending on `temperature` telemetry value: + +```javascript +var temperature = value; +if (typeof temperature !== undefined) { + var percent = (temperature + 60)/120 * 100; + return tinycolor.mix('blue', 'red', percent).toHexString(); +} +return 'blue'; +{:copy-code} +``` + +
+
diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md index 64e994fc3e..ede068d68f 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/color_fn.md @@ -31,7 +31,7 @@ if (type == 'colorpin') { var temperature = data['temperature']; if (typeof temperature !== undefined) { var percent = (temperature + 60)/120 * 100; - return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + return tinycolor.mix('blue', 'red', percent).toHexString(); } return 'blue'; } diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md index 056e47d0eb..c4df0a99a9 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_color_fn.md @@ -31,7 +31,7 @@ if (type == 'colorpin') { var temperature = data['temperature']; if (typeof temperature !== undefined) { var percent = (temperature + 60)/120 * 100; - return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + return tinycolor.mix('blue', 'red', percent).toHexString(); } return 'blue'; } diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md index 30f5e0f4d5..de092704c3 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/path_point_color_fn.md @@ -31,7 +31,7 @@ if (type == 'colorpin') { var temperature = data['temperature']; if (typeof temperature !== undefined) { var percent = (temperature + 60)/120 * 100; - return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + return tinycolor.mix('blue', 'red', percent).toHexString(); } return 'blue'; } diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md index 736bd727f0..b4cc0c5223 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/polygon_color_fn.md @@ -31,7 +31,7 @@ if (type == 'thermostat') { var temperature = data['temperature']; if (typeof temperature !== undefined) { var percent = (temperature + 60)/120 * 100; - return tinycolor.mix('blue', 'red', amount = percent).toHexString(); + return tinycolor.mix('blue', 'red', percent).toHexString(); } return 'blue'; } 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 cd379fa4dc..1a93bf03db 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4407,6 +4407,17 @@ "ticks": "Ticks", "horizontal-axis": "Horizontal axis" }, + "color": { + "color-settings": "Color settings", + "color-type-constant": "Constant", + "color-type-range": "Range", + "color-type-function": "Function", + "color": "Color", + "value-range": "Value range", + "from": "From", + "to": "To", + "color-function": "Color function" + }, "dashboard-state": { "dashboard-state-settings": "Dashboard state settings", "dashboard-state": "Dashboard state id", @@ -5216,6 +5227,16 @@ "label-position-left": "Left", "label-position-top": "Top" }, + "value-card": { + "layout": "Layout", + "layout-square": "Square", + "layout-vertical": "Vertical", + "layout-centered": "Centered", + "layout-simplified": "Simplified", + "layout-horizontal": "Horizontal", + "layout-horizontal-reversed": "Horizontal reversed", + "label": "Label" + }, "table": { "common-table-settings": "Common Table Settings", "enable-search": "Enable search", @@ -5290,6 +5311,7 @@ "source-entity-attribute": "Source entity attribute" }, "widget-font": { + "font-settings": "Font settings", "font-family": "Font family", "size": "Size", "relative-font-size": "Relative font size (percents)", @@ -5303,7 +5325,8 @@ "font-weight-bolder": "Bolder", "font-weight-lighter": "Lighter", "color": "Color", - "shadow-color": "Shadow color" + "shadow-color": "Shadow color", + "preview": "Preview" }, "home": { "no-data-available": "No data available" diff --git a/ui-ngx/src/assets/metadata/material-icons.json b/ui-ngx/src/assets/metadata/material-icons.json index 7f12a1e605..2da54c48c2 100644 --- a/ui-ngx/src/assets/metadata/material-icons.json +++ b/ui-ngx/src/assets/metadata/material-icons.json @@ -1,6367 +1 @@ -[ { - "name" : "more_horiz", - "tags" : [ "3", "DISABLE_IOS", "app", "application", "components", "disable_ios", "dots", "etc", "horiz", "horizontal", "interface", "ios", "more", "screen", "site", "three", "ui", "ux", "web", "website" ] -}, { - "name" : "more_vert", - "tags" : [ "3", "DISABLE_IOS", "android", "app", "application", "components", "disable_ios", "dots", "etc", "interface", "more", "screen", "site", "three", "ui", "ux", "vert", "vertical", "web", "website" ] -}, { - "name" : "open_in_new", - "tags" : [ "app", "application", "arrow", "box", "components", "in", "interface", "new", "open", "right", "screen", "site", "ui", "up", "ux", "web", "website", "window" ] -}, { - "name" : "visibility", - "tags" : [ "eye", "on", "reveal", "see", "show", "view", "visibility" ] -}, { - "name" : "play_arrow", - "tags" : [ "arrow", "control", "controls", "media", "music", "play", "video" ] -}, { - "name" : "arrow_back", - "tags" : [ "DISABLE_IOS", "app", "application", "arrow", "back", "components", "direction", "disable_ios", "interface", "left", "navigation", "previous", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "arrow_downward", - "tags" : [ "app", "application", "arrow", "components", "direction", "down", "downward", "interface", "navigation", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "arrow_forward", - "tags" : [ "app", "application", "arrow", "arrows", "components", "direction", "forward", "interface", "navigation", "right", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "arrow_upward", - "tags" : [ "app", "application", "arrow", "components", "direction", "interface", "navigation", "screen", "site", "ui", "up", "upward", "ux", "web", "website" ] -}, { - "name" : "close", - "tags" : [ "cancel", "close", "exit", "stop", "x" ] -}, { - "name" : "refresh", - "tags" : [ "around", "arrow", "arrows", "direction", "inprogress", "load", "loading refresh", "navigation", "refresh", "renew", "right", "rotate", "turn" ] -}, { - "name" : "menu", - "tags" : [ "app", "application", "components", "hamburger", "interface", "line", "lines", "menu", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "show_chart", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "line", "measure", "metrics", "presentation", "show chart", "statistics", "tracking" ] -}, { - "name" : "multiline_chart", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "line", "measure", "metrics", "multiple", "statistics", "tracking" ] -}, { - "name" : "pie_chart", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "pie", "statistics", "tracking" ] -}, { - "name" : "insert_chart", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "insert", "measure", "metrics", "statistics", "tracking" ] -}, { - "name" : "people", - "tags" : [ "accounts", "committee", "face", "family", "friends", "humans", "network", "people", "persons", "profiles", "social", "team", "users" ] -}, { - "name" : "person", - "tags" : [ "account", "face", "human", "people", "person", "profile", "user" ] -}, { - "name" : "domain", - "tags" : [ "apartment", "architecture", "building", "business", "domain", "estate", "home", "place", "real", "residence", "residential", "shelter", "web", "www" ] -}, { - "name" : "devices_other", - "tags" : [ "Android", "OS", "ar", "cell", "chrome", "desktop", "device", "gadget", "hardware", "iOS", "ipad", "mac", "mobile", "monitor", "other", "phone", "tablet", "vr", "watch", "wearables", "window" ] -}, { - "name" : "widgets", - "tags" : [ "app", "box", "menu", "setting", "squares", "ui", "widgets" ] -}, { - "name" : "dashboard", - "tags" : [ "cards", "dashboard", "format", "layout", "rectangle", "shapes", "square", "web", "website" ] -}, { - "name" : "map", - "tags" : [ "destination", "direction", "location", "map", "maps", "pin", "place", "route", "stop", "travel" ] -}, { - "name" : "pin_drop", - "tags" : [ "destination", "direction", "drop", "location", "maps", "navigation", "pin", "place", "stop" ] -}, { - "name" : "gps_fixed", - "tags" : [ "destination", "direction", "fixed", "gps", "location", "maps", "pin", "place", "pointer", "stop", "tracking" ] -}, { - "name" : "extension", - "tags" : [ "app", "extended", "extension", "game", "jigsaw", "plugin add", "puzzle", "shape" ] -}, { - "name" : "search", - "tags" : [ "filter", "find", "glass", "look", "magnify", "magnifying", "search", "see" ] -}, { - "name" : "settings", - "tags" : [ "application", "change", "details", "gear", "info", "information", "options", "personal", "service", "settings" ] -}, { - "name" : "notifications", - "tags" : [ "active", "alarm", "alert", "bell", "chime", "notifications", "notify", "reminder", "ring", "sound" ] -}, { - "name" : "notifications_active", - "tags" : [ "active", "alarm", "alert", "bell", "chime", "notifications", "notify", "reminder", "ring", "ringing", "sound" ] -}, { - "name" : "info", - "tags" : [ "alert", "announcement", "assistance", "details", "help", "i", "info", "information", "service", "support" ] -}, { - "name" : "error_outline", - "tags" : [ "!", "alert", "attention", "caution", "circle", "danger", "error", "exclamation", "important", "mark", "notification", "outline", "symbol", "warning" ] -}, { - "name" : "warning", - "tags" : [ "!", "alert", "attention", "caution", "danger", "error", "exclamation", "important", "mark", "notification", "symbol", "triangle", "warning" ] -}, { - "name" : "list", - "tags" : [ "file", "format", "index", "list", "menu", "options" ] -}, { - "name" : "download", - "tags" : [ "arrow", "down", "download", "downloads", "drive", "install", "upload" ] -}, { - "name" : "import_export", - "tags" : [ "arrow", "arrows", "direction", "down", "explort", "import", "up" ] -}, { - "name" : "share", - "tags" : [ "DISABLE_IOS", "android", "connect", "contect", "disable_ios", "link", "media", "multimedia", "multiple", "network", "options", "share", "shared", "sharing", "social" ] -}, { - "name" : "add", - "tags" : [ "+", "add", "new symbol", "plus", "symbol" ] -}, { - "name" : "edit", - "tags" : [ "compose", "create", "edit", "editing", "input", "new", "pen", "pencil", "write", "writing" ] -}, { - "name" : "check", - "tags" : [ "DISABLE_IOS", "check", "confirm", "correct", "disable_ios", "done", "enter", "mark", "ok", "okay", "select", "tick", "yes" ] -}, { - "name" : "delete", - "tags" : [ "bin", "can", "delete", "garbage", "remove", "trash" ] -}, { - "name" : "thermostat", - "tags" : [ "climate", "forecast", "temperature", "thermostat", "weather" ] -}, { - "name" : "air", - "tags" : [ "air", "blowing", "breeze", "flow", "wave", "weather", "wind" ] -}, { - "name" : "lightbulb", - "tags" : [ "alert", "announcement", "idea", "info", "information", "light", "lightbulb" ] -}, { - "name" : "home", - "tags" : [ "address", "app", "application--house", "architecture", "building", "components", "design", "estate", "home", "interface", "layout", "place", "real", "residence", "residential", "screen", "shelter", "site", "structure", "ui", "unit", "ux", "web", "website", "window" ] -}, { - "name" : "account_circle", - "tags" : [ "account", "avatar", "circle", "face", "human", "people", "person", "profile", "thumbnail", "user" ] -}, { - "name" : "done", - "tags" : [ "DISABLE_IOS", "approve", "check", "complete", "disable_ios", "done", "mark", "ok", "select", "tick", "validate", "verified", "yes" ] -}, { - "name" : "check_circle", - "tags" : [ "approve", "check", "circle", "complete", "done", "mark", "ok", "select", "tick", "validate", "verified", "yes" ] -}, { - "name" : "expand_more", - "tags" : [ "arrow", "arrows", "chevron", "collapse", "direction", "down", "expand", "expandable", "list", "more" ] -}, { - "name" : "shopping_cart", - "tags" : [ "add", "bill", "buy", "card", "cart", "cash", "checkout", "coin", "commerce", "credit", "currency", "dollars", "money", "online", "pay", "payment", "shopping" ] -}, { - "name" : "email", - "tags" : [ "email", "envelop", "letter", "mail", "message", "send" ] -}, { - "name" : "favorite", - "tags" : [ "appreciate", "favorite", "heart", "like", "love", "remember", "save", "shape" ] -}, { - "name" : "description", - "tags" : [ "article", "data", "description", "doc", "document", "drive", "file", "folder", "folders", "notes", "page", "paper", "sheet", "slide", "text", "writing" ] -}, { - "name" : "logout", - "tags" : [ "app", "application", "arrow", "components", "design", "exit", "interface", "leave", "log", "login", "logout", "right", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "favorite_border", - "tags" : [ "border", "favorite", "heart", "like", "love", "outline", "remember", "save", "shape" ] -}, { - "name" : "chevron_right", - "tags" : [ "arrow", "arrows", "chevron", "direction", "right" ] -}, { - "name" : "lock", - "tags" : [ "lock", "locked", "password", "privacy", "private", "protection", "safety", "secure", "security" ] -}, { - "name" : "location_on", - "tags" : [ "destination", "direction", "location", "maps", "on", "pin", "place", "room", "stop" ] -}, { - "name" : "schedule", - "tags" : [ "clock", "date", "schedule", "time" ] -}, { - "name" : "local_shipping", - "tags" : [ "automobile", "car", "cars", "delivery", "letter", "local", "mail", "maps", "office", "package", "parcel", "post", "postal", "send", "shipping", "shopping", "stamp", "transportation", "truck", "vehicle" ] -}, { - "name" : "language", - "tags" : [ "globe", "internet", "language", "planet", "website", "world", "www" ] -}, { - "name" : "call", - "tags" : [ "call", "cell", "contact", "device", "hardware", "mobile", "phone", "telephone" ] -}, { - "name" : "file_download", - "tags" : [ "arrow", "arrows", "down", "download", "downloads", "drive", "export", "file", "install", "upload" ] -}, { - "name" : "arrow_forward_ios", - "tags" : [ "app", "application", "arrow", "chevron", "components", "direction", "forward", "interface", "ios", "navigation", "next", "right", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "arrow_back_ios", - "tags" : [ "DISABLE_IOS", "app", "application", "arrow", "back", "chevron", "components", "direction", "disable_ios", "interface", "ios", "left", "navigation", "previous", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "groups", - "tags" : [ "body", "club", "collaboration", "crowd", "gathering", "groups", "human", "meeting", "people", "person", "social", "teams" ] -}, { - "name" : "cancel", - "tags" : [ "cancel", "circle", "close", "exit", "stop", "x" ] -}, { - "name" : "help_outline", - "tags" : [ "?", "assistance", "circle", "help", "info", "information", "outline", "punctuation", "question mark", "recent", "restore", "shape", "support", "symbol" ] -}, { - "name" : "arrow_drop_down", - "tags" : [ "app", "application", "arrow", "components", "direction", "down", "drop", "interface", "navigation", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "face", - "tags" : [ "account", "emoji", "eyes", "face", "human", "lock", "log", "login", "logout", "people", "person", "profile", "recognition", "security", "social", "thumbnail", "unlock", "user" ] -}, { - "name" : "manage_accounts", - "tags" : [ "accounts", "change", "details service-human", "face", "gear", "manage", "options", "people", "person", "profile", "settings", "user" ] -}, { - "name" : "place", - "tags" : [ "destination", "direction", "location", "maps", "navigation", "pin", "place", "point", "stop" ] -}, { - "name" : "verified", - "tags" : [ "approve", "badge", "burst", "check", "complete", "done", "mark", "ok", "select", "star", "tick", "validate", "verified", "yes" ] -}, { - "name" : "add_circle_outline", - "tags" : [ "+", "add", "circle", "create", "new", "outline", "plus" ] -}, { - "name" : "filter_alt", - "tags" : [ "alt", "edit", "filter", "funnel", "options", "refine", "sift" ] -}, { - "name" : "thumb_up", - "tags" : [ "favorite", "fingers", "gesture", "hand", "hands", "like", "rank", "ranking", "rate", "rating", "thumb", "up" ] -}, { - "name" : "event", - "tags" : [ "calendar", "date", "day", "event", "mark", "month", "range", "remember", "reminder", "today", "week" ] -}, { - "name" : "star", - "tags" : [ "best", "bookmark", "favorite", "highlight", "ranking", "rate", "rating", "save", "star", "toggle" ] -}, { - "name" : "fingerprint", - "tags" : [ "finger", "fingerprint", "id", "identification", "identity", "print", "reader", "thumbprint", "verification" ] -}, { - "name" : "content_copy", - "tags" : [ "content", "copy", "cut", "doc", "document", "duplicate", "file", "multiple", "past" ] -}, { - "name" : "login", - "tags" : [ "access", "app", "application", "arrow", "components", "design", "enter", "in", "interface", "left", "log", "login", "screen", "sign", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "add_circle", - "tags" : [ "+", "add", "circle", "create", "new", "plus" ] -}, { - "name" : "visibility_off", - "tags" : [ "disabled", "enabled", "eye", "off", "on", "reveal", "see", "show", "slash", "view", "visibility" ] -}, { - "name" : "check_circle_outline", - "tags" : [ "approve", "check", "circle", "complete", "done", "finished", "mark", "ok", "outline", "select", "tick", "validate", "verified", "yes" ] -}, { - "name" : "chevron_left", - "tags" : [ "DISABLE_IOS", "arrow", "arrows", "chevron", "direction", "disable_ios", "left" ] -}, { - "name" : "calendar_today", - "tags" : [ "calendar", "date", "day", "event", "month", "schedule", "today" ] -}, { - "name" : "send", - "tags" : [ "email", "mail", "message", "paper", "plane", "reply", "right", "send", "share" ] -}, { - "name" : "check_box", - "tags" : [ "approved", "box", "button", "check", "component", "control", "form", "mark", "ok", "select", "selected", "selection", "tick", "toggle", "ui", "yes" ] -}, { - "name" : "highlight_off", - "tags" : [ "cancel", "close", "exit", "highlight", "no", "off", "quit", "remove", "stop", "x" ] -}, { - "name" : "navigate_next", - "tags" : [ "arrow", "arrows", "direction", "navigate", "next", "right" ] -}, { - "name" : "help", - "tags" : [ "?", "assistance", "circle", "help", "info", "information", "punctuation", "question mark", "recent", "restore", "shape", "support", "symbol" ] -}, { - "name" : "phone", - "tags" : [ "call", "cell", "contact", "device", "hardware", "mobile", "phone", "telephone" ] -}, { - "name" : "paid", - "tags" : [ "circle", "currency", "money", "paid", "payment", "transaction" ] -}, { - "name" : "task_alt", - "tags" : [ "approve", "check", "circle", "complete", "done", "mark", "ok", "select", "task", "tick", "validate", "verified", "yes" ] -}, { - "name" : "question_answer", - "tags" : [ "answer", "bubble", "chat", "comment", "communicate", "conversation", "feedback", "message", "question", "speech", "talk" ] -}, { - "name" : "expand_less", - "tags" : [ "arrow", "arrows", "chevron", "collapse", "direction", "expand", "expandable", "less", "list", "up" ] -}, { - "name" : "clear", - "tags" : [ "back", "cancel", "clear", "correct", "delete", "erase", "exit", "x" ] -}, { - "name" : "date_range", - "tags" : [ "calendar", "date", "day", "event", "month", "range", "remember", "reminder", "schedule", "time", "today", "week" ] -}, { - "name" : "article", - "tags" : [ "article", "doc", "document", "file", "page", "paper", "text", "writing" ] -}, { - "name" : "error", - "tags" : [ "!", "alert", "attention", "caution", "circle", "danger", "error", "exclamation", "important", "mark", "notification", "symbol", "warning" ] -}, { - "name" : "photo_camera", - "tags" : [ "camera", "image", "photo", "photography", "picture" ] -}, { - "name" : "check_box_outline_blank", - "tags" : [ "blank", "box", "button", "check", "component", "control", "deselected", "empty", "form", "outline", "select", "selection", "square", "tick", "toggle", "ui" ] -}, { - "name" : "image", - "tags" : [ "disabled", "enabled", "hide", "image", "landscape", "mountain", "mountains", "off", "on", "photo", "photography", "picture", "slash" ] -}, { - "name" : "shopping_bag", - "tags" : [ "bag", "bill", "business", "buy", "card", "cart", "cash", "coin", "commerce", "credit", "currency", "dollars", "money", "online", "pay", "payment", "shop", "shopping", "store", "storefront" ] -}, { - "name" : "person_outline", - "tags" : [ "account", "face", "human", "outline", "people", "person", "profile", "user" ] -}, { - "name" : "school", - "tags" : [ "academy", "achievement", "cap", "class", "college", "education", "graduation", "hat", "knowledge", "learning", "school", "university" ] -}, { - "name" : "file_upload", - "tags" : [ "arrow", "arrows", "download", "drive", "export", "file", "up", "upload" ] -}, { - "name" : "perm_identity", - "tags" : [ "account", "avatar", "face", "human", "identity", "people", "perm", "person", "profile", "thumbnail", "user" ] -}, { - "name" : "credit_card", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "price", "shopping", "symbol" ] -}, { - "name" : "history", - "tags" : [ "arrow", "back", "backwards", "clock", "date", "history", "refresh", "renew", "reverse", "rotate", "schedule", "time", "turn" ] -}, { - "name" : "trending_up", - "tags" : [ "analytics", "arrow", "data", "diagram", "graph", "infographic", "measure", "metrics", "movement", "rate", "rating", "statistics", "tracking", "trending", "up" ] -}, { - "name" : "support_agent", - "tags" : [ "agent", "care", "customer", "face", "headphone", "person", "representative", "service", "support" ] -}, { - "name" : "account_balance", - "tags" : [ "account", "balance", "bank", "bill", "card", "cash", "coin", "commerce", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment" ] -}, { - "name" : "delete_outline", - "tags" : [ "bin", "can", "delete", "garbage", "outline", "remove", "trash" ] -}, { - "name" : "attach_money", - "tags" : [ "attach", "attachment", "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "symbol" ] -}, { - "name" : "person_add", - "tags" : [ "+", "account", "add", "avatar", "face", "human", "new", "people", "person", "plus", "profile", "symbol", "user" ] -}, { - "name" : "public", - "tags" : [ "earth", "global", "globe", "map", "network", "planet", "public", "social", "space", "web", "world" ] -}, { - "name" : "save", - "tags" : [ "data", "disk", "document", "drive", "file", "floppy", "multimedia", "save", "storage" ] -}, { - "name" : "mail", - "tags" : [ "email", "envelop", "letter", "mail", "message", "send" ] -}, { - "name" : "report_problem", - "tags" : [ "!", "alert", "attention", "caution", "danger", "error", "exclamation", "feedback", "important", "mark", "notification", "problem", "report", "symbol", "triangle", "warning" ] -}, { - "name" : "fact_check", - "tags" : [ "approve", "check", "complete", "done", "fact", "list", "mark", "ok", "select", "tick", "validate", "verified", "yes" ] -}, { - "name" : "radio_button_unchecked", - "tags" : [ "bullet", "button", "circle", "deselected", "form", "off", "on", "point", "radio", "record", "select", "toggle", "unchecked" ] -}, { - "name" : "verified_user", - "tags" : [ "approve", "certified", "check", "complete", "done", "mark", "ok", "privacy", "private", "protect", "protection", "security", "select", "shield", "tick", "user", "validate", "verified", "yes" ] -}, { - "name" : "assignment", - "tags" : [ "assignment", "clipboard", "doc", "document", "text", "writing" ] -}, { - "name" : "link", - "tags" : [ "chain", "clip", "connection", "link", "linked", "links", "multimedia", "url" ] -}, { - "name" : "play_circle_filled", - "tags" : [ "arrow", "circle", "control", "controls", "media", "music", "play", "video" ] -}, { - "name" : "emoji_events", - "tags" : [ "achievement", "award", "chalice", "champion", "cup", "emoji", "events", "first", "prize", "reward", "sport", "trophy", "winner" ] -}, { - "name" : "remove", - "tags" : [ "can", "delete", "minus", "negative", "remove", "substract", "trash" ] -}, { - "name" : "star_rate", - "tags" : [ "achievement", "bookmark", "favorite", "highlight", "important", "marked", "ranking", "rate", "rating rank", "reward", "save", "saved", "shape", "special", "star" ] -}, { - "name" : "apps", - "tags" : [ "all", "applications", "apps", "circles", "collection", "components", "dots", "grid", "interface", "squares", "ui", "ux" ] -}, { - "name" : "business", - "tags" : [ "apartment", "architecture", "building", "business", "company", "estate", "home", "place", "real", "residence", "residential", "shelter" ] -}, { - "name" : "filter_list", - "tags" : [ "filter", "lines", "list", "organize", "sort" ] -}, { - "name" : "arrow_right_alt", - "tags" : [ "alt", "arrow", "arrows", "direction", "east", "navigation", "pointing", "right" ] -}, { - "name" : "chat", - "tags" : [ "bubble", "chat", "comment", "communicate", "feedback", "message", "speech" ] -}, { - "name" : "account_balance_wallet", - "tags" : [ "account", "balance", "bank", "bill", "card", "cash", "coin", "commerce", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "wallet" ] -}, { - "name" : "payments", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "layer", "money", "multiple", "online", "pay", "payment", "payments", "price", "shopping", "symbol" ] -}, { - "name" : "menu_book", - "tags" : [ "book", "dining", "food", "meal", "menu", "restaurant" ] -}, { - "name" : "folder", - "tags" : [ "data", "doc", "document", "drive", "file", "folder", "folders", "sheet", "slide", "storage" ] -}, { - "name" : "keyboard_arrow_down", - "tags" : [ "arrow", "arrows", "down", "keyboard" ] -}, { - "name" : "autorenew", - "tags" : [ "around", "arrow", "arrows", "autorenew", "cache", "cached", "direction", "inprogress", "load", "loading refresh", "navigation", "renew", "rotate", "turn" ] -}, { - "name" : "build", - "tags" : [ "adjust", "build", "fix", "home", "nest", "repair", "tool", "tools", "wrench" ] -}, { - "name" : "videocam", - "tags" : [ "cam", "camera", "conference", "film", "filming", "hardware", "image", "motion", "picture", "video", "videography" ] -}, { - "name" : "view_list", - "tags" : [ "design", "format", "grid", "layout", "lines", "list", "stacked", "view", "website" ] -}, { - "name" : "print", - "tags" : [ "draft", "fax", "ink", "machine", "office", "paper", "print", "printer", "send" ] -}, { - "name" : "work", - "tags" : [ "bag", "baggage", "briefcase", "business", "case", "job", "suitcase", "work" ] -}, { - "name" : "store", - "tags" : [ "bill", "building", "business", "card", "cash", "coin", "commerce", "company", "credit", "currency", "dollars", "market", "money", "online", "pay", "payment", "shop", "shopping", "store", "storefront" ] -}, { - "name" : "analytics", - "tags" : [ "analytics", "assessment", "bar", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "statistics", "tracking" ] -}, { - "name" : "radio_button_checked", - "tags" : [ "app", "application", "bullet", "button", "checked", "circle", "components", "design", "form", "interface", "off", "on", "point", "radio", "record", "screen", "select", "selected", "site", "toggle", "ui", "ux", "web", "website" ] -}, { - "name" : "phone_iphone", - "tags" : [ "Android", "OS", "cell", "device", "hardware", "iOS", "iphone", "mobile", "phone", "tablet" ] -}, { - "name" : "play_circle", - "tags" : [ "arrow", "circle", "control", "controls", "media", "music", "play", "video" ] -}, { - "name" : "tune", - "tags" : [ "adjust", "audio", "controls", "custom", "customize", "edit", "editing", "filter", "filters", "instant", "mix", "music", "options", "setting", "settings", "slider", "sliders", "switches", "tune" ] -}, { - "name" : "delete_forever", - "tags" : [ "bin", "can", "cancel", "delete", "exit", "forever", "garbage", "remove", "trash", "x" ] -}, { - "name" : "today", - "tags" : [ "calendar", "date", "day", "event", "mark", "month", "remember", "reminder", "schedule", "time", "today" ] -}, { - "name" : "grid_view", - "tags" : [ "app", "application square", "blocks", "components", "dashboard", "design", "grid", "interface", "layout", "screen", "site", "tiles", "ui", "ux", "view", "web", "website", "window" ] -}, { - "name" : "east", - "tags" : [ "arrow", "directional", "east", "maps", "navigation", "right" ] -}, { - "name" : "inventory_2", - "tags" : [ "archive", "box", "file", "inventory", "organize", "packages", "product", "stock", "storage", "supply" ] -}, { - "name" : "mail_outline", - "tags" : [ "email", "envelop", "letter", "mail", "message", "outline", "send" ] -}, { - "name" : "admin_panel_settings", - "tags" : [ "account", "admin", "avatar", "certified", "face", "human", "panel", "people", "person", "privacy", "private", "profile", "protect", "protection", "security", "settings", "shield", "user", "verified" ] -}, { - "name" : "mic", - "tags" : [ "hear", "hearing", "mic", "microphone", "noise", "record", "sound", "voice" ] -}, { - "name" : "calendar_month", - "tags" : [ "calendar", "date", "day", "event", "month", "schedule", "today" ] -}, { - "name" : "group", - "tags" : [ "accounts", "committee", "face", "family", "friends", "group", "humans", "network", "people", "persons", "profiles", "social", "team", "users" ] -}, { - "name" : "picture_as_pdf", - "tags" : [ "alphabet", "as", "character", "document", "file", "font", "image", "letter", "multiple", "pdf", "photo", "photography", "picture", "symbol", "text", "type" ] -}, { - "name" : "lock_open", - "tags" : [ "lock", "open", "password", "privacy", "private", "protection", "safety", "secure", "security", "unlocked" ] -}, { - "name" : "volume_up", - "tags" : [ "audio", "control", "music", "sound", "speaker", "tv", "up", "volume" ] -}, { - "name" : "watch_later", - "tags" : [ "clock", "date", "later", "schedule", "time", "watch" ] -}, { - "name" : "grade", - "tags" : [ "'favorite_news' .", "'star_outline'", "Duplicate of 'star_boarder'", "star_border_purple500'" ] -}, { - "name" : "receipt_long", - "tags" : [ "bill", "check", "document", "list", "long", "paper", "paperwork", "receipt", "record", "store", "transaction" ] -}, { - "name" : "local_offer", - "tags" : [ "deal", "discount", "offer", "price", "shop", "shopping", "store", "tag" ] -}, { - "name" : "room", - "tags" : [ "destination", "direction", "location", "maps", "pin", "place", "room", "stop" ] -}, { - "name" : "update", - "tags" : [ "arrow", "back", "backwards", "clock", "forward", "history", "load", "refresh", "reverse", "schedule", "time", "update" ] -}, { - "name" : "badge", - "tags" : [ "account", "avatar", "badge", "card", "certified", "employee", "face", "human", "identification", "name", "people", "person", "profile", "security", "user", "work" ] -}, { - "name" : "savings", - "tags" : [ "bank", "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "pig", "piggy", "savings", "symbol" ] -}, { - "name" : "code", - "tags" : [ "brackets", "code", "css", "develop", "developer", "engineer", "engineering", "html", "platform" ] -}, { - "name" : "light_mode", - "tags" : [ "bright", "brightness", "day", "device", "light", "lighting", "mode", "morning", "sky", "sun", "sunny" ] -}, { - "name" : "receipt", - "tags" : [ ] -}, { - "name" : "circle", - "tags" : [ "circle", "full", "geometry", "moon" ] -}, { - "name" : "inventory", - "tags" : [ "archive", "box", "clipboard", "doc", "document", "file", "inventory", "organize", "packages", "product", "stock", "supply" ] -}, { - "name" : "add_shopping_cart", - "tags" : [ "add", "card", "cart", "cash", "checkout", "coin", "commerce", "credit", "currency", "dollars", "money", "online", "pay", "payment", "plus", "shopping" ] -}, { - "name" : "contact_support", - "tags" : [ "?", "bubble", "chat", "comment", "communicate", "contact", "help", "info", "information", "mark", "message", "punctuation", "question", "question mark", "speech", "support", "symbol" ] -}, { - "name" : "category", - "tags" : [ "categories", "category", "circle", "collection", "items", "product", "sort", "square", "triangle" ] -}, { - "name" : "edit_note", - "tags" : [ "compose", "create", "draft", "edit", "editing", "input", "lines", "note", "pen", "pencil", "text", "write", "writing" ] -}, { - "name" : "insights", - "tags" : [ "ai", "analytics", "artificial", "automatic", "automation", "bar", "bars", "chart", "custom", "data", "diagram", "genai", "graph", "infographic", "insights", "intelligence", "magic", "measure", "metrics", "smart", "spark", "sparkle", "star", "stars", "statistics", "tracking" ] -}, { - "name" : "power_settings_new", - "tags" : [ "info", "information", "off", "on", "power", "save", "settings", "shutdown" ] -}, { - "name" : "campaign", - "tags" : [ "alert", "announcement", "campaign", "loud", "megaphone", "microphone", "notification", "speaker" ] -}, { - "name" : "format_list_bulleted", - "tags" : [ "align", "alignment", "bulleted", "doc", "edit", "editing", "editor", "format", "list", "notes", "sheet", "spreadsheet", "text", "type", "writing" ] -}, { - "name" : "star_border", - "tags" : [ "best", "bookmark", "border", "favorite", "highlight", "outline", "ranking", "rate", "rating", "save", "star", "toggle" ] -}, { - "name" : "pause", - "tags" : [ "control", "controls", "media", "music", "pause", "video" ] -}, { - "name" : "remove_circle_outline", - "tags" : [ "block", "can", "circle", "delete", "minus", "negative", "outline", "remove", "substract", "trash" ] -}, { - "name" : "warning_amber", - "tags" : [ "!", "alert", "amber", "attention", "caution", "danger", "error", "exclamation", "important", "mark", "notification", "symbol", "triangle", "warning" ] -}, { - "name" : "wifi", - "tags" : [ "connection", "data", "internet", "network", "scan", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "arrow_back_ios_new", - "tags" : [ "DISABLE_IOS", "app", "application", "arrow", "back", "chevron", "components", "direction", "disable_ios", "interface", "ios", "left", "navigation", "new", "previous", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "restart_alt", - "tags" : [ "alt", "around", "arrow", "inprogress", "load", "loading refresh", "reboot", "renew", "repeat", "reset", "restart" ] -}, { - "name" : "done_all", - "tags" : [ "all", "approve", "check", "complete", "done", "layers", "mark", "multiple", "ok", "select", "stack", "tick", "validate", "verified", "yes" ] -}, { - "name" : "pets", - "tags" : [ "animal", "cat", "dog", "hand", "paw", "pet" ] -}, { - "name" : "storefront", - "tags" : [ "business", "buy", "cafe", "commerce", "front", "market", "places", "restaurant", "retail", "sell", "shop", "shopping", "store", "storefront" ] -}, { - "name" : "sort", - "tags" : [ "filter", "find", "lines", "list", "organize", "sort" ] -}, { - "name" : "mode_edit", - "tags" : [ "compose", "create", "draft", "draw", "edit", "mode", "pen", "pencil", "write" ] -}, { - "name" : "list_alt", - "tags" : [ "alt", "box", "contained", "format", "lines", "list", "order", "reorder", "stacked", "title" ] -}, { - "name" : "toggle_on", - "tags" : [ "active", "app", "application", "components", "configuration", "control", "design", "disable", "inable", "inactive", "interface", "off", "on", "selection", "settings", "site", "slider", "switch", "toggle", "ui", "ux", "web", "website" ] -}, { - "name" : "dark_mode", - "tags" : [ "app", "application", "dark", "device", "interface", "mode", "moon", "night", "silent", "theme", "ui", "ux", "website" ] -}, { - "name" : "engineering", - "tags" : [ "body", "cogs", "cogwheel", "construction", "engineering", "fixing", "gears", "hat", "helmet", "human", "maintenance", "people", "person", "setting", "worker" ] -}, { - "name" : "explore", - "tags" : [ "compass", "destination", "direction", "east", "explore", "location", "maps", "needle", "north", "south", "travel", "west" ] -}, { - "name" : "bolt", - "tags" : [ "bolt", "electric", "energy", "fast", "flash", "lightning", "power", "thunderbolt" ] -}, { - "name" : "construction", - "tags" : [ "build", "carpenter", "construction", "equipment", "fix", "hammer", "improvement", "industrial", "industry", "repair", "tools", "wrench" ] -}, { - "name" : "qr_code_scanner", - "tags" : [ "barcode", "camera", "code", "media", "product", "qr", "quick", "response", "scanner", "smartphone", "url", "urls" ] -}, { - "name" : "bookmark", - "tags" : [ "archive", "bookmark", "favorite", "label", "library", "read", "reading", "remember", "ribbon", "save", "tag" ] -}, { - "name" : "vpn_key", - "tags" : [ "code", "key", "lock", "network", "passcode", "password", "unlock", "vpn" ] -}, { - "name" : "monetization_on", - "tags" : [ "bill", "card", "cash", "circle", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "monetization", "money", "on", "online", "pay", "payment", "shopping", "symbol" ] -}, { - "name" : "attach_file", - "tags" : [ "add", "attach", "attachment", "clip", "file", "link", "mail", "media" ] -}, { - "name" : "timer", - "tags" : [ "alarm", "alert", "bell", "clock", "disabled", "duration", "enabled", "notification", "off", "on", "slash", "stop", "time", "timer", "watch" ] -}, { - "name" : "account_box", - "tags" : [ "account", "avatar", "box", "face", "human", "people", "person", "profile", "square", "thumbnail", "user" ] -}, { - "name" : "note_add", - "tags" : [ "+", "-doc", "add", "data", "document", "drive", "file", "folder", "folders", "new", "note", "page", "paper", "plus", "sheet", "slide", "symbol", "writing" ] -}, { - "name" : "reorder", - "tags" : [ "format", "lines", "list", "order", "reorder", "stacked" ] -}, { - "name" : "bookmark_border", - "tags" : [ "archive", "bookmark", "border", "favorite", "label", "library", "read", "reading", "remember", "ribbon", "save", "tag" ] -}, { - "name" : "arrow_right", - "tags" : [ "app", "application", "arrow", "components", "direction", "interface", "navigation", "right", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "pending_actions", - "tags" : [ "actions", "clipboard", "clock", "date", "doc", "document", "pending", "remember", "schedule", "time" ] -}, { - "name" : "smartphone", - "tags" : [ "Android", "OS", "call", "cell", "chat", "device", "hardware", "iOS", "mobile", "phone", "smartphone", "tablet", "text" ] -}, { - "name" : "upload_file", - "tags" : [ "arrow", "data", "doc", "document", "download", "drive", "file", "folder", "folders", "page", "paper", "sheet", "slide", "up", "upload", "writing" ] -}, { - "name" : "account_tree", - "tags" : [ "account", "analytics", "chart", "connect", "data", "diagram", "flow", "graph", "infographic", "measure", "metrics", "process", "square", "statistics", "structure", "tracking", "tree" ] -}, { - "name" : "shopping_basket", - "tags" : [ "add", "basket", "bill", "buy", "card", "cart", "cash", "checkout", "coin", "commerce", "credit", "currency", "dollars", "money", "online", "pay", "payment", "shopping" ] -}, { - "name" : "flag", - "tags" : [ "country", "flag", "goal", "mark", "nation", "report", "start" ] -}, { - "name" : "apartment", - "tags" : [ "accommodation", "apartment", "architecture", "building", "city", "company", "estate", "flat", "home", "house", "office", "places", "real", "residence", "residential", "shelter", "units", "workplace" ] -}, { - "name" : "restaurant", - "tags" : [ "breakfast", "dining", "dinner", "eat", "food", "fork", "knife", "local", "lunch", "meal", "places", "restaurant", "spoon", "utensils" ] -}, { - "name" : "people_alt", - "tags" : [ "accounts", "committee", "face", "family", "friends", "humans", "network", "people", "persons", "profiles", "social", "team", "users" ] -}, { - "name" : "reply", - "tags" : [ "arrow", "backward", "left", "mail", "message", "reply", "send", "share" ] -}, { - "name" : "play_circle_outline", - "tags" : [ "arrow", "circle", "control", "controls", "media", "music", "outline", "play", "video" ] -}, { - "name" : "payment", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "price", "shopping", "symbol" ] -}, { - "name" : "sync", - "tags" : [ "360", "around", "arrow", "arrows", "direction", "inprogress", "load", "loading refresh", "renew", "rotate", "sync", "turn" ] -}, { - "name" : "task", - "tags" : [ "approve", "check", "complete", "data", "doc", "document", "done", "drive", "file", "folder", "folders", "mark", "ok", "page", "paper", "select", "sheet", "slide", "task", "tick", "validate", "verified", "writing", "yes" ] -}, { - "name" : "launch", - "tags" : [ "app", "application", "arrow", "box", "components", "interface", "launch", "new", "open", "screen", "site", "ui", "ux", "web", "website", "window" ] -}, { - "name" : "menu_open", - "tags" : [ "app", "application", "arrow", "components", "hamburger", "interface", "left", "line", "lines", "menu", "open", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "add_box", - "tags" : [ "add", "box", "new square", "plus", "symbol" ] -}, { - "name" : "drag_indicator", - "tags" : [ "app", "application", "circles", "components", "design", "dots", "drag", "drop", "indicator", "interface", "layout", "mobile", "monitor", "move", "phone", "screen", "shape", "shift", "site", "tablet", "ui", "ux", "web", "website", "window" ] -}, { - "name" : "supervisor_account", - "tags" : [ "account", "avatar", "control", "face", "human", "parental", "parental control", "parents", "people", "person", "profile", "supervised", "supervisor", "user" ] -}, { - "name" : "touch_app", - "tags" : [ "app", "command", "fingers", "gesture", "hand", "press", "tap", "touch" ] -}, { - "name" : "pending", - "tags" : [ "circle", "dots", "loading", "pending", "progress", "wait", "waiting" ] -}, { - "name" : "zoom_in", - "tags" : [ "big", "bigger", "find", "glass", "grow", "in", "look", "magnify", "magnifying", "plus", "scale", "search", "see", "size", "zoom" ] -}, { - "name" : "manage_search", - "tags" : [ "glass", "history", "magnifying", "manage", "search", "text" ] -}, { - "name" : "remove_circle", - "tags" : [ "block", "can", "circle", "delete", "minus", "negative", "remove", "substract", "trash" ] -}, { - "name" : "group_add", - "tags" : [ "accounts", "add", "committee", "face", "family", "friends", "group", "humans", "increase", "more", "network", "people", "persons", "plus", "profiles", "social", "team", "users" ] -}, { - "name" : "chat_bubble_outline", - "tags" : [ "bubble", "chat", "comment", "communicate", "feedback", "message", "outline", "speech" ] -}, { - "name" : "assessment", - "tags" : [ "analytics", "assessment", "bar", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "statistics", "tracking" ] -}, { - "name" : "priority_high", - "tags" : [ "!", "alert", "attention", "caution", "danger", "error", "exclamation", "high", "important", "mark", "notification", "symbol", "warning" ] -}, { - "name" : "push_pin", - "tags" : [ "location", "marker", "pin", "place", "push", "remember", "save" ] -}, { - "name" : "feed", - "tags" : [ "article", "feed", "headline", "information", "news", "newspaper", "paper", "public", "social", "timeline" ] -}, { - "name" : "leaderboard", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "leaderboard", "measure", "metrics", "statistics", "tracking" ] -}, { - "name" : "summarize", - "tags" : [ "doc", "document", "list", "menu", "note", "report", "summary" ] -}, { - "name" : "block", - "tags" : [ "avoid", "block", "cancel", "close", "entry", "exit", "no", "prohibited", "quit", "remove", "stop" ] -}, { - "name" : "event_available", - "tags" : [ "approve", "available", "calendar", "check", "complete", "date", "done", "event", "mark", "ok", "schedule", "select", "tick", "time", "validate", "verified", "yes" ] -}, { - "name" : "thumb_up_off_alt", - "tags" : [ "alt", "disabled", "enabled", "favorite", "fingers", "gesture", "hand", "hands", "like", "off", "offline", "on", "rank", "ranking", "rate", "rating", "slash", "thumb", "up" ] -}, { - "name" : "directions_car", - "tags" : [ "automobile", "car", "cars", "direction", "directions", "maps", "public", "transportation", "vehicle" ] -}, { - "name" : "open_in_full", - "tags" : [ "action", "arrow", "arrows", "expand", "full", "grow", "in", "move", "open" ] -}, { - "name" : "auto_stories", - "tags" : [ "auto", "book", "flipping", "pages", "stories" ] -}, { - "name" : "post_add", - "tags" : [ "+", "add", "data", "doc", "document", "drive", "file", "folder", "folders", "page", "paper", "plus", "post", "sheet", "slide", "text", "writing" ] -}, { - "name" : "calculate", - "tags" : [ "+", "-", "=", "calculate", "count", "finance calculator", "math" ] -}, { - "name" : "alternate_email", - "tags" : [ "@", "address", "alternate", "contact", "email", "tag" ] -}, { - "name" : "create", - "tags" : [ "compose", "create", "edit", "editing", "input", "new", "pen", "pencil", "write", "writing" ] -}, { - "name" : "cloud_upload", - "tags" : [ "app", "application", "arrow", "backup", "cloud", "connection", "download", "drive", "files", "folders", "internet", "network", "sky", "storage", "up", "upload" ] -}, { - "name" : "local_fire_department", - "tags" : [ "911", "climate", "department", "fire", "firefighter", "flame", "heat", "home", "hot", "nest", "thermostat" ] -}, { - "name" : "bar_chart", - "tags" : [ "analytics", "bar", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "statistics", "tracking" ] -}, { - "name" : "password", - "tags" : [ "key", "login", "password", "pin", "security", "star", "unlock" ] -}, { - "name" : "collections", - "tags" : [ "album", "collections", "gallery", "image", "landscape", "library", "mountain", "mountains", "photo", "photography", "picture", "stack" ] -}, { - "name" : "preview", - "tags" : [ "design", "eye", "layout", "preview", "reveal", "screen", "see", "show", "site", "view", "web", "website", "window", "www" ] -}, { - "name" : "star_outline", - "tags" : [ "bookmark", "favorite", "half", "highlight", "ranking", "rate", "rating", "save", "star", "toggle" ] -}, { - "name" : "exit_to_app", - "tags" : [ "app", "application", "arrow", "components", "design", "exit", "export", "interface", "layout", "leave", "mobile", "monitor", "move", "output", "phone", "screen", "site", "tablet", "to", "ui", "ux", "web", "website", "window" ] -}, { - "name" : "done_outline", - "tags" : [ "all", "approve", "check", "complete", "done", "mark", "ok", "outline", "select", "tick", "validate", "verified", "yes" ] -}, { - "name" : "psychology", - "tags" : [ "behavior", "body", "brain", "cognitive", "function", "gear", "head", "human", "intellectual", "mental", "mind", "people", "person", "preferences", "psychiatric", "psychology", "science", "settings", "social", "therapy", "thinking", "thoughts" ] -}, { - "name" : "assignment_ind", - "tags" : [ "account", "assignment", "clipboard", "doc", "document", "face", "ind", "people", "person", "profile", "user" ] -}, { - "name" : "volunteer_activism", - "tags" : [ "activism", "donation", "fingers", "gesture", "giving", "hand", "hands", "heart", "love", "sharing", "volunteer" ] -}, { - "name" : "navigate_before", - "tags" : [ "arrow", "arrows", "before", "direction", "left", "navigate" ] -}, { - "name" : "published_with_changes", - "tags" : [ "approve", "arrow", "arrows", "changes", "check", "complete", "done", "inprogress", "load", "loading", "mark", "ok", "published", "refresh", "renew", "replace", "rotate", "select", "tick", "validate", "verified", "with", "yes" ] -}, { - "name" : "add_a_photo", - "tags" : [ "+", "a photo", "add", "camera", "lens", "new", "photography", "picture", "plus", "symbol" ] -}, { - "name" : "auto_awesome", - "tags" : [ "adjust", "ai", "artificial", "automatic", "automation", "custom", "edit", "editing", "enhance", "genai", "intelligence", "magic", "smart", "spark", "sparkle", "star", "stars" ] -}, { - "name" : "card_giftcard", - "tags" : [ "account", "balance", "bill", "card", "cart", "cash", "certificate", "coin", "commerce", "credit", "currency", "dollars", "gift", "giftcard", "money", "online", "pay", "payment", "present", "shopping" ] -}, { - "name" : "fullscreen", - "tags" : [ "adjust", "app", "application", "components", "full", "fullscreen", "interface", "screen", "site", "size", "ui", "ux", "view", "web", "website" ] -}, { - "name" : "sell", - "tags" : [ "bill", "card", "cart", "cash", "coin", "commerce", "credit", "currency", "dollars", "money", "online", "pay", "payment", "price", "sell", "shopping", "tag" ] -}, { - "name" : "checklist", - "tags" : [ "align", "alignment", "approve", "check", "checklist", "complete", "doc", "done", "edit", "editing", "editor", "format", "list", "mark", "notes", "ok", "select", "sheet", "spreadsheet", "text", "tick", "type", "validate", "verified", "writing", "yes" ] -}, { - "name" : "view_in_ar", - "tags" : [ "3d", "ar", "augmented", "cube", "daydream", "headset", "in", "reality", "square", "view", "vr" ] -}, { - "name" : "undo", - "tags" : [ "arrow", "backward", "mail", "previous", "redo", "repeat", "rotate", "undo" ] -}, { - "name" : "arrow_drop_up", - "tags" : [ "app", "application", "arrow", "components", "direction", "drop", "interface", "navigation", "screen", "site", "ui", "up", "ux", "web", "website" ] -}, { - "name" : "feedback", - "tags" : [ "!", "alert", "announcement", "attention", "bubble", "caution", "chat", "comment", "communicate", "danger", "error", "exclamation", "feedback", "important", "mark", "message", "notification", "speech", "symbol", "warning" ] -}, { - "name" : "health_and_safety", - "tags" : [ "+", "add", "and", "certified", "cross", "health", "home", "nest", "plus", "privacy", "private", "protect", "protection", "safety", "security", "shield", "symbol", "verified" ] -}, { - "name" : "work_outline", - "tags" : [ "bag", "baggage", "briefcase", "business", "case", "job", "suitcase", "work" ] -}, { - "name" : "unfold_more", - "tags" : [ "arrow", "arrows", "chevron", "collapse", "direction", "down", "expand", "expandable", "list", "more", "navigation", "unfold" ] -}, { - "name" : "travel_explore", - "tags" : [ "earth", "explore", "find", "glass", "global", "globe", "look", "magnify", "magnifying", "map", "network", "planet", "search", "see", "social", "space", "travel", "web", "world" ] -}, { - "name" : "palette", - "tags" : [ "art", "color", "colors", "filters", "paint", "palette" ] -}, { - "name" : "keyboard_arrow_right", - "tags" : [ "arrow", "arrows", "keyboard", "right" ] -}, { - "name" : "double_arrow", - "tags" : [ "arrow", "arrows", "direction", "double", "multiple", "navigation", "right" ] -}, { - "name" : "computer", - "tags" : [ "Android", "OS", "chrome", "computer", "desktop", "device", "hardware", "iOS", "mac", "monitor", "web", "window" ] -}, { - "name" : "timeline", - "tags" : [ "data", "history", "line", "movement", "point", "points", "timeline", "tracking", "trending", "zigzag" ] -}, { - "name" : "thumb_up_alt", - "tags" : [ "agreed", "approved", "confirm", "correct", "favorite", "feedback", "good", "happy", "like", "okay", "positive", "satisfaction", "social", "thumb", "up", "vote", "yes" ] -}, { - "name" : "signal_cellular_alt", - "tags" : [ "alt", "analytics", "bar", "cell", "cellular", "chart", "data", "diagram", "graph", "infographic", "internet", "measure", "metrics", "mobile", "network", "phone", "signal", "statistics", "tracking", "wifi", "wireless" ] -}, { - "name" : "replay", - "tags" : [ "arrow", "arrows", "control", "controls", "music", "refresh", "renew", "repeat", "replay", "video" ] -}, { - "name" : "swap_horiz", - "tags" : [ "arrow", "arrows", "back", "forward", "horizontal", "swap" ] -}, { - "name" : "volume_off", - "tags" : [ "audio", "control", "disabled", "enabled", "low", "music", "off", "on", "slash", "sound", "speaker", "tv", "volume" ] -}, { - "name" : "forum", - "tags" : [ "bubble", "chat", "comment", "communicate", "community", "conversation", "feedback", "forum", "hub", "message", "speech" ] -}, { - "name" : "skip_next", - "tags" : [ "arrow", "control", "controls", "music", "next", "play", "previous", "skip", "video" ] -}, { - "name" : "water_drop", - "tags" : [ "drink", "drop", "droplet", "eco", "liquid", "nature", "ocean", "rain", "social", "water" ] -}, { - "name" : "assignment_turned_in", - "tags" : [ "approve", "assignment", "check", "clipboard", "complete", "doc", "document", "done", "in", "mark", "ok", "select", "tick", "turn", "validate", "verified", "yes" ] -}, { - "name" : "library_books", - "tags" : [ "add", "album", "audio", "book", "books", "collection", "library", "read", "reading" ] -}, { - "name" : "maps_home_work", - "tags" : [ "building", "home", "house", "maps", "office", "work" ] -}, { - "name" : "dns", - "tags" : [ "address", "bars", "dns", "domain", "information", "ip", "list", "lookup", "name", "server", "system" ] -}, { - "name" : "sync_alt", - "tags" : [ "alt", "arrow", "arrows", "horizontal", "internet", "sync", "technology", "up", "update", "wifi" ] -}, { - "name" : "how_to_reg", - "tags" : [ "approve", "ballot", "check", "complete", "done", "election", "how", "mark", "ok", "poll", "register", "registration", "select", "tick", "to reg", "validate", "verified", "vote", "yes" ] -}, { - "name" : "notifications_none", - "tags" : [ "alarm", "alert", "bell", "none", "notifications", "notify", "reminder", "sound" ] -}, { - "name" : "stars", - "tags" : [ "achievement", "bookmark", "circle", "favorite", "highlight", "important", "marked", "ranking", "rate", "rating rank", "reward", "save", "saved", "shape", "special", "star" ] -}, { - "name" : "flight_takeoff", - "tags" : [ "airport", "departed", "departing", "flight", "fly", "landing", "plane", "takeoff", "transportation", "travel" ] -}, { - "name" : "label", - "tags" : [ "favorite", "indent", "label", "library", "mail", "remember", "save", "stamp", "sticker", "tag" ] -}, { - "name" : "devices", - "tags" : [ "Android", "OS", "computer", "desktop", "device", "hardware", "iOS", "laptop", "mobile", "monitor", "phone", "tablet", "watch", "wearable", "web" ] -}, { - "name" : "chat_bubble", - "tags" : [ "bubble", "chat", "comment", "communicate", "feedback", "message", "speech" ] -}, { - "name" : "emoji_emotions", - "tags" : [ "+", "add", "emoji", "emotions", "expressions", "face", "feelings", "glad", "happiness", "happy", "icon", "icons", "insert", "like", "mood", "new", "person", "pleased", "plus", "smile", "smiling", "social", "survey", "symbol" ] -}, { - "name" : "remove_red_eye", - "tags" : [ "eye", "iris", "look", "looking", "preview", "red", "remove", "see", "sight", "vision" ] -}, { - "name" : "content_paste", - "tags" : [ "clipboard", "content", "copy", "cut", "doc", "document", "file", "multiple", "past" ] -}, { - "name" : "folder_open", - "tags" : [ "data", "doc", "document", "drive", "file", "folder", "folders", "open", "sheet", "slide", "storage" ] -}, { - "name" : "text_snippet", - "tags" : [ "data", "doc", "document", "file", "note", "notes", "snippet", "storage", "text", "writing" ] -}, { - "name" : "tips_and_updates", - "tags" : [ "ai", "alert", "and", "announcement", "artificial", "automatic", "automation", "custom", "electricity", "genai", "idea", "info", "information", "intelligence", "light", "lightbulb", "magic", "smart", "spark", "sparkle", "star", "tips", "updates" ] -}, { - "name" : "my_location", - "tags" : [ "destination", "direction", "location", "maps", "navigation", "pin", "place", "point", "stop" ] -}, { - "name" : "textsms", - "tags" : [ "bubble", "chat", "comment", "communicate", "dots", "feedback", "message", "speech", "textsms" ] -}, { - "name" : "cloud", - "tags" : [ "cloud", "connection", "internet", "network", "sky", "upload" ] -}, { - "name" : "sports_esports", - "tags" : [ "controller", "entertainment", "esports", "game", "gamepad", "gaming", "hobby", "online", "social", "sports", "video" ] -}, { - "name" : "security", - "tags" : [ "certified", "privacy", "private", "protect", "protection", "security", "shield", "verified" ] -}, { - "name" : "request_quote", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "price", "quote", "request", "shopping", "symbol" ] -}, { - "name" : "toggle_off", - "tags" : [ "active", "app", "application", "components", "configuration", "control", "design", "disable", "inable", "inactive", "interface", "off", "on", "selection", "settings", "site", "slider", "switch", "toggle", "ui", "ux", "web", "website" ] -}, { - "name" : "book", - "tags" : [ "book", "bookmark", "favorite", "label", "library", "read", "reading", "remember", "ribbon", "save", "tag" ] -}, { - "name" : "contact_page", - "tags" : [ "account", "avatar", "contact", "data", "doc", "document", "drive", "face", "file", "folder", "folders", "human", "page", "people", "person", "profile", "sheet", "slide", "storage", "user", "writing" ] -}, { - "name" : "speed", - "tags" : [ "arrow", "control", "controls", "fast", "gauge", "meter", "motion", "music", "slow", "speed", "speedometer", "velocity", "video" ] -}, { - "name" : "bug_report", - "tags" : [ "animal", "bug", "fix", "insect", "issue", "problem", "report", "testing", "virus", "warning" ] -}, { - "name" : "space_dashboard", - "tags" : [ "cards", "dashboard", "format", "grid", "layout", "rectangle", "shapes", "space", "squares", "web", "website" ] -}, { - "name" : "fiber_manual_record", - "tags" : [ "circle", "dot", "fiber", "manual", "play", "record", "watch" ] -}, { - "name" : "report", - "tags" : [ "!", "alert", "attention", "caution", "danger", "error", "exclamation", "important", "mark", "notification", "octagon", "report", "symbol", "warning" ] -}, { - "name" : "alarm", - "tags" : [ "alarm", "alert", "bell", "clock", "countdown", "date", "notification", "schedule", "time" ] -}, { - "name" : "cached", - "tags" : [ "around", "arrows", "cache", "cached", "inprogress", "load", "loading refresh", "renew", "rotate" ] -}, { - "name" : "translate", - "tags" : [ "language", "speaking", "speech", "translate", "translator", "words" ] -}, { - "name" : "pan_tool", - "tags" : [ "fingers", "gesture", "hand", "hands", "human", "move", "pan", "scan", "stop", "tool" ] -}, { - "name" : "gavel", - "tags" : [ "agreement", "contract", "court", "document", "gavel", "government", "judge", "law", "mallet", "official", "police", "rule", "rules", "terms" ] -}, { - "name" : "settings_suggest", - "tags" : [ "ai", "artificial", "automatic", "automation", "change", "custom", "details", "gear", "genai", "intelligence", "magic", "options", "recommendation", "service", "settings", "smart", "spark", "sparkle", "star", "suggest", "suggestion", "system" ] -}, { - "name" : "file_copy", - "tags" : [ "content", "copy", "cut", "doc", "document", "duplicate", "file", "multiple", "past" ] -}, { - "name" : "edit_calendar", - "tags" : [ "calendar", "compose", "create", "date", "day", "draft", "edit", "editing", "event", "month", "pen", "pencil", "schedule", "write", "writing" ] -}, { - "name" : "contact_mail", - "tags" : [ "account", "address", "avatar", "communicate", "contact", "email", "face", "human", "info", "information", "mail", "message", "people", "person", "profile", "user" ] -}, { - "name" : "quiz", - "tags" : [ "?", "assistance", "faq", "help", "info", "information", "punctuation", "question mark", "quiz", "support", "symbol", "test" ] -}, { - "name" : "supervised_user_circle", - "tags" : [ "account", "avatar", "circle", "control", "face", "human", "parental", "parents", "people", "person", "profile", "supervised", "supervisor", "user" ] -}, { - "name" : "cloud_download", - "tags" : [ "app", "application", "arrow", "backup", "cloud", "connection", "down", "download", "drive", "files", "folders", "internet", "network", "sky", "storage", "upload" ] -}, { - "name" : "stop", - "tags" : [ "control", "controls", "music", "pause", "play", "square", "stop", "video" ] -}, { - "name" : "person_search", - "tags" : [ "account", "avatar", "face", "find", "glass", "human", "look", "magnify", "magnifying", "people", "person", "profile", "search", "user" ] -}, { - "name" : "location_city", - "tags" : [ "apartments", "architecture", "buildings", "business", "city", "estate", "home", "landscape", "location", "place", "real", "residence", "residential", "shelter", "town", "urban" ] -}, { - "name" : "sentiment_very_satisfied", - "tags" : [ "emotions", "expressions", "face", "feelings", "glad", "happiness", "happy", "like", "mood", "person", "pleased", "satisfied", "sentiment", "smile", "smiling", "survey", "very" ] -}, { - "name" : "ios_share", - "tags" : [ "arrow", "export", "ios", "send", "share", "up" ] -}, { - "name" : "minimize", - "tags" : [ "app", "application", "components", "design", "interface", "line", "minimize", "screen", "shape", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "qr_code", - "tags" : [ "barcode", "camera", "code", "media", "product", "qr", "quick", "response", "smartphone", "url", "urls" ] -}, { - "name" : "sentiment_satisfied_alt", - "tags" : [ "account", "alt", "emoji", "face", "happy", "human", "people", "person", "profile", "satisfied", "sentiment", "smile", "user" ] -}, { - "name" : "local_mall", - "tags" : [ "bag", "bill", "building", "business", "buy", "card", "cart", "cash", "coin", "commerce", "credit", "currency", "dollars", "handbag", "local", "mall", "money", "online", "pay", "payment", "shop", "shopping", "store", "storefront" ] -}, { - "name" : "qr_code_2", - "tags" : [ "barcode", "camera", "code", "media", "product", "qr", "quick", "response", "smartphone", "url", "urls" ] -}, { - "name" : "flight", - "tags" : [ "air", "airplane", "airport", "flight", "plane", "transportation", "travel", "trip" ] -}, { - "name" : "desktop_windows", - "tags" : [ "Android", "OS", "chrome", "desktop", "device", "display", "hardware", "iOS", "mac", "monitor", "screen", "television", "tv", "web", "window", "windows" ] -}, { - "name" : "music_note", - "tags" : [ "audio", "audiotrack", "key", "music", "note", "sound", "track" ] -}, { - "name" : "sentiment_satisfied", - "tags" : [ "emotions", "expressions", "face", "feelings", "glad", "happiness", "happy", "like", "mood", "person", "pleased", "satisfied", "sentiment", "smile", "smiling", "survey" ] -}, { - "name" : "android", - "tags" : [ "android", "character", "logo", "mascot", "toy" ] -}, { - "name" : "accessibility", - "tags" : [ "accessibility", "accessible", "body", "handicap", "help", "human", "people", "person" ] -}, { - "name" : "backspace", - "tags" : [ "arrow", "back", "backspace", "cancel", "clear", "correct", "delete", "erase", "remove" ] -}, { - "name" : "precision_manufacturing", - "tags" : [ "arm", "automatic", "chain", "conveyor", "crane", "factory", "industry", "machinery", "manufacturing", "mechanical", "precision", "production", "repairing", "robot", "supply", "warehouse" ] -}, { - "name" : "drag_handle", - "tags" : [ "app", "application ui", "components", "design", "drag", "handle", "interface", "layout", "menu", "move", "screen", "site", "ui", "ux", "web", "website", "window" ] -}, { - "name" : "smart_display", - "tags" : [ "airplay", "cast", "chrome", "connect", "device", "display", "play", "screen", "screencast", "smart", "stream", "television", "tv", "video", "wireless" ] -}, { - "name" : "near_me", - "tags" : [ "destination", "direction", "location", "maps", "me", "navigation", "near", "pin", "place", "point", "stop" ] -}, { - "name" : "west", - "tags" : [ "arrow", "directional", "left", "maps", "navigation", "west" ] -}, { - "name" : "get_app", - "tags" : [ "app", "arrow", "arrows", "down", "download", "downloads", "export", "get", "install", "play", "upload" ] -}, { - "name" : "person_add_alt", - "tags" : [ "+", "account", "add", "face", "human", "people", "person", "plus", "profile", "user" ] -}, { - "name" : "fitness_center", - "tags" : [ "athlete", "center", "dumbbell", "exercise", "fitness", "gym", "hobby", "places", "sport", "weights", "workout" ] -}, { - "name" : "shield", - "tags" : [ "certified", "privacy", "private", "protect", "protection", "security", "shield", "verified" ] -}, { - "name" : "message", - "tags" : [ "bubble", "chat", "comment", "communicate", "feedback", "message", "speech" ] -}, { - "name" : "rocket_launch", - "tags" : [ "launch", "rocket", "space", "spaceship", "takeoff" ] -}, { - "name" : "record_voice_over", - "tags" : [ "account", "face", "human", "over", "people", "person", "profile", "record", "recording", "speak", "speaking", "speech", "transcript", "user", "voice" ] -}, { - "name" : "add_task", - "tags" : [ "+", "add", "approve", "check", "circle", "completed", "increase", "mark", "ok", "plus", "select", "task", "tick", "yes" ] -}, { - "name" : "drive_file_rename_outline", - "tags" : [ "compose", "create", "draft", "drive", "edit", "editing", "file", "input", "marker", "pen", "pencil", "rename", "write", "writing" ] -}, { - "name" : "insert_drive_file", - "tags" : [ "doc", "drive", "file", "format", "insert", "sheet", "slide" ] -}, { - "name" : "question_mark", - "tags" : [ "?", "assistance", "help", "info", "information", "punctuation", "question mark", "support", "symbol" ] -}, { - "name" : "trending_flat", - "tags" : [ "arrow", "change", "data", "flat", "metric", "movement", "rate", "right", "track", "tracking", "trending" ] -}, { - "name" : "handyman", - "tags" : [ "build", "construction", "fix", "hammer", "handyman", "repair", "screw", "screwdriver", "tools" ] -}, { - "name" : "emoji_objects", - "tags" : [ "bulb", "creative", "emoji", "idea", "light", "objects", "solution", "thinking" ] -}, { - "name" : "military_tech", - "tags" : [ "army", "award", "badge", "honor", "medal", "merit", "military", "order", "privilege", "prize", "rank", "reward", "ribbon", "soldier", "star", "status", "tech", "trophy", "win", "winner" ] -}, { - "name" : "hourglass_empty", - "tags" : [ "countdown", "empty", "hourglass", "loading", "minutes", "time", "wait", "waiting" ] -}, { - "name" : "help_center", - "tags" : [ "?", "assistance", "center", "help", "info", "information", "punctuation", "question mark", "recent", "restore", "support", "symbol" ] -}, { - "name" : "science", - "tags" : [ "beaker", "chemical", "chemistry", "experiment", "flask", "glass", "laboratory", "research", "science", "tube" ] -}, { - "name" : "storage", - "tags" : [ "computer", "data", "drive", "memory", "storage" ] -}, { - "name" : "movie", - "tags" : [ "cinema", "film", "media", "movie", "slate", "video" ] -}, { - "name" : "accessibility_new", - "tags" : [ "accessibility", "accessible", "body", "handicap", "help", "human", "new", "people", "person" ] -}, { - "name" : "workspace_premium", - "tags" : [ "certification", "degree", "ecommerce", "guarantee", "medal", "permit", "premium", "ribbon", "verification", "workspace" ] -}, { - "name" : "directions_run", - "tags" : [ "body", "directions", "human", "jogging", "maps", "people", "person", "route", "run", "running", "walk" ] -}, { - "name" : "rule", - "tags" : [ "approve", "check", "complete", "done", "incomplete", "line", "mark", "missing", "no", "ok", "rule", "select", "tick", "validate", "verified", "wrong", "x", "yes" ] -}, { - "name" : "thumb_down", - "tags" : [ "ate", "dislike", "down", "favorite", "fingers", "gesture", "hand", "hands", "like", "rank", "ranking", "rating", "thumb" ] -}, { - "name" : "event_note", - "tags" : [ "calendar", "date", "event", "note", "schedule", "text", "time", "writing" ] -}, { - "name" : "contacts", - "tags" : [ "account", "avatar", "call", "cell", "contacts", "face", "human", "info", "information", "mobile", "people", "person", "phone", "profile", "user" ] -}, { - "name" : "comment", - "tags" : [ "bubble", "chat", "comment", "communicate", "feedback", "message", "outline", "speech" ] -}, { - "name" : "restaurant_menu", - "tags" : [ "book", "dining", "eat", "food", "fork", "knife", "local", "meal", "menu", "restaurant", "spoon" ] -}, { - "name" : "add_photo_alternate", - "tags" : [ "+", "add", "alternate", "image", "landscape", "mountain", "mountains", "new", "photo", "photography", "picture", "plus", "symbol" ] -}, { - "name" : "confirmation_number", - "tags" : [ "admission", "confirmation", "entertainment", "event", "number", "ticket" ] -}, { - "name" : "sticky_note_2", - "tags" : [ "2", "bookmark", "mark", "message", "note", "paper", "sticky", "text", "writing" ] -}, { - "name" : "format_quote", - "tags" : [ "doc", "edit", "editing", "editor", "format", "quotation", "quote", "sheet", "spreadsheet", "text", "type", "writing" ] -}, { - "name" : "history_edu", - "tags" : [ "document", "edu", "education", "feather", "history", "letter", "paper", "pen", "quill", "school", "story", "tools", "write", "writing" ] -}, { - "name" : "business_center", - "tags" : [ "bag", "baggage", "briefcase", "business", "case", "center", "places", "purse", "suitcase", "work" ] -}, { - "name" : "upload", - "tags" : [ "arrow", "arrows", "download", "drive", "up", "upload" ] -}, { - "name" : "skip_previous", - "tags" : [ "arrow", "control", "controls", "music", "next", "play", "previous", "skip", "video" ] -}, { - "name" : "archive", - "tags" : [ "archive", "inbox", "mail", "store" ] -}, { - "name" : "wb_sunny", - "tags" : [ "balance", "bright", "light", "lighting", "sun", "sunny", "wb", "white" ] -}, { - "name" : "cake", - "tags" : [ "add", "baked", "birthday", "cake", "candles", "celebration", "dessert", "food", "frosting", "new", "party", "pastries", "pastry", "plus", "social", "sweet", "symbol" ] -}, { - "name" : "attachment", - "tags" : [ "attach", "attachment", "clip", "compose", "file", "image", "link" ] -}, { - "name" : "source", - "tags" : [ "code", "composer", "content", "creation", "data", "doc", "document", "file", "folder", "mode", "source", "storage", "view" ] -}, { - "name" : "settings_applications", - "tags" : [ "application", "change", "details", "gear", "info", "information", "options", "personal", "service", "settings" ] -}, { - "name" : "dashboard_customize", - "tags" : [ "cards", "customize", "dashboard", "format", "layout", "rectangle", "shapes", "square", "web", "website" ] -}, { - "name" : "find_in_page", - "tags" : [ "data", "doc", "document", "drive", "file", "find", "folder", "folders", "glass", "in", "look", "magnify", "magnifying", "page", "paper", "search", "see", "sheet", "slide", "writing" ] -}, { - "name" : "support", - "tags" : [ "assist", "buoy", "help", "life", "lifebuoy", "rescue", "safe", "safety", "support" ] -}, { - "name" : "ads_click", - "tags" : [ "ads", "browser", "click", "clicks", "cursor", "internet", "target", "traffic", "web" ] -}, { - "name" : "new_releases", - "tags" : [ "approve", "award", "check", "checkmark", "complete", "done", "new", "notification", "ok", "release", "releases", "select", "star", "symbol", "tick", "verification", "verified", "warning", "yes" ] -}, { - "name" : "flutter_dash", - "tags" : [ "bird", "dash", "flutter", "mascot" ] -}, { - "name" : "playlist_add", - "tags" : [ "+", "add", "collection", "list", "music", "new", "playlist", "plus", "symbol" ] -}, { - "name" : "save_alt", - "tags" : [ "alt", "arrow", "disk", "document", "down", "file", "floppy", "multimedia", "save" ] -}, { - "name" : "close_fullscreen", - "tags" : [ "action", "arrow", "arrows", "close", "collapse", "direction", "full", "fullscreen", "minimize", "screen" ] -}, { - "name" : "credit_score", - "tags" : [ "approve", "bill", "card", "cash", "check", "coin", "commerce", "complete", "cost", "credit", "currency", "dollars", "done", "finance", "loan", "mark", "money", "ok", "online", "pay", "payment", "score", "select", "symbol", "tick", "validate", "verified", "yes" ] -}, { - "name" : "layers", - "tags" : [ "arrange", "disabled", "enabled", "interaction", "layers", "maps", "off", "on", "overlay", "pages", "slash" ] -}, { - "name" : "redeem", - "tags" : [ "bill", "card", "cart", "cash", "certificate", "coin", "commerce", "credit", "currency", "dollars", "gift", "giftcard", "money", "online", "pay", "payment", "present", "redeem", "shopping" ] -}, { - "name" : "spa", - "tags" : [ "aromatherapy", "flower", "healthcare", "leaf", "massage", "meditation", "nature", "petals", "places", "relax", "spa", "wellbeing", "wellness" ] -}, { - "name" : "announcement", - "tags" : [ "!", "alert", "announcement", "attention", "bubble", "caution", "chat", "comment", "communicate", "danger", "error", "exclamation", "feedback", "important", "mark", "message", "notification", "speech", "symbol", "warning" ] -}, { - "name" : "keyboard_backspace", - "tags" : [ "arrow", "back", "backspace", "keyboard", "left" ] -}, { - "name" : "loyalty", - "tags" : [ "benefits", "card", "credit", "heart", "loyalty", "membership", "miles", "points", "program", "subscription", "tag", "travel", "trip" ] -}, { - "name" : "swap_vert", - "tags" : [ "arrow", "arrows", "direction", "down", "navigation", "swap", "up", "vert", "vertical" ] -}, { - "name" : "sentiment_dissatisfied", - "tags" : [ "angry", "disappointed", "dislike", "dissatisfied", "emotions", "expressions", "face", "feelings", "frown", "mood", "person", "sad", "sentiment", "survey", "unhappy", "unsatisfied", "upset" ] -}, { - "name" : "medical_services", - "tags" : [ "aid", "bag", "briefcase", "emergency", "first", "kit", "medical", "medicine", "services" ] -}, { - "name" : "view_headline", - "tags" : [ "design", "format", "grid", "headline", "layout", "paragraph", "text", "view", "website" ] -}, { - "name" : "arrow_circle_right", - "tags" : [ "arrow", "circle", "direction", "navigation", "right" ] -}, { - "name" : "format_list_numbered", - "tags" : [ "align", "alignment", "digit", "doc", "edit", "editing", "editor", "format", "list", "notes", "number", "numbered", "sheet", "spreadsheet", "symbol", "text", "type", "writing" ] -}, { - "name" : "phone_android", - "tags" : [ "OS", "android", "cell", "device", "hardware", "iOS", "mobile", "phone", "tablet" ] -}, { - "name" : "sms", - "tags" : [ "3", "bubble", "chat", "communication", "conversation", "dots", "message", "more", "service", "sms", "speech", "three" ] -}, { - "name" : "restore", - "tags" : [ "arrow", "back", "backwards", "clock", "date", "history", "refresh", "renew", "restore", "reverse", "rotate", "schedule", "time", "turn" ] -}, { - "name" : "policy", - "tags" : [ "certified", "find", "glass", "legal", "look", "magnify", "magnifying", "policy", "privacy", "private", "protect", "protection", "search", "security", "see", "shield", "verified" ] -}, { - "name" : "dangerous", - "tags" : [ "broken", "danger", "dangerous", "fix", "no", "sign", "stop", "update", "warning", "wrong", "x" ] -}, { - "name" : "battery_full", - "tags" : [ "battery", "cell", "charge", "full", "mobile", "power" ] -}, { - "name" : "euro_symbol", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "euro", "finance", "money", "online", "pay", "payment", "symbol" ] -}, { - "name" : "query_stats", - "tags" : [ "analytics", "chart", "data", "diagram", "find", "glass", "graph", "infographic", "line", "look", "magnify", "magnifying", "measure", "metrics", "query", "search", "see", "statistics", "stats", "tracking" ] -}, { - "name" : "group_work", - "tags" : [ "alliance", "collaboration", "group", "partnership", "team", "teamwork", "together", "work" ] -}, { - "name" : "expand_circle_down", - "tags" : [ "arrow", "arrows", "chevron", "circle", "collapse", "direction", "down", "expand", "expandable", "list", "more" ] -}, { - "name" : "sensors", - "tags" : [ "connection", "network", "scan", "sensors", "signal", "wireless" ] -}, { - "name" : "keyboard_arrow_up", - "tags" : [ "arrow", "arrows", "keyboard", "up" ] -}, { - "name" : "brush", - "tags" : [ "art", "brush", "design", "draw", "edit", "editing", "paint", "painting", "tool" ] -}, { - "name" : "meeting_room", - "tags" : [ "building", "door", "doorway", "entrance", "home", "house", "interior", "meeting", "office", "open", "places", "room" ] -}, { - "name" : "key", - "tags" : [ "key", "lock", "password", "unlock" ] -}, { - "name" : "house", - "tags" : [ "architecture", "building", "estate", "family", "home", "homepage", "house", "place", "places", "real", "residence", "residential", "shelter" ] -}, { - "name" : "lunch_dining", - "tags" : [ "breakfast", "dining", "dinner", "drink", "fastfood", "food", "hamburger", "lunch", "meal" ] -}, { - "name" : "table_chart", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic grid", "measure", "metrics", "statistics", "table", "tracking" ] -}, { - "name" : "border_color", - "tags" : [ "all", "border", "doc", "edit", "editing", "editor", "pen", "pencil", "sheet", "spreadsheet", "stroke", "text", "type", "writing" ] -}, { - "name" : "compare_arrows", - "tags" : [ "arrow", "arrows", "collide", "compare", "direction", "left", "pressure", "push", "right", "together" ] -}, { - "name" : "south", - "tags" : [ "arrow", "directional", "down", "maps", "navigation", "south" ] -}, { - "name" : "directions_walk", - "tags" : [ "body", "direction", "directions", "human", "jogging", "maps", "people", "person", "route", "run", "walk" ] -}, { - "name" : "arrow_left", - "tags" : [ "app", "application", "arrow", "components", "direction", "interface", "left", "navigation", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "tag", - "tags" : [ "hash", "hashtag", "key", "media", "number", "pound", "social", "tag", "trend" ] -}, { - "name" : "change_circle", - "tags" : [ "around", "arrows", "change", "circle", "direction", "navigation", "rotate" ] -}, { - "name" : "subject", - "tags" : [ "alignment", "doc", "document", "email", "full", "justify", "list", "note", "subject", "text", "writing" ] -}, { - "name" : "sentiment_very_dissatisfied", - "tags" : [ "angry", "disappointed", "dislike", "dissatisfied", "emotions", "expressions", "face", "feelings", "mood", "person", "sad", "sentiment", "sorrow", "survey", "unhappy", "unsatisfied", "upset", "very" ] -}, { - "name" : "local_hospital", - "tags" : [ "911", "aid", "cross", "emergency", "first", "hospital", "local", "medicine" ] -}, { - "name" : "table_view", - "tags" : [ "format", "grid", "group", "layout", "multiple", "table", "view" ] -}, { - "name" : "disabled_by_default", - "tags" : [ "box", "by", "cancel", "close", "default", "disabled", "exit", "no", "quit", "remove", "square", "stop", "x" ] -}, { - "name" : "notification_important", - "tags" : [ "!", "active", "alarm", "alert", "attention", "bell", "caution", "chime", "danger", "error", "exclamation", "important", "mark", "notification", "notifications", "notify", "reminder", "ring", "sound", "symbol", "warning" ] -}, { - "name" : "celebration", - "tags" : [ "activity", "birthday", "celebration", "event", "fun", "party" ] -}, { - "name" : "laptop", - "tags" : [ "Android", "OS", "chrome", "computer", "desktop", "device", "hardware", "iOS", "laptop", "mac", "monitor", "web", "windows" ] -}, { - "name" : "loop", - "tags" : [ "around", "arrow", "arrows", "direction", "inprogress", "load", "loading refresh", "loop", "music", "navigation", "renew", "rotate", "turn" ] -}, { - "name" : "nightlight_round", - "tags" : [ "dark", "half", "light", "mode", "moon", "night", "nightlight", "round" ] -}, { - "name" : "privacy_tip", - "tags" : [ "alert", "announcement", "assistance", "certified", "details", "help", "i", "info", "information", "privacy", "private", "protect", "protection", "security", "service", "shield", "support", "tip", "verified" ] -}, { - "name" : "import_contacts", - "tags" : [ "address", "book", "contacts", "import", "info", "information", "open" ] -}, { - "name" : "equalizer", - "tags" : [ "adjustment", "analytics", "chart", "data", "equalizer", "graph", "measure", "metrics", "music", "noise", "sound", "static", "statistics", "tracking", "volume" ] -}, { - "name" : "app_registration", - "tags" : [ "app", "apps", "edit", "pencil", "register", "registration" ] -}, { - "name" : "keyboard_double_arrow_right", - "tags" : [ "arrow", "arrows", "direction", "double", "multiple", "navigation", "right" ] -}, { - "name" : "handshake", - "tags" : [ "agreement", "hand", "hands", "partnership", "shake" ] -}, { - "name" : "corporate_fare", - "tags" : [ "architecture", "building", "business", "corporate", "estate", "fare", "organization", "place", "real", "residence", "residential", "shelter" ] -}, { - "name" : "local_library", - "tags" : [ "book", "community learning", "library", "local", "read" ] -}, { - "name" : "https", - "tags" : [ "https", "lock", "locked", "password", "privacy", "private", "protection", "safety", "secure", "security" ] -}, { - "name" : "euro", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "euro", "euros", "finance", "money", "online", "pay", "payment", "price", "shopping", "symbol" ] -}, { - "name" : "coronavirus", - "tags" : [ "19", "bacteria", "coronavirus", "covid", "disease", "germs", "illness", "sick", "social" ] -}, { - "name" : "price_check", - "tags" : [ "approve", "bill", "card", "cash", "check", "coin", "commerce", "complete", "cost", "credit", "currency", "dollars", "done", "finance", "mark", "money", "ok", "online", "pay", "payment", "price", "select", "shopping", "symbol", "tick", "validate", "verified", "yes" ] -}, { - "name" : "live_tv", - "tags" : [ "Android", "OS", "antennas hardware", "chrome", "desktop", "device", "iOS", "live", "mac", "monitor", "movie", "play", "stream", "television", "tv", "web", "window" ] -}, { - "name" : "park", - "tags" : [ "attraction", "fresh", "local", "nature", "outside", "park", "plant", "tree" ] -}, { - "name" : "toc", - "tags" : [ "content", "format", "lines", "list", "order", "reorder", "stacked", "table", "title", "titles", "toc" ] -}, { - "name" : "track_changes", - "tags" : [ "bullseye", "changes", "circle", "evolve", "lines", "movement", "rotate", "shift", "target", "track" ] -}, { - "name" : "arrow_circle_up", - "tags" : [ "arrow", "circle", "direction", "navigation", "up" ] -}, { - "name" : "emoji_people", - "tags" : [ "arm", "body", "emoji", "greeting", "human", "people", "person", "social", "waving" ] -}, { - "name" : "flash_on", - "tags" : [ "bolt", "disabled", "electric", "enabled", "fast", "flash", "lightning", "off", "on", "slash", "thunderbolt" ] -}, { - "name" : "copyright", - "tags" : [ "alphabet", "c", "character", "copyright", "emblem", "font", "legal", "letter", "owner", "symbol", "text" ] -}, { - "name" : "bookmarks", - "tags" : [ "bookmark", "bookmarks", "favorite", "label", "layers", "library", "multiple", "read", "reading", "remember", "ribbon", "save", "stack", "tag" ] -}, { - "name" : "ac_unit", - "tags" : [ "ac", "air", "cold", "conditioner", "flake", "snow", "temperature", "unit", "weather", "winter" ] -}, { - "name" : "contact_phone", - "tags" : [ "account", "avatar", "call", "communicate", "contact", "face", "human", "info", "information", "message", "mobile", "people", "person", "phone", "profile", "user" ] -}, { - "name" : "keyboard_arrow_left", - "tags" : [ "arrow", "arrows", "keyboard", "left" ] -}, { - "name" : "medication", - "tags" : [ "doctor", "drug", "emergency", "hospital", "medication", "medicine", "pharmacy", "pills", "prescription" ] -}, { - "name" : "grading", - "tags" : [ "'favorite'_new'. ' Remove this icon & keep 'star'.", "'star_boarder'", "'star_border_purple500'", "'star_outline'", "'star_purple500'", "'star_rate'", "Same as 'star'" ] -}, { - "name" : "keyboard_return", - "tags" : [ "arrow", "back", "keyboard", "left", "return" ] -}, { - "name" : "api", - "tags" : [ "api", "developer", "development", "enterprise", "software" ] -}, { - "name" : "smart_toy", - "tags" : [ "bot", "droid", "games", "robot", "smart", "toy" ] -}, { - "name" : "input", - "tags" : [ "arrow", "box", "download", "input", "login", "move", "right" ] -}, { - "name" : "self_improvement", - "tags" : [ "body", "calm", "care", "chi", "human", "improvement", "meditate", "meditation", "people", "person", "relax", "self", "sitting", "wellbeing", "yoga", "zen" ] -}, { - "name" : "live_help", - "tags" : [ "?", "assistance", "bubble", "chat", "comment", "communicate", "help", "info", "information", "live", "message", "punctuation", "question mark", "recent", "restore", "speech", "support", "symbol" ] -}, { - "name" : "query_builder", - "tags" : [ "builder", "clock", "date", "query", "schedule", "time" ] -}, { - "name" : "perm_media", - "tags" : [ "collection", "data", "doc", "document", "file", "folder", "folders", "image", "landscape", "media", "mountain", "mountains", "perm", "photo", "photography", "picture", "storage" ] -}, { - "name" : "download_for_offline", - "tags" : [ "arrow", "circle", "down", "download", "for offline", "install", "upload" ] -}, { - "name" : "view_module", - "tags" : [ "design", "format", "grid", "layout", "module", "square", "squares", "stacked", "view", "website" ] -}, { - "name" : "pin", - "tags" : [ "1", "2", "3", "digit", "key", "login", "logout", "number", "password", "pattern", "pin", "security", "star", "symbol", "unlock" ] -}, { - "name" : "fast_forward", - "tags" : [ "control", "fast", "forward", "media", "music", "play", "speed", "time", "tv", "video" ] -}, { - "name" : "forward_to_inbox", - "tags" : [ "arrow", "arrows", "directions", "email", "envelop", "forward", "inbox", "letter", "mail", "message", "navigation", "outgoing", "right", "send", "to" ] -}, { - "name" : "person_remove", - "tags" : [ "account", "avatar", "delete", "face", "human", "minus", "people", "person", "profile", "remove", "unfriend", "user" ] -}, { - "name" : "local_atm", - "tags" : [ "atm", "bill", "card", "cart", "cash", "coin", "commerce", "credit", "currency", "dollars", "local", "money", "online", "pay", "payment", "shopping", "symbol" ] -}, { - "name" : "star_half", - "tags" : [ "achievement", "bookmark", "favorite", "half", "highlight", "important", "marked", "ranking", "rate", "rating rank", "reward", "save", "saved", "shape", "special", "star", "toggle" ] -}, { - "name" : "build_circle", - "tags" : [ "adjust", "build", "circle", "fix", "repair", "tool", "wrench" ] -}, { - "name" : "redo", - "tags" : [ "arrow", "backward", "forward", "next", "redo", "repeat", "rotate", "undo" ] -}, { - "name" : "web", - "tags" : [ "browser", "internet", "page", "screen", "site", "web", "website", "www" ] -}, { - "name" : "north_east", - "tags" : [ "arrow", "east", "maps", "navigation", "noth", "right", "up" ] -}, { - "name" : "north", - "tags" : [ "arrow", "directional", "maps", "navigation", "north", "up" ] -}, { - "name" : "cottage", - "tags" : [ "architecture", "beach", "cottage", "estate", "home", "house", "lake", "lodge", "maps", "place", "real", "residence", "residential", "stay", "traveling" ] -}, { - "name" : "local_activity", - "tags" : [ "activity", "event", "event ticket", "local", "star", "things", "ticket" ] -}, { - "name" : "currency_exchange", - "tags" : [ "360", "around", "arrow", "arrows", "cash", "coin", "commerce", "currency", "direction", "dollars", "exchange", "inprogress", "money", "pay", "renew", "rotate", "sync", "turn", "universal" ] -}, { - "name" : "video_library", - "tags" : [ "arrow", "collection", "library", "play", "video" ] -}, { - "name" : "hourglass_bottom", - "tags" : [ "bottom", "countdown", "half", "hourglass", "loading", "minute", "minutes", "time", "wait", "waiting" ] -}, { - "name" : "headphones", - "tags" : [ "accessory", "audio", "device", "ear", "earphone", "headphones", "headset", "listen", "music", "sound" ] -}, { - "name" : "zoom_out", - "tags" : [ "find", "glass", "look", "magnify", "magnifying", "minus", "negative", "out", "scale", "search", "see", "size", "small", "smaller", "zoom" ] -}, { - "name" : "poll", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "poll", "statistics", "survey", "tracking", "vote" ] -}, { - "name" : "perm_contact_calendar", - "tags" : [ "account", "calendar", "contact", "date", "face", "human", "information", "people", "perm", "person", "profile", "schedule", "time", "user" ] -}, { - "name" : "forward", - "tags" : [ "arrow", "forward", "mail", "message", "playback", "right", "sent" ] -}, { - "name" : "person_pin", - "tags" : [ "account", "avatar", "destination", "direction", "face", "human", "location", "maps", "people", "person", "pin", "place", "profile", "stop", "user" ] -}, { - "name" : "home_work", - "tags" : [ "architecture", "building", "estate", "home", "place", "real", "residence", "residential", "shelter", "work" ] -}, { - "name" : "playlist_add_check", - "tags" : [ "add", "approve", "check", "collection", "complete", "done", "list", "mark", "music", "ok", "playlist", "select", "tick", "validate", "verified", "yes" ] -}, { - "name" : "local_cafe", - "tags" : [ "bottle", "cafe", "coffee", "cup", "drink", "food", "restaurant", "tea" ] -}, { - "name" : "ondemand_video", - "tags" : [ "Android", "OS", "chrome", "demand", "desktop", "device", "hardware", "iOS", "mac", "monitor", "ondemand", "play", "television", "tv", "video", "web", "window" ] -}, { - "name" : "design_services", - "tags" : [ "compose", "create", "design", "draft", "edit", "editing", "input", "pen", "pencil", "ruler", "service", "write", "writing" ] -}, { - "name" : "looks_one", - "tags" : [ "1", "digit", "looks", "numbers", "square", "symbol" ] -}, { - "name" : "backup", - "tags" : [ "arrow", "backup", "cloud", "data", "drive", "files folders", "storage", "up", "upload" ] -}, { - "name" : "newspaper", - "tags" : [ "article", "data", "doc", "document", "drive", "file", "folder", "folders", "magazine", "media", "news", "newspaper", "notes", "page", "paper", "sheet", "slide", "text", "writing" ] -}, { - "name" : "memory", - "tags" : [ "card", "chip", "digital", "memory", "micro", "processor", "sd", "storage" ] -}, { - "name" : "open_with", - "tags" : [ "arrow", "arrows", "direction", "expand", "move", "open", "pan", "with" ] -}, { - "name" : "content_cut", - "tags" : [ "content", "copy", "cut", "doc", "document", "file", "past", "scissors", "trim" ] -}, { - "name" : "keyboard", - "tags" : [ "computer", "device", "hardware", "input", "keyboard", "keypad", "letter", "office", "text", "type" ] -}, { - "name" : "hourglass_top", - "tags" : [ "countdown", "half", "hourglass", "loading", "minute", "minutes", "time", "top", "wait", "waiting" ] -}, { - "name" : "settings_phone", - "tags" : [ "call", "cell", "contact", "device", "hardware", "mobile", "phone", "settings", "telephone" ] -}, { - "name" : "rss_feed", - "tags" : [ "application", "blog", "connection", "data", "feed", "internet", "network", "rss", "service", "signal", "website", "wifi", "wireless" ] -}, { - "name" : "first_page", - "tags" : [ "arrow", "back", "chevron", "first", "left", "page", "rewind" ] -}, { - "name" : "delivery_dining", - "tags" : [ "delivery", "dining", "food", "meal", "restaurant", "scooter", "takeout", "transportation", "vehicle", "vespa" ] -}, { - "name" : "rate_review", - "tags" : [ "comment", "feedback", "pen", "pencil", "rate", "review", "stars", "write" ] -}, { - "name" : "control_point", - "tags" : [ "+", "add", "circle", "control", "plus", "point" ] -}, { - "name" : "gpp_good", - "tags" : [ "certified", "check", "good", "gpp", "ok", "pass", "security", "shield", "sim", "tick" ] -}, { - "name" : "circle_notifications", - "tags" : [ "active", "alarm", "alert", "bell", "chime", "circle", "notifications", "notify", "reminder", "ring", "sound" ] -}, { - "name" : "auto_fix_high", - "tags" : [ "adjust", "ai", "artificial", "auto", "automatic", "automation", "custom", "edit", "editing", "enhance", "erase", "fix", "genai", "high", "intelligence", "magic", "modify", "pen", "smart", "spark", "sparkle", "star", "tool", "wand" ] -}, { - "name" : "book_online", - "tags" : [ "Android", "OS", "admission", "appointment", "book", "cell", "device", "event", "hardware", "iOS", "mobile", "online", "pass", "phone", "reservation", "tablet", "ticket" ] -}, { - "name" : "notes", - "tags" : [ "comment", "doc", "document", "note", "notes", "text", "write", "writing" ] -}, { - "name" : "point_of_sale", - "tags" : [ "checkout", "cost", "machine", "merchant", "money", "of", "pay", "payment", "point", "pos", "retail", "sale", "system", "transaction" ] -}, { - "name" : "perm_phone_msg", - "tags" : [ "bubble", "call", "cell", "chat", "comment", "communicate", "contact", "device", "message", "msg", "perm", "phone", "recording", "speech", "telephone", "voice" ] -}, { - "name" : "speaker_notes", - "tags" : [ "bubble", "chat", "comment", "communicate", "format", "list", "message", "notes", "speaker", "speech", "text" ] -}, { - "name" : "fullscreen_exit", - "tags" : [ "adjust", "app", "application", "components", "exit", "full", "fullscreen", "interface", "screen", "site", "size", "ui", "ux", "view", "web", "website" ] -}, { - "name" : "headset_mic", - "tags" : [ "accessory", "audio", "chat", "device", "ear", "earphone", "headphones", "headset", "listen", "mic", "music", "sound", "talk" ] -}, { - "name" : "create_new_folder", - "tags" : [ "+", "add", "create", "data", "doc", "document", "drive", "file", "folder", "new", "plus", "sheet", "slide", "storage", "symbol" ] -}, { - "name" : "wysiwyg", - "tags" : [ "composer", "mode", "screen", "site", "software", "system", "text", "view", "visibility", "web", "website", "window", "wysiwyg" ] -}, { - "name" : "label_important", - "tags" : [ "favorite", "important", "indent", "label", "library", "mail", "remember", "save", "stamp", "sticker", "tag", "wing" ] -}, { - "name" : "card_membership", - "tags" : [ "bill", "bookmark", "card", "cash", "certificate", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "loyalty", "membership", "money", "online", "pay", "payment", "shopping", "subscription" ] -}, { - "name" : "style", - "tags" : [ "booklet", "cards", "filters", "options", "style", "tags" ] -}, { - "name" : "arrow_circle_down", - "tags" : [ "arrow", "circle", "direction", "down", "navigation" ] -}, { - "name" : "file_present", - "tags" : [ "clip", "data", "doc", "document", "drive", "file", "folder", "folders", "note", "paper", "present", "reminder", "sheet", "slide", "storage", "writing" ] -}, { - "name" : "directions_bus", - "tags" : [ "automobile", "bus", "car", "cars", "directions", "maps", "public", "transportation", "vehicle" ] -}, { - "name" : "whatshot", - "tags" : [ "arrow", "circle", "direction", "fire", "frames", "hot", "round", "whatshot" ] -}, { - "name" : "sports_soccer", - "tags" : [ "athlete", "athletic", "ball", "entertainment", "exercise", "football", "game", "hobby", "soccer", "social", "sports" ] -}, { - "name" : "indeterminate_check_box", - "tags" : [ "app", "application", "box", "button", "check", "components", "control", "design", "form", "indeterminate", "interface", "screen", "select", "selected", "selection", "site", "square", "toggle", "ui", "undetermined", "ux", "web", "website" ] -}, { - "name" : "outlined_flag", - "tags" : [ "country", "flag", "goal", "mark", "nation", "outlined", "report", "start" ] -}, { - "name" : "price_change", - "tags" : [ "arrows", "bill", "card", "cash", "change", "coin", "commerce", "cost", "credit", "currency", "dollars", "down", "finance", "money", "online", "pay", "payment", "price", "shopping", "symbol", "up" ] -}, { - "name" : "mark_email_read", - "tags" : [ "approve", "check", "complete", "done", "email", "envelop", "letter", "mail", "mark", "message", "note", "ok", "read", "select", "send", "sent", "tick", "yes" ] -}, { - "name" : "library_add", - "tags" : [ "+", "add", "collection", "layers", "library", "multiple", "music", "new", "plus", "stacked", "symbol", "video" ] -}, { - "name" : "pageview", - "tags" : [ "doc", "document", "find", "glass", "magnifying", "page", "paper", "search", "view" ] -}, { - "name" : "tv", - "tags" : [ "device", "display", "monitor", "screen", "screencast", "stream", "television", "tv", "video", "wireless" ] -}, { - "name" : "inbox", - "tags" : [ "archive", "email", "inbox", "incoming", "mail", "message" ] -}, { - "name" : "adjust", - "tags" : [ "adjust", "alter", "center", "circle", "circles", "dot", "fix", "image", "move", "target" ] -}, { - "name" : "3d_rotation", - "tags" : [ "3", "3d", "D", "alphabet", "arrow", "arrows", "av", "camera", "character", "digit", "font", "letter", "number", "rotation", "symbol", "text", "type", "vr" ] -}, { - "name" : "battery_charging_full", - "tags" : [ "battery", "bolt", "cell", "charge", "charging", "full", "lightening", "mobile", "power", "thunderbolt" ] -}, { - "name" : "chair", - "tags" : [ "chair", "comfort", "couch", "decoration", "furniture", "home", "house", "living", "lounging", "loveseat", "room", "seat", "seating", "sofa" ] -}, { - "name" : "directions_bike", - "tags" : [ "bicycle", "bike", "direction", "directions", "human", "maps", "person", "public", "route", "transportation" ] -}, { - "name" : "mic_off", - "tags" : [ "audio", "disabled", "enabled", "hear", "hearing", "mic", "microphone", "noise", "off", "on", "record", "recording", "slash", "sound", "voice" ] -}, { - "name" : "local_police", - "tags" : [ "911", "badge", "law", "local", "officer", "police", "protect", "protection", "security", "shield" ] -}, { - "name" : "fastfood", - "tags" : [ "drink", "fastfood", "food", "hamburger", "maps", "meal", "places" ] -}, { - "name" : "tungsten", - "tags" : [ "electricity", "indoor", "lamp", "light", "lightbulb", "setting", "tungsten" ] -}, { - "name" : "mood", - "tags" : [ "emoji", "emotions", "expressions", "face", "feelings", "glad", "happiness", "happy", "like", "mood", "person", "pleased", "smile", "smiling", "social", "survey" ] -}, { - "name" : "pause_circle", - "tags" : [ "circle", "control", "controls", "media", "music", "pause", "video" ] -}, { - "name" : "upgrade", - "tags" : [ "arrow", "export", "instal", "line", "replace", "up", "update", "upgrade" ] -}, { - "name" : "recommend", - "tags" : [ "approved", "circle", "confirm", "favorite", "gesture", "hand", "like", "reaction", "recommend", "social", "support", "thumbs", "up", "well" ] -}, { - "name" : "directions_car_filled", - "tags" : [ "automobile", "car", "cars", "direction", "directions", "filled", "maps", "public", "transportation", "vehicle" ] -}, { - "name" : "fmd_good", - "tags" : [ "destination", "direction", "fmd", "good", "location", "maps", "pin", "place", "stop" ] -}, { - "name" : "integration_instructions", - "tags" : [ "brackets", "clipboard", "code", "css", "develop", "developer", "doc", "document", "engineer", "engineering clipboard", "html", "instructions", "integration", "platform" ] -}, { - "name" : "format_bold", - "tags" : [ "B", "alphabet", "bold", "character", "doc", "edit", "editing", "editor", "font", "format", "letter", "sheet", "spreadsheet", "styles", "symbol", "text", "type", "writing" ] -}, { - "name" : "people_outline", - "tags" : [ "accounts", "committee", "face", "family", "friends", "humans", "network", "outline", "people", "persons", "profiles", "social", "team", "users" ] -}, { - "name" : "trending_down", - "tags" : [ "analytics", "arrow", "data", "diagram", "down", "graph", "infographic", "measure", "metrics", "movement", "rate", "rating", "statistics", "tracking", "trending" ] -}, { - "name" : "change_history", - "tags" : [ "change", "history", "shape", "triangle" ] -}, { - "name" : "female", - "tags" : [ "female", "gender", "girl", "lady", "social", "symbol", "woman", "women" ] -}, { - "name" : "link_off", - "tags" : [ "attached", "chain", "clip", "connection", "disabled", "enabled", "link", "linked", "links", "multimedia", "off", "on", "slash", "url" ] -}, { - "name" : "text_fields", - "tags" : [ "T", "add", "alphabet", "character", "field", "fields", "font", "input", "letter", "symbol", "text", "type" ] -}, { - "name" : "swipe", - "tags" : [ "arrow", "arrows", "fingers", "gesture", "hand", "hands", "swipe", "touch" ] -}, { - "name" : "reviews", - "tags" : [ "bubble", "chat", "comment", "communicate", "feedback", "message", "rate", "rating", "recommendation", "reviews", "speech" ] -}, { - "name" : "home_repair_service", - "tags" : [ "box", "equipment", "fix", "home", "kit", "mechanic", "repair", "repairing", "service", "tool", "toolbox", "tools", "workshop" ] -}, { - "name" : "subscriptions", - "tags" : [ "enroll", "list", "media", "order", "play", "signup", "subscribe", "subscriptions" ] -}, { - "name" : "video_call", - "tags" : [ "+", "add", "call", "camera", "chat", "conference", "film", "filming", "hardware", "image", "motion", "new", "picture", "plus", "symbol", "video", "videography" ] -}, { - "name" : "zoom_out_map", - "tags" : [ "arrow", "arrows", "destination", "location", "maps", "move", "out", "place", "stop", "zoom" ] -}, { - "name" : "straighten", - "tags" : [ "length", "measure", "measurement", "ruler", "size", "straighten" ] -}, { - "name" : "arrow_drop_down_circle", - "tags" : [ "app", "application", "arrow", "circle", "components", "direction", "down", "drop", "interface", "navigation", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "bed", - "tags" : [ "bed", "bedroom", "double", "full", "furniture", "home", "hotel", "house", "king", "night", "pillows", "queen", "rest", "room", "size", "sleep" ] -}, { - "name" : "drive_eta", - "tags" : [ "automobile", "car", "cars", "destination", "direction", "drive", "estimate", "eta", "maps", "public", "transportation", "travel", "trip", "vehicle" ] -}, { - "name" : "class", - "tags" : [ "archive", "book", "bookmark", "class", "favorite", "label", "library", "read", "reading", "remember", "ribbon", "save", "tag" ] -}, { - "name" : "drafts", - "tags" : [ "document", "draft", "drafts", "email", "file", "letter", "mail", "message", "read" ] -}, { - "name" : "ballot", - "tags" : [ "ballot", "bullet", "election", "list", "point", "poll", "vote" ] -}, { - "name" : "volume_mute", - "tags" : [ "audio", "control", "music", "mute", "sound", "speaker", "tv", "volume" ] -}, { - "name" : "table_rows", - "tags" : [ "grid", "layout", "lines", "rows", "stacked", "table" ] -}, { - "name" : "accessible", - "tags" : [ "accessibility", "accessible", "body", "handicap", "help", "human", "people", "person", "wheelchair" ] -}, { - "name" : "stop_circle", - "tags" : [ "circle", "control", "controls", "music", "pause", "play", "square", "stop", "video" ] -}, { - "name" : "family_restroom", - "tags" : [ "bathroom", "child", "children", "family", "father", "kids", "mother", "parents", "restroom", "wc" ] -}, { - "name" : "title", - "tags" : [ "T", "alphabet", "character", "font", "header", "letter", "subject", "symbol", "text", "title", "type" ] -}, { - "name" : "biotech", - "tags" : [ "biotech", "chemistry", "laboratory", "microscope", "research", "science", "technology" ] -}, { - "name" : "insert_emoticon", - "tags" : [ "account", "emoji", "emoticon", "face", "happy", "human", "insert", "people", "person", "profile", "sentiment", "smile", "user" ] -}, { - "name" : "g_translate", - "tags" : [ "emblem", "g", "google", "language", "logo", "mark", "speaking", "speech", "translate", "translator", "words" ] -}, { - "name" : "last_page", - "tags" : [ "app", "application", "arrow", "chevron", "components", "end", "forward", "interface", "last", "page", "right", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "publish", - "tags" : [ "arrow", "cloud", "file", "import", "publish", "up", "upload" ] -}, { - "name" : "repeat", - "tags" : [ "arrow", "arrows", "control", "controls", "media", "music", "repeat", "video" ] -}, { - "name" : "checklist_rtl", - "tags" : [ "align", "alignment", "approve", "check", "checklist", "complete", "doc", "done", "edit", "editing", "editor", "format", "list", "mark", "notes", "ok", "rtl", "select", "sheet", "spreadsheet", "text", "tick", "type", "validate", "verified", "writing", "yes" ] -}, { - "name" : "wifi_off", - "tags" : [ "connection", "data", "disabled", "enabled", "internet", "network", "off", "offline", "on", "scan", "service", "signal", "slash", "wifi", "wireless" ] -}, { - "name" : "settings_accessibility", - "tags" : [ "accessibility", "body", "details", "human", "information", "people", "person", "personal", "preferences", "profile", "settings", "user" ] -}, { - "name" : "percent", - "tags" : [ "math", "number", "percent", "symbol" ] -}, { - "name" : "insert_photo", - "tags" : [ "image", "insert", "landscape", "mountain", "mountains", "photo", "photography", "picture" ] -}, { - "name" : "hotel", - "tags" : [ "body", "hotel", "human", "people", "person", "sleep", "stay", "travel", "trip" ] -}, { - "name" : "cleaning_services", - "tags" : [ "clean", "cleaning", "dust", "services", "sweep" ] -}, { - "name" : "downloading", - "tags" : [ "arrow", "circle", "down", "download", "downloading", "downloads", "install", "pending", "progress", "upload" ] -}, { - "name" : "expand", - "tags" : [ "arrow", "arrows", "compress", "enlarge", "expand", "grow", "move", "push", "together" ] -}, { - "name" : "local_phone", - "tags" : [ "booth", "call", "communication", "phone", "telecommunication" ] -}, { - "name" : "offline_bolt", - "tags" : [ "bolt", "circle", "electric", "fast", "lightning", "offline", "thunderbolt" ] -}, { - "name" : "auto_graph", - "tags" : [ "analytics", "auto", "chart", "data", "diagram", "graph", "infographic", "line", "measure", "metrics", "stars", "statistics", "tracking" ] -}, { - "name" : "local_grocery_store", - "tags" : [ "grocery", "market", "shop", "store" ] -}, { - "name" : "photo_library", - "tags" : [ "album", "image", "library", "mountain", "mountains", "photo", "photography", "picture" ] -}, { - "name" : "miscellaneous_services", - "tags" : [ ] -}, { - "name" : "note_alt", - "tags" : [ "alt", "clipboard", "document", "file", "memo", "note", "page", "paper", "writing" ] -}, { - "name" : "settings_backup_restore", - "tags" : [ "arrow", "back", "backup", "backwards", "refresh", "restore", "reverse", "rotate", "settings" ] -}, { - "name" : "production_quantity_limits", - "tags" : [ "!", "alert", "attention", "bill", "card", "cart", "cash", "caution", "coin", "commerce", "credit", "currency", "danger", "dollars", "error", "exclamation", "important", "limits", "mark", "money", "notification", "online", "pay", "payment", "production", "quantity", "shopping", "symbol", "warning" ] -}, { - "name" : "person_off", - "tags" : [ "account", "avatar", "disabled", "enabled", "face", "human", "off", "on", "people", "person", "profile", "slash", "user" ] -}, { - "name" : "report_gmailerrorred", - "tags" : [ "!", "alert", "attention", "caution", "danger", "error", "exclamation", "gmail", "gmailerrorred", "important", "mark", "notification", "octagon", "report", "symbol", "warning" ] -}, { - "name" : "camera", - "tags" : [ "aperture", "camera", "lens", "photo", "photography", "picture", "shutter" ] -}, { - "name" : "recycling", - "tags" : [ "bio", "eco", "green", "loop", "recyclable", "recycle", "recycling", "rotate", "sustainability", "sustainable", "trash" ] -}, { - "name" : "male", - "tags" : [ "boy", "gender", "male", "man", "social", "symbol" ] -}, { - "name" : "not_interested", - "tags" : [ "cancel", "close", "dislike", "exit", "interested", "no", "not", "off", "quit", "remove", "stop", "x" ] -}, { - "name" : "event_busy", - "tags" : [ "busy", "calendar", "cancel", "close", "date", "event", "exit", "no", "remove", "schedule", "stop", "time", "unavailable", "x" ] -}, { - "name" : "arrow_circle_left", - "tags" : [ "arrow", "circle", "direction", "left", "navigation" ] -}, { - "name" : "shuffle", - "tags" : [ "arrow", "arrows", "control", "controls", "music", "random", "shuffle", "video" ] -}, { - "name" : "aspect_ratio", - "tags" : [ "aspect", "expand", "image", "ratio", "resize", "scale", "size", "square" ] -}, { - "name" : "other_houses", - "tags" : [ "architecture", "cottage", "estate", "home", "house", "houses", "maps", "other", "place", "real", "residence", "residential", "stay", "traveling" ] -}, { - "name" : "model_training", - "tags" : [ "arrow", "bulb", "idea", "inprogress", "light", "load", "loading", "model", "refresh", "renew", "restore", "reverse", "rotate", "training" ] -}, { - "name" : "unfold_less", - "tags" : [ "arrow", "arrows", "chevron", "collapse", "direction", "expand", "expandable", "inward", "less", "list", "navigation", "unfold", "up" ] -}, { - "name" : "insert_chart_outlined", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "insert", "measure", "metrics", "outlined", "statistics", "tracking" ] -}, { - "name" : "donut_large", - "tags" : [ "analytics", "chart", "data", "diagram", "donut", "graph", "infographic", "inprogress", "large", "measure", "metrics", "pie", "statistics", "tracking" ] -}, { - "name" : "view_column", - "tags" : [ "column", "design", "format", "grid", "layout", "vertical", "view", "website" ] -}, { - "name" : "segment", - "tags" : [ "alignment", "fonts", "format", "lines", "list", "paragraph", "part", "piece", "rule", "rules", "segment", "style", "text" ] -}, { - "name" : "checkroom", - "tags" : [ "checkroom", "closet", "clothes", "coat check", "hanger" ] -}, { - "name" : "mode", - "tags" : [ "compose", "create", "draft", "draw", "edit", "mode", "pen", "pencil", "write" ] -}, { - "name" : "portrait", - "tags" : [ "account", "face", "human", "people", "person", "photo", "picture", "portrait", "profile", "user" ] -}, { - "name" : "camera_alt", - "tags" : [ "alt", "camera", "image", "photo", "photography", "picture" ] -}, { - "name" : "keyboard_double_arrow_left", - "tags" : [ "arrow", "arrows", "direction", "double", "left", "multiple", "navigation" ] -}, { - "name" : "delete_sweep", - "tags" : [ "bin", "can", "delete", "garbage", "remove", "sweep", "trash" ] -}, { - "name" : "hub", - "tags" : [ "center", "connection", "core", "focal point", "hub", "network", "nucleus", "topology" ] -}, { - "name" : "audiotrack", - "tags" : [ "audio", "audiotrack", "key", "music", "note", "sound", "track" ] -}, { - "name" : "calendar_view_month", - "tags" : [ "calendar", "date", "day", "event", "format", "grid", "layout", "month", "schedule", "today", "view" ] -}, { - "name" : "draw", - "tags" : [ "compose", "create", "design", "draft", "draw", "edit", "editing", "input", "pen", "pencil", "write", "writing" ] -}, { - "name" : "navigation", - "tags" : [ "destination", "direction", "location", "maps", "navigation", "pin", "place", "point", "stop" ] -}, { - "name" : "folder_shared", - "tags" : [ "account", "collaboration", "data", "doc", "document", "drive", "face", "file", "folder", "human", "people", "person", "profile", "share", "shared", "sheet", "slide", "storage", "team", "user" ] -}, { - "name" : "read_more", - "tags" : [ "arrow", "more", "read", "text" ] -}, { - "name" : "stacked_bar_chart", - "tags" : [ "analytics", "bar", "chart-chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "stacked", "statistics", "tracking" ] -}, { - "name" : "mode_comment", - "tags" : [ "bubble", "chat", "comment", "communicate", "feedback", "message", "mode comment", "speech" ] -}, { - "name" : "schedule_send", - "tags" : [ "calendar", "clock", "date", "email", "letter", "mail", "remember", "schedule", "send", "share", "time" ] -}, { - "name" : "bluetooth", - "tags" : [ "bluetooth", "cast", "connect", "connection", "device", "paring", "streaming", "symbol", "wireless" ] -}, { - "name" : "graphic_eq", - "tags" : [ "audio", "eq", "equalizer", "graphic", "music", "recording", "sound", "voice" ] -}, { - "name" : "markunread", - "tags" : [ "email", "envelop", "letter", "mail", "markunread", "message", "send", "unread" ] -}, { - "name" : "alarm_on", - "tags" : [ "alarm", "alert", "bell", "clock", "disabled", "duration", "enabled", "notification", "off", "on", "slash", "time", "timer", "watch" ] -}, { - "name" : "local_gas_station", - "tags" : [ "auto", "car", "gas", "local", "oil", "station", "vehicle" ] -}, { - "name" : "person_add_alt_1", - "tags" : [ ] -}, { - "name" : "maximize", - "tags" : [ "app", "application", "components", "design", "interface", "line", "maximize", "screen", "shape", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "bookmark_add", - "tags" : [ "+", "add", "bookmark", "favorite", "plus", "remember", "ribbon", "save", "symbol" ] -}, { - "name" : "dvr", - "tags" : [ "Android", "OS", "audio", "chrome", "computer", "desktop", "device", "display", "dvr", "electronic", "hardware", "iOS", "list", "mac", "monitor", "record", "recorder", "screen", "tv", "video", "web", "window" ] -}, { - "name" : "do_not_disturb_on", - "tags" : [ "cancel", "close", "denied", "deny", "disabled", "disturb", "do", "enabled", "off", "on", "remove", "silence", "slash", "stop" ] -}, { - "name" : "train", - "tags" : [ "automobile", "car", "cars", "direction", "maps", "public", "rail", "subway", "train", "transportation", "vehicle" ] -}, { - "name" : "person_pin_circle", - "tags" : [ "account", "circle", "destination", "direction", "face", "human", "location", "maps", "people", "person", "pin", "place", "profile", "stop", "user" ] -}, { - "name" : "square_foot", - "tags" : [ "construction", "feet", "foot", "inches", "length", "measurement", "ruler", "school", "set", "square", "tools" ] -}, { - "name" : "more_time", - "tags" : [ "+", "add", "clock", "date", "more", "new", "plus", "schedule", "symbol", "time" ] -}, { - "name" : "document_scanner", - "tags" : [ "article", "data", "doc", "document", "drive", "file", "folder", "folders", "notes", "page", "paper", "scan", "scanner", "sheet", "slide", "text", "writing" ] -}, { - "name" : "thumbs_up_down", - "tags" : [ "dislike", "down", "favorite", "fingers", "gesture", "hands", "like", "rate", "rating", "thumbs", "up" ] -}, { - "name" : "settings_ethernet", - "tags" : [ "arrows", "computer", "connect", "connection", "connectivity", "dots", "ethernet", "internet", "network", "settings", "wifi" ] -}, { - "name" : "sort_by_alpha", - "tags" : [ "alphabet", "alphabetize", "az", "by alpha", "character", "font", "letter", "list", "order", "organize", "sort", "symbol", "text", "type" ] -}, { - "name" : "theaters", - "tags" : [ "film", "movie", "movies", "show", "showtimes", "theater", "theaters", "watch" ] -}, { - "name" : "cloud_done", - "tags" : [ "app", "application", "approve", "backup", "check", "cloud", "complete", "connection", "done", "drive", "files", "folders", "internet", "mark", "network", "ok", "select", "sky", "storage", "tick", "upload", "validate", "verified", "yes" ] -}, { - "name" : "local_parking", - "tags" : [ "alphabet", "auto", "car", "character", "font", "garage", "letter", "local", "park", "parking", "symbol", "text", "type", "vehicle" ] -}, { - "name" : "view_agenda", - "tags" : [ "agenda", "cards", "design", "format", "grid", "layout", "stacked", "view", "website" ] -}, { - "name" : "mark_email_unread", - "tags" : [ "check", "circle", "email", "envelop", "letter", "mail", "mark", "message", "note", "notification", "send", "unread" ] -}, { - "name" : "local_florist", - "tags" : [ "florist", "flower", "local", "shop" ] -}, { - "name" : "connect_without_contact", - "tags" : [ "communicating", "connect", "contact", "distance", "people", "signal", "social", "socialize", "without" ] -}, { - "name" : "thumb_down_off_alt", - "tags" : [ "disabled", "dislike", "down", "enabled", "favorite", "filled", "fingers", "gesture", "hand", "hands", "like", "off", "offline", "on", "rank", "ranking", "rate", "rating", "slash", "thumb" ] -}, { - "name" : "sentiment_neutral", - "tags" : [ "emotionless", "emotions", "expressions", "face", "feelings", "fine", "indifference", "mood", "neutral", "okay", "person", "sentiment", "survey" ] -}, { - "name" : "call_end", - "tags" : [ "call", "cell", "contact", "device", "end", "hardware", "mobile", "phone", "telephone" ] -}, { - "name" : "subdirectory_arrow_right", - "tags" : [ "arrow", "directory", "down", "navigation", "right", "sub", "subdirectory" ] -}, { - "name" : "diamond", - "tags" : [ "diamond", "fashion", "gems", "jewelry", "logo", "retail", "valuable", "valuables" ] -}, { - "name" : "podcasts", - "tags" : [ "broadcast", "casting", "network", "podcasts", "signal", "transmitting", "wireless" ] -}, { - "name" : "monitor_heart", - "tags" : [ "baseline", "device", "ecc", "ecg", "fitness", "health", "heart", "medical", "monitor", "track" ] -}, { - "name" : "all_inclusive", - "tags" : [ "all", "endless", "forever", "inclusive", "infinity", "loop", "mobius", "neverending", "strip", "sustainability", "sustainable" ] -}, { - "name" : "wc", - "tags" : [ "bathroom", "closet", "female", "male", "man", "restroom", "room", "wash", "water", "wc", "women" ] -}, { - "name" : "grass", - "tags" : [ "backyard", "fodder", "grass", "ground", "home", "lawn", "plant", "turf", "yard" ] -}, { - "name" : "important_devices", - "tags" : [ "Android", "OS", "desktop", "devices", "hardware", "iOS", "important", "mobile", "monitor", "phone", "star", "tablet", "web" ] -}, { - "name" : "back_hand", - "tags" : [ "back", "fingers", "gesture", "hand", "raised" ] -}, { - "name" : "hiking", - "tags" : [ "backpacking", "bag", "climbing", "duffle", "hiking", "mountain", "social", "sports", "stick", "trail", "travel", "walking" ] -}, { - "name" : "masks", - "tags" : [ "air", "cover", "covid", "face", "hospital", "masks", "medical", "pollution", "protection", "respirator", "sick", "social" ] -}, { - "name" : "waving_hand", - "tags" : [ "bye", "fingers", "gesture", "goodbye", "greetings", "hand", "hello", "palm", "wave", "waving" ] -}, { - "name" : "architecture", - "tags" : [ "architecture", "art", "compass", "design", "draw", "drawing", "engineering", "geometric", "tool" ] -}, { - "name" : "local_post_office", - "tags" : [ "delivery", "email", "envelop", "letter", "local", "mail", "message", "office", "package", "parcel", "post", "postal", "send", "stamp" ] -}, { - "name" : "functions", - "tags" : [ "average", "calculate", "count", "custom", "doc", "edit", "editing", "editor", "functions", "math", "sheet", "spreadsheet", "style", "sum", "text", "type", "writing" ] -}, { - "name" : "directions", - "tags" : [ "arrow", "directions", "maps", "right", "route", "sign", "traffic" ] -}, { - "name" : "money", - "tags" : [ "100", "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "digit", "dollars", "finance", "money", "number", "online", "pay", "payment", "price", "shopping", "symbol" ] -}, { - "name" : "unpublished", - "tags" : [ "approve", "check", "circle", "complete", "disabled", "done", "enabled", "mark", "off", "ok", "on", "select", "slash", "tick", "unpublished", "validate", "verified", "yes" ] -}, { - "name" : "notifications_off", - "tags" : [ "active", "alarm", "alert", "bell", "chime", "disabled", "enabled", "notifications", "notify", "off", "offline", "on", "reminder", "ring", "slash", "sound" ] -}, { - "name" : "airport_shuttle", - "tags" : [ "airport", "automobile", "car", "cars", "commercial", "delivery", "direction", "maps", "mini", "public", "shuttle", "transport", "transportation", "travel", "truck", "van", "vehicle" ] -}, { - "name" : "insert_link", - "tags" : [ "add", "attach", "clip", "file", "insert", "link", "mail", "media" ] -}, { - "name" : "thumb_down_alt", - "tags" : [ "bad", "decline", "disapprove", "dislike", "down", "feedback", "hate", "negative", "no", "reject", "social", "thumb", "veto", "vote" ] -}, { - "name" : "two_wheeler", - "tags" : [ "automobile", "bike", "car", "cars", "direction", "maps", "motorcycle", "public", "scooter", "sport", "transportation", "travel", "two wheeler", "vehicle" ] -}, { - "name" : "nightlight", - "tags" : [ "dark", "disturb", "mode", "moon", "night", "nightlight", "sleep" ] -}, { - "name" : "mic_none", - "tags" : [ "hear", "hearing", "mic", "microphone", "noise", "none", "record", "sound", "voice" ] -}, { - "name" : "keyboard_double_arrow_down", - "tags" : [ "arrow", "arrows", "direction", "double", "down", "multiple", "navigation" ] -}, { - "name" : "invert_colors", - "tags" : [ "colors", "drop", "droplet", "edit", "editing", "hue", "invert", "inverted", "palette", "tone", "water" ] -}, { - "name" : "clear_all", - "tags" : [ "all", "clear", "doc", "document", "format", "lines", "list" ] -}, { - "name" : "mouse", - "tags" : [ "click", "computer", "cursor", "device", "hardware", "mouse", "wireless" ] -}, { - "name" : "mode_edit_outline", - "tags" : [ "compose", "create", "draft", "draw", "edit", "mode", "outline", "pen", "pencil", "write" ] -}, { - "name" : "open_in_browser", - "tags" : [ "arrow", "browser", "in", "open", "site", "up", "web", "website", "window" ] -}, { - "name" : "insert_invitation", - "tags" : [ "calendar", "date", "day", "event", "insert", "invitation", "mark", "month", "range", "remember", "reminder", "today", "week" ] -}, { - "name" : "fast_rewind", - "tags" : [ "back", "control", "fast", "media", "music", "play", "rewind", "speed", "time", "tv", "video" ] -}, { - "name" : "opacity", - "tags" : [ "color", "drop", "droplet", "hue", "invert", "inverted", "opacity", "palette", "tone", "water" ] -}, { - "name" : "video_camera_front", - "tags" : [ "account", "camera", "face", "front", "human", "image", "people", "person", "photo", "photography", "picture", "profile", "user", "video" ] -}, { - "name" : "commute", - "tags" : [ "automobile", "car", "commute", "direction", "maps", "public", "train", "transportation", "trip", "vehicle" ] -}, { - "name" : "addchart", - "tags" : [ "+", "addchart", "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "new", "plus", "statistics", "symbol", "tracking" ] -}, { - "name" : "no_accounts", - "tags" : [ "account", "accounts", "avatar", "disabled", "enabled", "face", "human", "no", "off", "offline", "on", "people", "person", "profile", "slash", "thumbnail", "unavailable", "unidentifiable", "unknown", "user" ] -}, { - "name" : "coffee", - "tags" : [ "beverage", "coffee", "cup", "drink", "mug", "plate", "set", "tea" ] -}, { - "name" : "luggage", - "tags" : [ "airport", "bag", "baggage", "carry", "flight", "hotel", "luggage", "on", "suitcase", "travel", "trip" ] -}, { - "name" : "workspaces", - "tags" : [ "circles", "collaboration", "dot", "filled", "group", "outline", "space", "team", "work", "workspaces" ] -}, { - "name" : "child_care", - "tags" : [ "babies", "baby", "care", "child", "children", "face", "infant", "kids", "newborn", "toddler", "young" ] -}, { - "name" : "sports_score", - "tags" : [ "destination", "flag", "goal", "score", "sports" ] -}, { - "name" : "library_music", - "tags" : [ "add", "album", "collection", "library", "music", "song", "sounds" ] -}, { - "name" : "history_toggle_off", - "tags" : [ "clock", "date", "history", "off", "schedule", "time", "toggle" ] -}, { - "name" : "system_update_alt", - "tags" : [ "arrow", "down", "download", "export", "system", "update" ] -}, { - "name" : "access_time", - "tags" : [ ] -}, { - "name" : "rotate_right", - "tags" : [ "around", "arrow", "direction", "inprogress", "load", "loading refresh", "renew", "right", "rotate", "turn" ] -}, { - "name" : "color_lens", - "tags" : [ "art", "color", "lens", "paint", "pallet" ] -}, { - "name" : "grid_on", - "tags" : [ "collage", "disabled", "enabled", "grid", "image", "layout", "off", "on", "slash", "view" ] -}, { - "name" : "crop_free", - "tags" : [ "adjust", "adjustments", "crop", "edit", "editing", "focus", "frame", "free", "image", "photo", "photos", "settings", "size", "zoom" ] -}, { - "name" : "cloud_queue", - "tags" : [ "cloud", "connection", "internet", "network", "queue", "sky", "upload" ] -}, { - "name" : "keyboard_voice", - "tags" : [ "keyboard", "mic", "microphone", "noise", "record", "recorder", "speaker", "voice" ] -}, { - "name" : "format_align_left", - "tags" : [ "align", "alignment", "doc", "edit", "editing", "editor", "format", "left", "sheet", "spreadsheet", "text", "type", "writing" ] -}, { - "name" : "view_week", - "tags" : [ "bars", "columns", "design", "format", "grid", "layout", "view", "website", "week" ] -}, { - "name" : "real_estate_agent", - "tags" : [ "agent", "architecture", "broker", "estate", "hand", "home", "house", "loan", "mortgage", "property", "real", "residence", "residential", "sales", "social" ] -}, { - "name" : "horizontal_rule", - "tags" : [ "gmail", "horizontal", "line", "novitas", "rule" ] -}, { - "name" : "topic", - "tags" : [ "data", "doc", "document", "drive", "file", "folder", "sheet", "slide", "storage", "topic" ] -}, { - "name" : "shower", - "tags" : [ "bath", "bathroom", "closet", "home", "house", "place", "plumbing", "room", "shower", "sprinkler", "wash", "water", "wc" ] -}, { - "name" : "format_italic", - "tags" : [ "alphabet", "character", "doc", "edit", "editing", "editor", "font", "format", "italic", "letter", "sheet", "spreadsheet", "style", "symbol", "text", "type", "writing" ] -}, { - "name" : "traffic", - "tags" : [ "direction", "light", "maps", "signal", "street", "traffic" ] -}, { - "name" : "add_business", - "tags" : [ "+", "add", "bill", "building", "business", "card", "cash", "coin", "commerce", "company", "credit", "currency", "dollars", "market", "money", "new", "online", "pay", "payment", "plus", "shop", "shopping", "store", "storefront", "symbol" ] -}, { - "name" : "electrical_services", - "tags" : [ "charge", "cord", "electric", "electrical", "plug", "power", "services", "wire" ] -}, { - "name" : "timelapse", - "tags" : [ "duration", "motion", "photo", "time", "timelapse", "timer", "video" ] -}, { - "name" : "youtube_searched_for", - "tags" : [ "arrow", "back", "backwards", "find", "glass", "history", "inprogress", "load", "loading", "look", "magnify", "magnifying", "refresh", "renew", "restore", "reverse", "rotate", "search", "see", "youtube" ] -}, { - "name" : "front_hand", - "tags" : [ "fingers", "front", "gesture", "hand", "hello", "palm", "stop" ] -}, { - "name" : "yard", - "tags" : [ "backyard", "flower", "garden", "home", "house", "nature", "pettle", "plants", "yard" ] -}, { - "name" : "tour", - "tags" : [ "destination", "flag", "places", "tour", "travel", "visit" ] -}, { - "name" : "factory", - "tags" : [ "factory", "industry", "manufacturing", "warehouse" ] -}, { - "name" : "developer_board", - "tags" : [ "board", "chip", "computer", "developer", "development", "hardware", "microchip", "processor" ] -}, { - "name" : "more", - "tags" : [ "3", "archive", "bookmark", "dots", "etc", "favorite", "indent", "label", "more", "remember", "save", "stamp", "sticker", "tab", "tag", "three" ] -}, { - "name" : "star_purple500", - "tags" : [ "500", "best", "bookmark", "favorite", "highlight", "purple", "ranking", "rate", "rating", "save", "star", "toggle" ] -}, { - "name" : "format_color_fill", - "tags" : [ "bucket", "color", "doc", "edit", "editing", "editor", "fill", "format", "paint", "sheet", "spreadsheet", "style", "text", "type", "writing" ] -}, { - "name" : "beach_access", - "tags" : [ "access", "beach", "places", "summer", "sunny", "umbrella" ] -}, { - "name" : "local_bar", - "tags" : [ "alcohol", "bar", "bottle", "club", "cocktail", "drink", "food", "liquor", "local", "wine" ] -}, { - "name" : "add_link", - "tags" : [ "add", "attach", "clip", "link", "new", "plus", "symbol" ] -}, { - "name" : "landscape", - "tags" : [ "image", "landscape", "mountain", "mountains", "nature", "photo", "photography", "picture" ] -}, { - "name" : "slideshow", - "tags" : [ "movie", "photos", "play", "slideshow", "square", "video", "view" ] -}, { - "name" : "stream", - "tags" : [ "cast", "connected", "feed", "live", "network", "signal", "stream", "wireless" ] -}, { - "name" : "videocam_off", - "tags" : [ "cam", "camera", "conference", "disabled", "enabled", "film", "filming", "hardware", "image", "motion", "off", "offline", "on", "picture", "slash", "video", "videography" ] -}, { - "name" : "directions_boat", - "tags" : [ "automobile", "boat", "car", "cars", "direction", "directions", "ferry", "maps", "public", "transportation", "vehicle" ] -}, { - "name" : "download_done", - "tags" : [ "arrow", "arrows", "check", "done", "down", "download", "downloads", "drive", "install", "installed", "ok", "tick", "upload" ] -}, { - "name" : "volume_down", - "tags" : [ "audio", "control", "down", "music", "sound", "speaker", "tv", "volume" ] -}, { - "name" : "alt_route", - "tags" : [ "alt", "alternate", "alternative", "arrows", "direction", "maps", "navigation", "options", "other", "route", "routes", "split", "symbol" ] -}, { - "name" : "mood_bad", - "tags" : [ "bad", "disappointment", "dislike", "emoji", "emotions", "expressions", "face", "feelings", "mood", "person", "rating", "social", "survey", "unhappiness", "unhappy", "unpleased", "unsmile", "unsmiling" ] -}, { - "name" : "vaccines", - "tags" : [ "aid", "covid", "doctor", "drug", "emergency", "hospital", "immunity", "injection", "medical", "medication", "medicine", "needle", "pharmacy", "sick", "syringe", "vaccination", "vaccines", "vial" ] -}, { - "name" : "dialpad", - "tags" : [ "buttons", "call", "contact", "device", "dial", "dialpad", "dots", "mobile", "numbers", "pad", "phone" ] -}, { - "name" : "route", - "tags" : [ "directions", "maps", "path", "route", "sign", "traffic" ] -}, { - "name" : "hide_source", - "tags" : [ "circle", "disabled", "enabled", "hide", "off", "offline", "on", "shape", "slash", "source" ] -}, { - "name" : "bookmark_added", - "tags" : [ "added", "approve", "bookmark", "check", "complete", "done", "favorite", "mark", "ok", "remember", "save", "select", "tick", "validate", "verified", "yes" ] -}, { - "name" : "mark_as_unread", - "tags" : [ "as", "envelop", "letter", "mail", "mark", "post", "postal", "read", "receive", "send", "unread" ] -}, { - "name" : "plagiarism", - "tags" : [ "doc", "document", "find", "glass", "look", "magnifying", "page", "paper", "plagiarism", "search", "see" ] -}, { - "name" : "turned_in", - "tags" : [ "archive", "bookmark", "favorite", "in", "label", "library", "read", "reading", "remember", "ribbon", "save", "tag", "turned" ] -}, { - "name" : "settings_input_antenna", - "tags" : [ "airplay", "antenna", "arrows", "cast", "computer", "connect", "connection", "connectivity", "dots", "input", "internet", "network", "screencast", "settings", "stream", "wifi", "wireless" ] -}, { - "name" : "shop", - "tags" : [ "bag", "bill", "buy", "card", "cart", "cash", "coin", "commerce", "credit", "currency", "dollars", "google", "money", "online", "pay", "payment", "play", "shop", "shopping", "store" ] -}, { - "name" : "pool", - "tags" : [ "athlete", "athletic", "beach", "body", "entertainment", "exercise", "hobby", "human", "ocean", "people", "person", "places", "pool", "sea", "sports", "swim", "swimming", "water" ] -}, { - "name" : "search_off", - "tags" : [ "cancel", "close", "disabled", "enabled", "find", "glass", "look", "magnify", "magnifying", "off", "on", "search", "see", "slash", "stop", "x" ] -}, { - "name" : "approval", - "tags" : [ "apply", "approval", "approvals", "approve", "certificate", "certification", "disapproval", "drive", "file", "impression", "ink", "mark", "postage", "stamp" ] -}, { - "name" : "currency_rupee", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "price", "rupee", "shopping", "symbol" ] -}, { - "name" : "power", - "tags" : [ "charge", "cord", "electric", "electrical", "outlet", "plug", "power" ] -}, { - "name" : "collections_bookmark", - "tags" : [ "album", "archive", "bookmark", "collections", "favorite", "gallery", "label", "library", "read", "reading", "remember", "ribbon", "save", "stack", "tag" ] -}, { - "name" : "not_started", - "tags" : [ "circle", "media", "not", "pause", "play", "started", "video" ] -}, { - "name" : "pedal_bike", - "tags" : [ "automobile", "bicycle", "bike", "car", "cars", "direction", "human", "maps", "pedal", "public", "route", "scooter", "transportation", "vehicle", "vespa" ] -}, { - "name" : "water", - "tags" : [ "aqua", "beach", "lake", "ocean", "river", "water", "waves", "weather" ] -}, { - "name" : "router", - "tags" : [ "box", "cable", "connection", "hardware", "internet", "network", "router", "signal", "wifi" ] -}, { - "name" : "flight_land", - "tags" : [ "airport", "arrival", "arriving", "flight", "fly", "land", "landing", "plane", "transportation", "travel" ] -}, { - "name" : "shopping_cart_checkout", - "tags" : [ "arrow", "cart", "cash", "checkout", "coin", "commerce", "currency", "dollars", "money", "online", "pay", "payment", "right", "shopping" ] -}, { - "name" : "agriculture", - "tags" : [ "agriculture", "automobile", "car", "cars", "cultivation", "farm", "harvest", "maps", "tractor", "transport", "travel", "truck", "vehicle" ] -}, { - "name" : "where_to_vote", - "tags" : [ "approve", "ballot", "check", "complete", "destination", "direction", "done", "location", "maps", "mark", "ok", "pin", "place", "poll", "select", "stop", "tick", "to", "validate election", "verified", "vote", "where", "yes" ] -}, { - "name" : "beenhere", - "tags" : [ "approve", "archive", "beenhere", "bookmark", "check", "complete", "done", "favorite", "label", "library", "mark", "ok", "read", "reading", "remember", "ribbon", "save", "select", "tag", "tick", "validate", "verified", "yes" ] -}, { - "name" : "add_comment", - "tags" : [ "+", "add", "bubble", "chat", "comment", "communicate", "feedback", "message", "new", "plus", "speech", "symbol" ] -}, { - "name" : "copy_all", - "tags" : [ "all", "content", "copy", "cut", "doc", "document", "file", "multiple", "page", "paper", "past" ] -}, { - "name" : "dynamic_feed", - "tags" : [ "'mail_outline'", "'markunread'. Keep 'mail' and remove others.", "Duplicate of 'email'" ] -}, { - "name" : "videogame_asset", - "tags" : [ "asset", "console", "controller", "device", "game", "gamepad", "gaming", "playstation", "video" ] -}, { - "name" : "move_to_inbox", - "tags" : [ "archive", "arrow", "down", "email", "envelop", "inbox", "incoming", "letter", "mail", "message", "move to", "send" ] -}, { - "name" : "crop_square", - "tags" : [ "adjust", "adjustments", "app", "application", "area", "components", "crop", "design", "edit", "editing", "expand", "frame", "image", "images", "interface", "open", "photo", "photos", "rectangle", "screen", "settings", "shape", "shapes", "site", "size", "square", "ui", "ux", "web", "website", "window" ] -}, { - "name" : "recent_actors", - "tags" : [ "account", "actors", "avatar", "card", "cards", "carousel", "face", "human", "layers", "list", "people", "person", "profile", "recent", "thumbnail", "user" ] -}, { - "name" : "emoji_nature", - "tags" : [ "animal", "bee", "bug", "daisy", "emoji", "flower", "insect", "ladybug", "nature", "petals", "spring", "summer" ] -}, { - "name" : "cloud_off", - "tags" : [ "app", "application", "backup", "cloud", "connection", "disabled", "drive", "enabled", "files", "folders", "internet", "network", "off", "offline", "on", "sky", "slash", "storage", "upload" ] -}, { - "name" : "panorama_fish_eye", - "tags" : [ "angle", "circle", "eye", "fish", "image", "panorama", "photo", "photography", "picture", "wide" ] -}, { - "name" : "lens", - "tags" : [ "circle", "full", "geometry", "lens", "moon" ] -}, { - "name" : "360", - "tags" : [ "360", "arrow", "av", "camera", "direction", "rotate", "rotation", "vr" ] -}, { - "name" : "share_location", - "tags" : [ "destination", "direction", "gps", "location", "maps", "pin", "place", "share", "stop", "tracking" ] -}, { - "name" : "assignment_late", - "tags" : [ "!", "alert", "assignment", "attention", "caution", "clipboard", "danger", "doc", "document", "error", "exclamation", "important", "late", "mark", "notification", "symbol", "warning" ] -}, { - "name" : "switch_account", - "tags" : [ "account", "choices", "face", "human", "multiple", "options", "people", "person", "profile", "social", "switch", "user" ] -}, { - "name" : "looks_two", - "tags" : [ "2", "digit", "looks", "numbers", "square", "symbol" ] -}, { - "name" : "do_not_disturb", - "tags" : [ "cancel", "close", "denied", "deny", "disturb", "do", "remove", "silence", "stop" ] -}, { - "name" : "donut_small", - "tags" : [ "analytics", "chart", "data", "diagram", "donut", "graph", "infographic", "inprogress", "measure", "metrics", "pie", "small", "statistics", "tracking" ] -}, { - "name" : "saved_search", - "tags" : [ "find", "glass", "important", "look", "magnify", "magnifying", "marked", "saved", "search", "see", "star" ] -}, { - "name" : "contactless", - "tags" : [ "bluetooth", "cash", "connect", "connection", "connectivity", "contact", "contactless", "credit", "device", "finance", "pay", "payment", "signal", "transaction", "wifi", "wireless" ] -}, { - "name" : "highlight_alt", - "tags" : [ "alt", "arrow", "box", "click", "cursor", "draw", "focus", "highlight", "pointer", "select", "selection", "target" ] -}, { - "name" : "assignment_return", - "tags" : [ "arrow", "assignment", "back", "clipboard", "doc", "document", "left", "retun" ] -}, { - "name" : "kitchen", - "tags" : [ "appliance", "cold", "food", "fridge", "home", "house", "ice", "kitchen", "places", "refrigerator", "storage" ] -}, { - "name" : "warehouse", - "tags" : [ "garage", "industry", "manufacturing", "storage", "warehouse" ] -}, { - "name" : "liquor", - "tags" : [ "alcohol", "bar", "bottle", "club", "cocktail", "drink", "food", "liquor", "party", "store", "wine" ] -}, { - "name" : "gpp_maybe", - "tags" : [ "!", "alert", "attention", "caution", "certified", "danger", "error", "exclamation", "gpp", "important", "mark", "maybe", "notification", "privacy", "private", "protect", "protection", "security", "shield", "sim", "symbol", "verified", "warning" ] -}, { - "name" : "settings_input_component", - "tags" : [ "audio", "av", "cable", "cables", "component", "connect", "connection", "connectivity", "input", "internet", "plug", "points", "settings", "video", "wifi" ] -}, { - "name" : "waves", - "tags" : [ "beach", "lake", "ocean", "pool", "river", "sea", "swim", "water", "wave", "waves" ] -}, { - "name" : "hotel_class", - "tags" : [ "achievement", "bookmark", "class", "favorite", "highlight", "hotel", "important", "marked", "rank", "ranking", "rate", "rating", "reward", "save", "saved", "shape", "special", "star" ] -}, { - "name" : "web_asset", - "tags" : [ "-website", "app", "application desktop", "asset", "browser", "design", "download", "image", "interface", "internet", "layout", "screen", "site", "ui", "ux", "video", "web", "website", "window", "www" ] -}, { - "name" : "view_carousel", - "tags" : [ "cards", "carousel", "design", "format", "grid", "layout", "view", "website" ] -}, { - "name" : "anchor", - "tags" : [ "anchor", "google", "logo" ] -}, { - "name" : "filter_alt_off", - "tags" : [ "alt", "disabled", "edit", "filter", "funnel", "off", "offline", "options", "refine", "sift", "slash" ] -}, { - "name" : "balance", - "tags" : [ "balance", "equal", "equity", "impartiality", "justice", "parity", "stability. equilibrium", "steadiness", "symmetry" ] -}, { - "name" : "view_quilt", - "tags" : [ "design", "format", "grid", "layout", "quilt", "square", "squares", "stacked", "view", "website" ] -}, { - "name" : "library_add_check", - "tags" : [ "add", "approve", "check", "collection", "complete", "done", "layers", "library", "mark", "multiple", "music", "ok", "select", "stacked", "tick", "validate", "verified", "video", "yes" ] -}, { - "name" : "queue_music", - "tags" : [ "collection", "list", "music", "playlist", "queue" ] -}, { - "name" : "casino", - "tags" : [ "casino", "dice", "dots", "entertainment", "gamble", "gambling", "game", "games", "luck", "places" ] -}, { - "name" : "hearing", - "tags" : [ "accessibility", "accessible", "aid", "ear", "handicap", "hearing", "help", "impaired", "listen", "sound", "volume" ] -}, { - "name" : "phone_enabled", - "tags" : [ "call", "cell", "contact", "device", "enabled", "hardware", "mobile", "phone", "telephone" ] -}, { - "name" : "linear_scale", - "tags" : [ "app", "application", "components", "design", "interface", "layout", "linear", "measure", "menu", "scale", "screen", "site", "slider", "ui", "ux", "web", "website", "window" ] -}, { - "name" : "holiday_village", - "tags" : [ "architecture", "beach", "camping", "cottage", "estate", "holiday", "home", "house", "lake", "lodge", "maps", "place", "real", "residence", "residential", "stay", "traveling", "vacation", "village" ] -}, { - "name" : "turned_in_not", - "tags" : [ "archive", "bookmark", "favorite", "in", "label", "library", "not", "read", "reading", "remember", "ribbon", "save", "tag", "turned" ] -}, { - "name" : "sync_problem", - "tags" : [ "!", "360", "alert", "around", "arrow", "arrows", "attention", "caution", "danger", "direction", "error", "exclamation", "important", "inprogress", "load", "loading refresh", "mark", "notification", "problem", "renew", "rotate", "symbol", "sync", "turn", "warning" ] -}, { - "name" : "start", - "tags" : [ "arrow", "keyboard", "next", "right", "start" ] -}, { - "name" : "all_inbox", - "tags" : [ "Inbox", "all", "delivered", "delivery", "email", "mail", "message", "send" ] -}, { - "name" : "mediation", - "tags" : [ "arrow", "arrows", "direction", "dots", "mediation", "right" ] -}, { - "name" : "edit_off", - "tags" : [ "compose", "create", "disabled", "draft", "edit", "editing", "enabled", "input", "new", "off", "offline", "on", "pen", "pencil", "slash", "write", "writing" ] -}, { - "name" : "emergency", - "tags" : [ "asterisk", "clinic", "emergency", "health", "hospital", "maps", "medical", "symbol" ] -}, { - "name" : "settings_remote", - "tags" : [ "bluetooth", "connection", "connectivity", "device", "remote", "settings", "signal", "wifi", "wireless" ] -}, { - "name" : "drive_file_move", - "tags" : [ "arrow", "data", "doc", "document", "drive", "file", "folder", "move", "right", "sheet", "slide", "storage" ] -}, { - "name" : "fit_screen", - "tags" : [ "enlarge", "fit", "format", "layout", "reduce", "scale", "screen", "size" ] -}, { - "name" : "hourglass_full", - "tags" : [ "countdown", "full", "hourglass", "loading", "minutes", "time", "wait", "waiting" ] -}, { - "name" : "nights_stay", - "tags" : [ "climate", "cloud", "crescent", "dark", "lunar", "mode", "moon", "nights", "phases", "silence", "silent", "sky", "stay", "time", "weather" ] -}, { - "name" : "pause_circle_filled", - "tags" : [ "circle", "control", "controls", "filled", "media", "music", "pause", "video" ] -}, { - "name" : "catching_pokemon", - "tags" : [ "catching", "go", "pokemon", "pokestop", "travel" ] -}, { - "name" : "king_bed", - "tags" : [ "bed", "bedroom", "double", "furniture", "home", "hotel", "house", "king", "night", "pillows", "queen", "rest", "room", "sleep" ] -}, { - "name" : "flaky", - "tags" : [ "approve", "check", "close", "complete", "contrast", "done", "exit", "flaky", "mark", "no", "ok", "options", "select", "stop", "tick", "verified", "x", "yes" ] -}, { - "name" : "format_size", - "tags" : [ "alphabet", "character", "color", "doc", "edit", "editing", "editor", "fill", "font", "format", "letter", "paint", "sheet", "size", "spreadsheet", "style", "symbol", "text", "type", "writing" ] -}, { - "name" : "interests", - "tags" : [ "circle", "heart", "interests", "shapes", "social", "square", "triangle" ] -}, { - "name" : "stacked_line_chart", - "tags" : [ "analytics", "chart", "data", "diagram", "graph", "infographic", "line", "measure", "metrics", "stacked", "statistics", "tracking" ] -}, { - "name" : "unarchive", - "tags" : [ "archive", "arrow", "inbox", "mail", "store", "unarchive", "undo", "up" ] -}, { - "name" : "subtitles", - "tags" : [ "accessible", "caption", "cc", "character", "closed", "decoder", "language", "media", "movies", "subtitle", "subtitles", "tv" ] -}, { - "name" : "toll", - "tags" : [ "bill", "booth", "car", "card", "cash", "coin", "commerce", "credit", "currency", "dollars", "highway", "money", "online", "pay", "payment", "ticket", "toll" ] -}, { - "name" : "keyboard_double_arrow_up", - "tags" : [ "arrow", "arrows", "direction", "double", "multiple", "navigation", "up" ] -}, { - "name" : "time_to_leave", - "tags" : [ "automobile", "car", "cars", "destination", "direction", "drive", "estimate", "eta", "maps", "public", "transportation", "travel", "trip", "vehicle" ] -}, { - "name" : "location_searching", - "tags" : [ "destination", "direction", "location", "maps", "pin", "place", "pointer", "searching", "stop", "tracking" ] -}, { - "name" : "cable", - "tags" : [ "cable", "connect", "connection", "device", "electronics", "usb", "wire" ] -}, { - "name" : "moving", - "tags" : [ "arrow", "direction", "moving", "navigation", "travel", "up" ] -}, { - "name" : "remove_shopping_cart", - "tags" : [ "card", "cart", "cash", "checkout", "coin", "commerce", "credit", "currency", "disabled", "dollars", "enabled", "off", "on", "online", "pay", "payment", "remove", "shopping", "slash", "tick" ] -}, { - "name" : "cast_for_education", - "tags" : [ "Android", "OS", "airplay", "cast", "chrome", "connect", "desktop", "device", "display", "education", "for", "hardware", "iOS", "learning", "lessons teaching", "mac", "monitor", "screen", "screencast", "streaming", "television", "tv", "web", "window", "wireless" ] -}, { - "name" : "fiber_new", - "tags" : [ "alphabet", "character", "fiber", "font", "letter", "network", "new", "symbol", "text", "type" ] -}, { - "name" : "format_underlined", - "tags" : [ "alphabet", "character", "doc", "edit", "editing", "editor", "font", "format", "letter", "line", "sheet", "spreadsheet", "style", "symbol", "text", "type", "under", "underlined", "writing" ] -}, { - "name" : "pause_circle_outline", - "tags" : [ "circle", "control", "controls", "media", "music", "outline", "pause", "video" ] -}, { - "name" : "mark_chat_unread", - "tags" : [ "bubble", "chat", "circle", "comment", "communicate", "mark", "message", "notification", "speech", "unread" ] -}, { - "name" : "insert_comment", - "tags" : [ "add", "bubble", "chat", "comment", "feedback", "insert", "message" ] -}, { - "name" : "cameraswitch", - "tags" : [ "arrows", "camera", "cameraswitch", "flip", "rotate", "swap", "switch", "view" ] -}, { - "name" : "rocket", - "tags" : [ "rocket", "space", "spaceship" ] -}, { - "name" : "local_airport", - "tags" : [ "air", "airplane", "airport", "flight", "plane", "transportation", "travel", "trip" ] -}, { - "name" : "lock_clock", - "tags" : [ "clock", "date", "lock", "locked", "password", "privacy", "private", "protection", "safety", "schedule", "secure", "security", "time" ] -}, { - "name" : "device_hub", - "tags" : [ "Android", "OS", "circle", "computer", "desktop", "device", "hardware", "hub", "iOS", "laptop", "mobile", "monitor", "phone", "square", "tablet", "triangle", "watch", "wearable", "web" ] -}, { - "name" : "filter_vintage", - "tags" : [ "edit", "editing", "effect", "filter", "flower", "image", "images", "photography", "picture", "pictures", "vintage" ] -}, { - "name" : "sailing", - "tags" : [ "boat", "entertainment", "fishing", "hobby", "ocean", "sailboat", "sailing", "sea", "social sports", "travel", "water" ] -}, { - "name" : "roofing", - "tags" : [ "architecture", "building", "chimney", "construction", "estate", "home", "house", "real", "residence", "residential", "roof", "roofing", "service", "shelter" ] -}, { - "name" : "settings_voice", - "tags" : [ "mic", "microphone", "record", "recorder", "settings", "speaker", "voice" ] -}, { - "name" : "swap_horizontal_circle", - "tags" : [ "arrow", "arrows", "back", "circle", "forward", "horizontal", "swap" ] -}, { - "name" : "add_location_alt", - "tags" : [ "+", "add", "alt", "destination", "direction", "location", "maps", "new", "pin", "place", "plus", "stop", "symbol" ] -}, { - "name" : "room_service", - "tags" : [ "alert", "bell", "delivery", "hotel", "notify", "room", "service" ] -}, { - "name" : "content_paste_search", - "tags" : [ "clipboard", "content", "doc", "document", "file", "find", "paste", "search", "trace", "track" ] -}, { - "name" : "reply_all", - "tags" : [ "all", "arrow", "backward", "group", "left", "mail", "message", "multiple", "reply", "send", "share" ] -}, { - "name" : "compost", - "tags" : [ "bio", "compost", "compostable", "decomposable", "decompose", "eco", "green", "leaf", "leafs", "nature", "organic", "plant", "recycle", "sustainability", "sustainable" ] -}, { - "name" : "bubble_chart", - "tags" : [ "analytics", "bar", "bars", "bubble", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "statistics", "tracking" ] -}, { - "name" : "compare", - "tags" : [ "adjust", "adjustment", "compare", "edit", "editing", "edits", "enhance", "fix", "image", "images", "photo", "photography", "photos", "scan", "settings" ] -}, { - "name" : "money_off", - "tags" : [ "bill", "card", "cart", "cash", "coin", "commerce", "credit", "currency", "disabled", "dollars", "enabled", "money", "off", "on", "online", "pay", "payment", "shopping", "slash", "symbol" ] -}, { - "name" : "file_open", - "tags" : [ "arrow", "doc", "document", "drive", "file", "left", "open", "page", "paper" ] -}, { - "name" : "filter_drama", - "tags" : [ "cloud", "drama", "edit", "editing", "effect", "filter", "image", "photo", "photography", "picture", "sky camera" ] -}, { - "name" : "shortcut", - "tags" : [ "arrow", "direction", "forward", "right", "shortcut" ] -}, { - "name" : "view_sidebar", - "tags" : [ "design", "format", "grid", "layout", "sidebar", "view", "web" ] -}, { - "name" : "looks_3", - "tags" : [ "3", "digit", "looks", "numbers", "square", "symbol" ] -}, { - "name" : "note", - "tags" : [ "bookmark", "message", "note", "paper" ] -}, { - "name" : "vertical_align_bottom", - "tags" : [ "align", "alignment", "arrow", "bottom", "doc", "down", "edit", "editing", "editor", "sheet", "spreadsheet", "text", "type", "vertical", "writing" ] -}, { - "name" : "3p", - "tags" : [ "3", "3p", "account", "avatar", "bubble", "chat", "comment", "communicate", "face", "human", "message", "party", "people", "person", "profile", "speech", "user" ] -}, { - "name" : "online_prediction", - "tags" : [ "bulb", "connection", "idea", "light", "network", "online", "prediction", "signal", "wireless" ] -}, { - "name" : "cancel_presentation", - "tags" : [ "cancel", "close", "device", "exit", "no", "present", "presentation", "quit", "remove", "screen", "slide", "stop", "website", "window", "x" ] -}, { - "name" : "select_all", - "tags" : [ "all", "select", "selection", "square", "tool" ] -}, { - "name" : "event_seat", - "tags" : [ "assign", "assigned", "chair", "event", "furniture", "reservation", "row", "seat", "section", "sit" ] -}, { - "name" : "window", - "tags" : [ "close", "glass", "grid", "home", "house", "interior", "layout", "outside", "window" ] -}, { - "name" : "av_timer", - "tags" : [ "av", "clock", "countdown", "duration", "minutes", "seconds", "time", "timer", "watch" ] -}, { - "name" : "album", - "tags" : [ "album", "artist", "audio", "bvb", "cd", "computer", "data", "disk", "file", "music", "record", "sound", "storage", "track" ] -}, { - "name" : "local_dining", - "tags" : [ "dining", "eat", "food", "fork", "knife", "local", "meal", "restaurant", "spoon" ] -}, { - "name" : "headset", - "tags" : [ "accessory", "audio", "device", "ear", "earphone", "headphones", "headset", "listen", "music", "sound" ] -}, { - "name" : "maps_ugc", - "tags" : [ "+", "add", "bubble", "comment", "communicate", "feedback", "maps", "message", "new", "plus", "speech", "symbol", "ugc" ] -}, { - "name" : "airplane_ticket", - "tags" : [ "airplane", "airport", "boarding", "flight", "fly", "maps", "pass", "ticket", "transportation", "travel" ] -}, { - "name" : "vertical_split", - "tags" : [ "design", "format", "grid", "layout", "paragraph", "split", "text", "vertical", "website", "writing" ] -}, { - "name" : "sports_basketball", - "tags" : [ "athlete", "athletic", "ball", "basketball", "entertainment", "exercise", "game", "hobby", "social", "sports" ] -}, { - "name" : "next_plan", - "tags" : [ "arrow", "circle", "next", "plan", "right" ] -}, { - "name" : "drive_folder_upload", - "tags" : [ "arrow", "data", "doc", "document", "drive", "file", "folder", "sheet", "slide", "storage", "up", "upload" ] -}, { - "name" : "pregnant_woman", - "tags" : [ "baby", "birth", "body", "female", "human", "lady", "maternity", "mom", "mother", "people", "person", "pregnant", "women" ] -}, { - "name" : "wallpaper", - "tags" : [ "background", "image", "landscape", "photo", "photography", "picture", "wallpaper" ] -}, { - "name" : "image_search", - "tags" : [ "find", "glass", "image", "landscape", "look", "magnify", "magnifying", "mountain", "mountains", "photo", "photography", "picture", "search", "see" ] -}, { - "name" : "data_exploration", - "tags" : [ "analytics", "arrow", "chart", "data", "diagram", "exploration", "graph", "infographic", "measure", "metrics", "statistics", "tracking" ] -}, { - "name" : "device_thermostat", - "tags" : [ "celsius", "device", "fahrenheit", "meter", "temp", "temperature", "thermometer", "thermostat" ] -}, { - "name" : "healing", - "tags" : [ "bandage", "edit", "editing", "emergency", "fix", "healing", "hospital", "image", "medicine" ] -}, { - "name" : "laptop_mac", - "tags" : [ "Android", "OS", "chrome", "device", "display", "hardware", "iOS", "laptop", "mac", "monitor", "screen", "web", "window" ] -}, { - "name" : "height", - "tags" : [ "arrow", "color", "doc", "down", "edit", "editing", "editor", "fill", "format", "height", "paint", "sheet", "spreadsheet", "style", "text", "type", "up", "writing" ] -}, { - "name" : "restore_from_trash", - "tags" : [ "arrow", "back", "backwards", "clock", "date", "history", "refresh", "renew", "restore", "reverse", "rotate", "schedule", "time", "turn" ] -}, { - "name" : "radar", - "tags" : [ "detect", "military", "near", "network", "position", "radar", "scan" ] -}, { - "name" : "auto_awesome_motion", - "tags" : [ "adjust", "auto", "awesome", "collage", "edit", "editing", "enhance", "image", "motion", "photo", "video" ] -}, { - "name" : "file_download_done", - "tags" : [ "arrow", "arrows", "check", "done", "down", "download", "downloads", "drive", "file", "install", "installed", "tick", "upload" ] -}, { - "name" : "notification_add", - "tags" : [ "+", "active", "add", "alarm", "alert", "bell", "chime", "notification", "notifications", "notify", "plus", "reminder", "ring", "sound", "symbol" ] -}, { - "name" : "call_made", - "tags" : [ "arrow", "call", "device", "made", "mobile" ] -}, { - "name" : "camera_enhance", - "tags" : [ "ai", "artificial", "automatic", "automation", "camera", "custom", "enhance", "genai", "important", "intelligence", "lens", "magic", "photo", "photography", "picture", "quality", "smart", "spark", "sparkle", "special", "star" ] -}, { - "name" : "rotate_left", - "tags" : [ "around", "arrow", "direction", "inprogress", "left", "load", "loading refresh", "renew", "rotate", "turn" ] -}, { - "name" : "local_taxi", - "tags" : [ "automobile", "cab", "call", "car", "cars", "direction", "local", "lyft", "maps", "public", "taxi", "transportation", "uber", "vehicle", "yellow" ] -}, { - "name" : "star_border_purple500", - "tags" : [ "500", "best", "bookmark", "border", "favorite", "highlight", "outline", "purple", "ranking", "rate", "rating", "save", "star", "toggle" ] -}, { - "name" : "gpp_bad", - "tags" : [ "bad", "cancel", "certified", "close", "error", "exit", "gpp", "no", "privacy", "private", "protect", "protection", "remove", "security", "shield", "sim", "stop", "verified", "x" ] -}, { - "name" : "playlist_play", - "tags" : [ "arrow", "collection", "list", "music", "play", "playlist" ] -}, { - "name" : "cast", - "tags" : [ "Android", "OS", "airplay", "cast", "chrome", "connect", "desktop", "device", "display", "hardware", "iOS", "mac", "monitor", "screen", "screencast", "streaming", "television", "tv", "web", "window", "wireless" ] -}, { - "name" : "vertical_align_top", - "tags" : [ "align", "alignment", "arrow", "doc", "edit", "editing", "editor", "sheet", "spreadsheet", "text", "top", "type", "up", "vertical", "writing" ] -}, { - "name" : "ramen_dining", - "tags" : [ "breakfast", "dining", "dinner", "drink", "fastfood", "food", "lunch", "meal", "noodles", "ramen", "restaurant" ] -}, { - "name" : "data_usage", - "tags" : [ "analytics", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "statistics", "tracking", "usage" ] -}, { - "name" : "markunread_mailbox", - "tags" : [ "deliver", "envelop", "letter", "mail", "mailbox", "markunread", "post", "postal", "postbox", "receive", "send", "unread" ] -}, { - "name" : "terminal", - "tags" : [ "application", "code", "emulator", "program", "software", "terminal" ] -}, { - "name" : "screen_share", - "tags" : [ "Android", "OS", "arrow", "cast", "chrome", "device", "display", "hardware", "iOS", "laptop", "mac", "mirror", "monitor", "screen", "share", "steam", "streaming", "web", "window" ] -}, { - "name" : "center_focus_strong", - "tags" : [ "camera", "center", "focus", "image", "lens", "photo", "photography", "strong", "zoom" ] -}, { - "name" : "queue", - "tags" : [ "add", "collection", "layers", "list", "multiple", "music", "playlist", "queue", "stack", "stream", "video" ] -}, { - "name" : "games", - "tags" : [ "adjust", "arrow", "arrows", "control", "controller", "direction", "games", "gaming", "left", "move", "right" ] -}, { - "name" : "low_priority", - "tags" : [ "arrange", "arrow", "backward", "bottom", "list", "low", "move", "order", "priority" ] -}, { - "name" : "dynamic_form", - "tags" : [ "bolt", "code", "dynamic", "electric", "fast", "form", "lightning", "lists", "questionnaire", "thunderbolt" ] -}, { - "name" : "tab", - "tags" : [ "browser", "computer", "document", "documents", "folder", "internet", "tab", "tabs", "web", "website", "window", "windows" ] -}, { - "name" : "lock_reset", - "tags" : [ "around", "inprogress", "load", "loading refresh", "lock", "locked", "password", "privacy", "private", "protection", "renew", "rotate", "safety", "secure", "security", "turn" ] -}, { - "name" : "room_preferences", - "tags" : [ "building", "door", "doorway", "entrance", "gear", "home", "house", "interior", "office", "open", "preferences", "room", "settings" ] -}, { - "name" : "crop", - "tags" : [ "adjust", "adjustments", "area", "crop", "edit", "editing", "frame", "image", "images", "photo", "photos", "rectangle", "settings", "size", "square" ] -}, { - "name" : "monitor_weight", - "tags" : [ "body", "device", "diet", "health", "monitor", "scale", "smart", "weight" ] -}, { - "name" : "trip_origin", - "tags" : [ "circle", "departure", "origin", "trip" ] -}, { - "name" : "calendar_view_week", - "tags" : [ "calendar", "date", "day", "event", "format", "grid", "layout", "month", "schedule", "today", "view", "week" ] -}, { - "name" : "signal_wifi_4_bar", - "tags" : [ "4", "bar", "cell", "cellular", "data", "internet", "mobile", "network", "phone", "signal", "wifi", "wireless" ] -}, { - "name" : "blur_on", - "tags" : [ "blur", "disabled", "dots", "edit", "editing", "effect", "enabled", "enhance", "filter", "off", "on", "slash" ] -}, { - "name" : "view_stream", - "tags" : [ "design", "format", "grid", "layout", "lines", "list", "stacked", "stream", "view", "website" ] -}, { - "name" : "radio", - "tags" : [ "antenna", "audio", "device", "frequency", "hardware", "listen", "media", "music", "player", "radio", "signal", "tune" ] -}, { - "name" : "hail", - "tags" : [ "body", "hail", "human", "people", "person", "pick", "public", "stop", "taxi", "transportation" ] -}, { - "name" : "do_disturb_on", - "tags" : [ "cancel", "close", "denied", "deny", "disabled", "disturb", "do", "enabled", "off", "on", "remove", "silence", "slash", "stop" ] -}, { - "name" : "sensor_door", - "tags" : [ "alarm", "security", "security system" ] -}, { - "name" : "wb_incandescent", - "tags" : [ "balance", "bright", "edit", "editing", "incandescent", "light", "lighting", "setting", "settings", "white", "wp" ] -}, { - "name" : "local_drink", - "tags" : [ "cup", "drink", "drop", "droplet", "liquid", "local", "park", "water" ] -}, { - "name" : "accessible_forward", - "tags" : [ "accessibility", "accessible", "body", "forward", "handicap", "help", "human", "people", "person", "wheelchair" ] -}, { - "name" : "replay_circle_filled", - "tags" : [ "arrow", "arrows", "circle", "control", "controls", "filled", "music", "refresh", "renew", "repeat", "replay", "video" ] -}, { - "name" : "local_printshop", - "tags" : [ "draft", "fax", "ink", "local", "machine", "office", "paper", "print", "printer", "printshop", "send" ] -}, { - "name" : "local_laundry_service", - "tags" : [ "cleaning", "clothing", "dry", "dryer", "hotel", "laundry", "local", "service", "washer" ] -}, { - "name" : "vpn_lock", - "tags" : [ "earth", "globe", "lock", "locked", "network", "password", "privacy", "private", "protection", "safety", "secure", "security", "virtual", "vpn", "world" ] -}, { - "name" : "schema", - "tags" : [ "analytics", "chart", "data", "diagram", "flow", "graph", "infographic", "measure", "metrics", "schema", "statistics", "tracking" ] -}, { - "name" : "request_page", - "tags" : [ "data", "doc", "document", "drive", "file", "folder", "folders", "page", "paper", "request", "sheet", "slide", "writing" ] -}, { - "name" : "token", - "tags" : [ "badge", "hexagon", "mark", "shield", "sign", "symbol" ] -}, { - "name" : "branding_watermark", - "tags" : [ "branding", "components", "copyright", "design", "emblem", "format", "identity", "interface", "layout", "logo", "screen", "site", "stamp", "ui", "ux", "watermark", "web", "website", "window" ] -}, { - "name" : "theater_comedy", - "tags" : [ "broadway", "comedy", "event", "movie", "musical", "places", "show", "standup", "theater", "tour", "watch" ] -}, { - "name" : "text_format", - "tags" : [ "alphabet", "character", "font", "format", "letter", "square A", "style", "symbol", "text", "type" ] -}, { - "name" : "directions_bus_filled", - "tags" : [ "automobile", "bus", "car", "cars", "direction", "directions", "filled", "maps", "public", "transportation", "vehicle" ] -}, { - "name" : "remove_done", - "tags" : [ "approve", "check", "complete", "disabled", "done", "enabled", "finished", "mark", "multiple", "off", "ok", "on", "remove", "select", "slash", "tick", "yes" ] -}, { - "name" : "sports_bar", - "tags" : [ "alcohol", "bar", "beer", "drink", "liquor", "pint", "places", "pub", "sports" ] -}, { - "name" : "watch", - "tags" : [ "Android", "OS", "ar", "clock", "gadget", "iOS", "time", "vr", "watch", "wearables", "web", "wristwatch" ] -}, { - "name" : "add_to_drive", - "tags" : [ "add", "app", "application", "backup", "cloud", "drive", "files", "folders", "gdrive", "google", "recovery", "shortcut", "storage" ] -}, { - "name" : "format_align_center", - "tags" : [ "align", "alignment", "center", "doc", "edit", "editing", "editor", "format", "sheet", "spreadsheet", "text", "type", "writing" ] -}, { - "name" : "settings_power", - "tags" : [ "info", "information", "off", "on", "power", "save", "settings", "shutdown" ] -}, { - "name" : "local_pizza", - "tags" : [ "drink", "fastfood", "food", "local", "meal", "pizza" ] -}, { - "name" : "add_alert", - "tags" : [ "+", "active", "add", "alarm", "alert", "bell", "chime", "new", "notifications", "notify", "plus", "reminder", "ring", "sound", "symbol" ] -}, { - "name" : "smart_button", - "tags" : [ "action", "ai", "artificial", "automatic", "automation", "button", "components", "composer", "custom", "function", "genai", "intelligence", "interface", "magic", "site", "smart", "spark", "sparkle", "special", "star", "stars", "ui", "ux", "web", "website" ] -}, { - "name" : "flare", - "tags" : [ "bright", "edit", "editing", "effect", "flare", "image", "images", "light", "photography", "picture", "pictures", "sun" ] -}, { - "name" : "developer_mode", - "tags" : [ "Android", "OS", "bracket", "cell", "code", "developer", "development", "device", "engineer", "hardware", "iOS", "mobile", "mode", "phone", "tablet" ] -}, { - "name" : "call_split", - "tags" : [ "arrow", "call", "device", "mobile", "split" ] -}, { - "name" : "free_breakfast", - "tags" : [ "beverage", "breakfast", "cafe", "coffee", "cup", "drink", "free", "mug", "tea" ] -}, { - "name" : "auto_delete", - "tags" : [ "auto", "bin", "can", "clock", "date", "delete", "garbage", "remove", "schedule", "time", "trash" ] -}, { - "name" : "sports_kabaddi", - "tags" : [ "athlete", "athletic", "body", "combat", "entertainment", "exercise", "fighting", "game", "hobby", "human", "kabaddi", "people", "person", "social", "sports", "wrestle", "wrestling" ] -}, { - "name" : "face_retouching_natural", - "tags" : [ "ai", "artificial", "automatic", "automation", "custom", "edit", "editing", "effect", "emoji", "emotion", "face", "faces", "genai", "image", "intelligence", "magic", "natural", "photo", "photography", "retouch", "retouching", "settings", "smart", "spark", "sparkle", "star", "tag" ] -}, { - "name" : "not_listed_location", - "tags" : [ "?", "assistance", "destination", "direction", "help", "info", "information", "listed", "location", "maps", "not", "pin", "place", "punctuation", "question mark", "stop", "support", "symbol" ] -}, { - "name" : "wb_cloudy", - "tags" : [ "balance", "cloud", "cloudy", "edit", "editing", "white", "wp" ] -}, { - "name" : "sports", - "tags" : [ "athlete", "athletic", "blowing", "coach", "entertainment", "exercise", "game", "hobby", "instrument", "referee", "social", "sound", "sports", "warning", "whistle" ] -}, { - "name" : "emoji_symbols", - "tags" : [ "ampersand", "character", "emoji", "hieroglyph", "music", "note", "percent", "sign", "symbols" ] -}, { - "name" : "bathtub", - "tags" : [ "bath", "bathing", "bathroom", "bathtub", "home", "hotel", "human", "person", "shower", "travel", "tub" ] -}, { - "name" : "forward_10", - "tags" : [ "10", "arrow", "control", "controls", "digit", "fast", "forward", "music", "number", "play", "seconds", "symbol", "video" ] -}, { - "name" : "tablet_mac", - "tags" : [ "Android", "OS", "device", "hardware", "iOS", "ipad", "mobile", "tablet mac", "web" ] -}, { - "name" : "mode_night", - "tags" : [ "dark", "disturb", "lunar", "mode", "moon", "night", "sleep" ] -}, { - "name" : "broken_image", - "tags" : [ "broken", "corrupt", "error", "image", "landscape", "mountain", "mountains", "photo", "photography", "picture", "torn" ] -}, { - "name" : "escalator_warning", - "tags" : [ "body", "child", "escalator", "human", "kid", "parent", "people", "person", "warning" ] -}, { - "name" : "assistant", - "tags" : [ "ai", "artificial", "assistant", "automatic", "automation", "bubble", "chat", "comment", "communicate", "custom", "feedback", "genai", "intelligence", "magic", "message", "recommendation", "smart", "spark", "sparkle", "speech", "star", "suggestion", "twinkle" ] -}, { - "name" : "cases", - "tags" : [ "bag", "baggage", "briefcase", "business", "case", "cases", "purse", "suitcase" ] -}, { - "name" : "wifi_tethering", - "tags" : [ "cell", "cellular", "connection", "data", "internet", "mobile", "network", "phone", "scan", "service", "signal", "speed", "tethering", "wifi", "wireless" ] -}, { - "name" : "reduce_capacity", - "tags" : [ "arrow", "body", "capacity", "covid", "decrease", "down", "human", "people", "person", "reduce", "social" ] -}, { - "name" : "colorize", - "tags" : [ "color", "colorize", "dropper", "extract", "eye", "picker", "tool" ] -}, { - "name" : "save_as", - "tags" : [ "compose", "create", "data", "disk", "document", "draft", "drive", "edit", "editing", "file", "floppy", "input", "multimedia", "pen", "pencil", "save", "storage", "write", "writing" ] -}, { - "name" : "card_travel", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "membership", "miles", "money", "online", "pay", "payment", "travel", "trip" ] -}, { - "name" : "emoji_food_beverage", - "tags" : [ "beverage", "coffee", "cup", "drink", "emoji", "mug", "plate", "set", "tea" ] -}, { - "name" : "font_download", - "tags" : [ "A", "alphabet", "character", "download", "font", "letter", "square", "symbol", "text", "type" ] -}, { - "name" : "outbox", - "tags" : [ "box", "mail", "outbox", "send", "sent" ] -}, { - "name" : "battery_std", - "tags" : [ "battery", "cell", "charge", "mobile", "plus", "power", "standard", "std" ] -}, { - "name" : "sick", - "tags" : [ "covid", "discomfort", "emotions", "expressions", "face", "feelings", "fever", "flu", "ill", "mood", "pain", "person", "sick", "survey", "upset" ] -}, { - "name" : "add_location", - "tags" : [ "+", "add", "destination", "direction", "location", "maps", "new", "pin", "place", "plus", "stop", "symbol" ] -}, { - "name" : "try", - "tags" : [ "bookmark", "bubble", "chat", "comment", "communicate", "favorite", "feedback", "highlight", "important", "marked", "message", "save", "saved", "shape", "special", "speech", "star", "try" ] -}, { - "name" : "discount", - "tags" : [ ] -}, { - "name" : "man", - "tags" : [ "boy", "gender", "male", "man", "social", "symbol" ] -}, { - "name" : "running_with_errors", - "tags" : [ "!", "alert", "attention", "caution", "danger", "duration", "error", "errors", "exclamation", "important", "mark", "notification", "process", "processing", "running", "symbol", "time", "warning", "with" ] -}, { - "name" : "diversity_3", - "tags" : [ "committee", "diverse", "diversity", "family", "friends", "group", "groups", "humans", "network", "people", "persons", "social", "team" ] -}, { - "name" : "filter_none", - "tags" : [ "filter", "multiple", "none", "square", "stack" ] -}, { - "name" : "cloud_sync", - "tags" : [ "app", "application", "around", "backup", "cloud", "connection", "drive", "files", "folders", "inprogress", "internet", "load", "loading refresh", "network", "renew", "rotate", "sky", "storage", "turn", "upload" ] -}, { - "name" : "bloodtype", - "tags" : [ "blood", "bloodtype", "donate", "droplet", "emergency", "hospital", "medicine", "negative", "positive", "type", "water" ] -}, { - "name" : "dinner_dining", - "tags" : [ "breakfast", "dining", "dinner", "food", "fork", "lunch", "meal", "restaurant", "spaghetti", "utensils" ] -}, { - "name" : "transfer_within_a_station", - "tags" : [ "a", "arrow", "arrows", "body", "direction", "human", "left", "maps", "people", "person", "public", "right", "route", "station", "stop", "transfer", "transportation", "vehicle", "walk", "within" ] -}, { - "name" : "weekend", - "tags" : [ "chair", "couch", "furniture", "home", "living", "lounge", "relax", "room", "weekend" ] -}, { - "name" : "child_friendly", - "tags" : [ "baby", "care", "carriage", "child", "children", "friendly", "infant", "kid", "newborn", "stroller", "toddler", "young" ] -}, { - "name" : "offline_pin", - "tags" : [ "approve", "check", "checkmark", "circle", "complete", "done", "mark", "offline", "ok", "pin", "select", "tick", "validate", "verified", "yes" ] -}, { - "name" : "replay_10", - "tags" : [ "10", "arrow", "arrows", "control", "controls", "digit", "music", "number", "refresh", "renew", "repeat", "replay", "symbol", "ten", "video" ] -}, { - "name" : "brightness_4", - "tags" : [ "4", "brightness", "circle", "control", "crescent", "level", "moon", "screen", "sun" ] -}, { - "name" : "cruelty_free", - "tags" : [ "animal", "bunny", "cruelty", "eco", "free", "nature", "rabbit", "social", "sustainability", "sustainable", "testing" ] -}, { - "name" : "format_paint", - "tags" : [ "brush", "color", "doc", "edit", "editing", "editor", "fill", "format", "paint", "roller", "sheet", "spreadsheet", "style", "text", "type", "writing" ] -}, { - "name" : "filter_center_focus", - "tags" : [ "camera", "center", "dot", "edit", "filter", "focus", "image", "photo", "photography", "picture" ] -}, { - "name" : "area_chart", - "tags" : [ "analytics", "area", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "statistics", "tracking" ] -}, { - "name" : "bakery_dining", - "tags" : [ "bakery", "bread", "breakfast", "brunch", "croissant", "dining", "food" ] -}, { - "name" : "emoji_transportation", - "tags" : [ "architecture", "automobile", "building", "car", "cars", "direction", "emoji", "estate", "maps", "place", "public", "real", "residence", "residential", "shelter", "transportation", "travel", "vehicle" ] -}, { - "name" : "folder_special", - "tags" : [ "bookmark", "data", "doc", "document", "drive", "favorite", "file", "folder", "highlight", "important", "marked", "save", "saved", "shape", "sheet", "slide", "special", "star", "storage" ] -}, { - "name" : "door_front", - "tags" : [ "closed", "door", "doorway", "entrance", "exit", "front", "home", "house", "way" ] -}, { - "name" : "calendar_view_day", - "tags" : [ "calendar", "date", "day", "event", "format", "grid", "layout", "month", "schedule", "today", "view", "week" ] -}, { - "name" : "legend_toggle", - "tags" : [ "analytics", "chart", "data", "diagram", "graph", "infographic", "legend", "measure", "metrics", "monitoring", "stackdriver", "statistics", "toggle", "tracking" ] -}, { - "name" : "light", - "tags" : [ "bulb", "ceiling", "hanging", "inside", "interior", "lamp", "light", "lighting", "pendent", "room" ] -}, { - "name" : "find_replace", - "tags" : [ "around", "arrows", "find", "glass", "inprogress", "load", "loading refresh", "look", "magnify", "magnifying", "renew", "replace", "rotate", "search", "see" ] -}, { - "name" : "crop_original", - "tags" : [ "adjust", "adjustments", "area", "crop", "edit", "editing", "frame", "image", "images", "original", "photo", "photos", "picture", "settings", "size" ] -}, { - "name" : "rowing", - "tags" : [ "activity", "boat", "body", "canoe", "human", "people", "person", "row", "rowing", "sport", "water" ] -}, { - "name" : "enhanced_encryption", - "tags" : [ "+", "add", "encryption", "enhanced", "lock", "locked", "new", "password", "plus", "privacy", "private", "protection", "safety", "secure", "security", "symbol" ] -}, { - "name" : "how_to_vote", - "tags" : [ "ballot", "election", "how", "poll", "to", "vote" ] -}, { - "name" : "chrome_reader_mode", - "tags" : [ "chrome", "mode", "read", "reader", "text" ] -}, { - "name" : "auto_fix_normal", - "tags" : [ "ai", "artificial", "auto", "automatic", "automation", "custom", "edit", "erase", "fix", "genai", "intelligence", "magic", "modify", "smart", "spark", "sparkle", "star", "wand" ] -}, { - "name" : "compress", - "tags" : [ "arrow", "arrows", "collide", "compress", "pressure", "push", "together" ] -}, { - "name" : "dehaze", - "tags" : [ "adjust", "dehaze", "edit", "editing", "enhance", "haze", "image", "lines", "photo", "photography", "remove" ] -}, { - "name" : "outlet", - "tags" : [ "connect", "connecter", "electricity", "outlet", "plug", "power" ] -}, { - "name" : "desktop_mac", - "tags" : [ "Android", "OS", "chrome", "desktop", "device", "display", "hardware", "iOS", "mac", "monitor", "screen", "web", "window" ] -}, { - "name" : "nature_people", - "tags" : [ "activity", "body", "forest", "human", "nature", "outdoor", "outside", "park", "people", "person", "tree", "wilderness" ] -}, { - "name" : "sports_tennis", - "tags" : [ "athlete", "athletic", "ball", "bat", "entertainment", "exercise", "game", "hobby", "racket", "social", "sports", "tennis" ] -}, { - "name" : "forest", - "tags" : [ "forest", "jungle", "nature", "plantation", "plants", "trees", "woodland" ] -}, { - "name" : "upcoming", - "tags" : [ "alarm", "calendar", "mail", "message", "notification", "upcoming" ] -}, { - "name" : "assignment_returned", - "tags" : [ "arrow", "assignment", "clipboard", "doc", "document", "down", "returned" ] -}, { - "name" : "cookie", - "tags" : [ "biscuit", "cookies", "data", "dessert", "wafer" ] -}, { - "name" : "fax", - "tags" : [ "fax", "machine", "office", "phone", "send" ] -}, { - "name" : "square", - "tags" : [ "draw", "four", "shape quadrangle", "sides", "square" ] -}, { - "name" : "density_medium", - "tags" : [ "density", "horizontal", "lines", "medium", "rule", "rules" ] -}, { - "name" : "terrain", - "tags" : [ "geography", "landscape", "mountain", "terrain" ] -}, { - "name" : "settings_brightness", - "tags" : [ "brightness", "dark", "filter", "light", "mode", "setting", "settings" ] -}, { - "name" : "attach_email", - "tags" : [ "attach", "attachment", "clip", "compose", "email", "envelop", "letter", "link", "mail", "message", "send" ] -}, { - "name" : "photo", - "tags" : [ "image", "mountain", "mountains", "photo", "photography", "picture" ] -}, { - "name" : "http", - "tags" : [ "alphabet", "character", "font", "http", "letter", "symbol", "text", "transfer", "type", "url", "website" ] -}, { - "name" : "garage", - "tags" : [ "automobile", "automotive", "car", "cars", "direction", "garage", "maps", "transportation", "travel", "vehicle" ] -}, { - "name" : "wine_bar", - "tags" : [ "alcohol", "bar", "cocktail", "cup", "drink", "glass", "liquor", "wine" ] -}, { - "name" : "multiple_stop", - "tags" : [ "arrows", "directions", "dots", "left", "maps", "multiple", "navigation", "right", "stop" ] -}, { - "name" : "format_color_text", - "tags" : [ "color", "doc", "edit", "editing", "editor", "fill", "format", "paint", "sheet", "spreadsheet", "style", "text", "type", "writing" ] -}, { - "name" : "gesture", - "tags" : [ "drawing", "finger", "gesture", "gestures", "hand", "motion" ] -}, { - "name" : "heart_broken", - "tags" : [ "break", "broken", "core", "crush", "health", "heart", "nucleus", "split" ] -}, { - "name" : "format_align_right", - "tags" : [ "align", "alignment", "doc", "edit", "editing", "editor", "format", "right", "sheet", "spreadsheet", "text", "type", "writing" ] -}, { - "name" : "transgender", - "tags" : [ "female", "gender", "lgbt", "male", "neutral", "social", "symbol", "transgender" ] -}, { - "name" : "alarm_add", - "tags" : [ "+", "add", "alarm", "alert", "bell", "clock", "countdown", "date", "new", "notification", "plus", "schedule", "symbol", "time" ] -}, { - "name" : "new_label", - "tags" : [ "+", "add", "archive", "bookmark", "favorite", "label", "library", "new", "plus", "read", "reading", "remember", "ribbon", "save", "symbol", "tag" ] -}, { - "name" : "south_east", - "tags" : [ "arrow", "directional", "down", "east", "maps", "navigation", "right", "south" ] -}, { - "name" : "backup_table", - "tags" : [ "backup", "drive", "files folders", "format", "layout", "stack", "storage", "table" ] -}, { - "name" : "unsubscribe", - "tags" : [ "cancel", "close", "email", "envelop", "letter", "mail", "message", "newsletter", "off", "remove", "send", "subscribe", "unsubscribe" ] -}, { - "name" : "flash_off", - "tags" : [ "bolt", "disabled", "electric", "enabled", "fast", "flash", "lightning", "off", "on", "slash", "thunderbolt" ] -}, { - "name" : "elderly", - "tags" : [ "body", "cane", "elderly", "human", "old", "people", "person", "senior" ] -}, { - "name" : "generating_tokens", - "tags" : [ "access", "ai", "api", "artificial", "automatic", "automation", "coin", "custom", "genai", "generating", "intelligence", "magic", "smart", "spark", "sparkle", "star", "tokens" ] -}, { - "name" : "spellcheck", - "tags" : [ "a", "alphabet", "approve", "character", "check", "font", "letter", "mark", "ok", "processor", "select", "spell", "spellcheck", "symbol", "text", "tick", "type", "word", "write", "yes" ] -}, { - "name" : "auto_awesome_mosaic", - "tags" : [ "adjust", "auto", "awesome", "collage", "edit", "editing", "enhance", "image", "mosaic", "photo" ] -}, { - "name" : "outdoor_grill", - "tags" : [ "barbecue", "bbq", "charcoal", "cooking", "grill", "home", "house", "outdoor", "outside" ] -}, { - "name" : "restore_page", - "tags" : [ "arrow", "data", "doc", "file", "page", "paper", "refresh", "restore", "rotate", "sheet", "storage" ] -}, { - "name" : "foundation", - "tags" : [ "architecture", "base", "basis", "building", "construction", "estate", "foundation", "home", "house", "real", "residential" ] -}, { - "name" : "credit_card_off", - "tags" : [ "card", "charge", "commerce", "cost", "credit", "disabled", "enabled", "finance", "money", "off", "online", "pay", "payment", "slash" ] -}, { - "name" : "scatter_plot", - "tags" : [ "analytics", "bar", "bars", "chart", "circles", "data", "diagram", "dot", "graph", "infographic", "measure", "metrics", "plot", "scatter", "statistics", "tracking" ] -}, { - "name" : "signal_cellular_4_bar", - "tags" : [ "4", "bar", "cell", "cellular", "data", "internet", "mobile", "network", "phone", "signal", "speed", "wifi", "wireless" ] -}, { - "name" : "add_moderator", - "tags" : [ "+", "add", "certified", "moderator", "new", "plus", "privacy", "private", "protect", "protection", "security", "shield", "symbol", "verified" ] -}, { - "name" : "play_for_work", - "tags" : [ "arrow", "circle", "down", "google", "half", "play", "work" ] -}, { - "name" : "add_card", - "tags" : [ "+", "add", "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "new", "online", "pay", "payment", "plus", "price", "shopping", "symbol" ] -}, { - "name" : "app_settings_alt", - "tags" : [ "Android", "OS", "app", "applications", "cell", "device", "gear", "hardware", "iOS", "mobile", "phone", "setting", "settings", "tablet" ] -}, { - "name" : "keyboard_tab", - "tags" : [ "arrow", "keyboard", "left", "next", "right", "tab" ] -}, { - "name" : "wifi_protected_setup", - "tags" : [ "around", "arrow", "arrows", "protected", "rotate", "setup", "wifi" ] -}, { - "name" : "deck", - "tags" : [ "chairs", "deck", "home", "house", "outdoors", "outside", "patio", "social", "terrace", "umbrella", "yard" ] -}, { - "name" : "takeout_dining", - "tags" : [ "box", "container", "delivery", "dining", "food", "meal", "restaurant", "takeout" ] -}, { - "name" : "tag_faces", - "tags" : [ "emoji", "emotion", "faces", "happy", "satisfied", "smile", "tag" ] -}, { - "name" : "brightness_6", - "tags" : [ "6", "brightness", "circle", "control", "crescent", "level", "moon", "screen", "sun" ] -}, { - "name" : "woman", - "tags" : [ "female", "gender", "girl", "lady", "social", "symbol", "woman", "women" ] -}, { - "name" : "assistant_direction", - "tags" : [ "assistant", "destination", "direction", "location", "maps", "navigate", "navigation", "pin", "place", "right", "stop" ] -}, { - "name" : "brightness_5", - "tags" : [ "5", "brightness", "circle", "control", "crescent", "level", "moon", "screen", "sun" ] -}, { - "name" : "social_distance", - "tags" : [ "6", "apart", "body", "distance", "ft", "human", "people", "person", "social", "space" ] -}, { - "name" : "free_cancellation", - "tags" : [ "approve", "calendar", "cancel", "cancellation", "check", "complete", "date", "day", "done", "event", "exit", "free", "mark", "month", "no", "ok", "remove", "schedule", "select", "stop", "tick", "validate", "verified", "x", "yes" ] -}, { - "name" : "subdirectory_arrow_left", - "tags" : [ "arrow", "directory", "down", "left", "navigation", "sub", "subdirectory" ] -}, { - "name" : "laptop_chromebook", - "tags" : [ "Android", "OS", "chrome", "chromebook", "device", "display", "hardware", "iOS", "laptop", "mac chromebook", "monitor", "screen", "web", "window" ] -}, { - "name" : "format_list_numbered_rtl", - "tags" : [ "align", "alignment", "digit", "doc", "edit", "editing", "editor", "format", "list", "notes", "number", "numbered", "rtl", "sheet", "spreadsheet", "symbol", "text", "type", "writing" ] -}, { - "name" : "store_mall_directory", - "tags" : [ "directory", "mall", "store" ] -}, { - "name" : "settings_overscan", - "tags" : [ "arrows", "expand", "image", "photo", "picture", "scan", "settings" ] -}, { - "name" : "icecream", - "tags" : [ "cream", "dessert", "food", "ice", "icecream", "snack" ] -}, { - "name" : "details", - "tags" : [ "details", "edit", "editing", "enhance", "image", "photo", "photography", "sharpen", "triangle" ] -}, { - "name" : "add_reaction", - "tags" : [ "+", "add", "emoji", "emotions", "expressions", "face", "feelings", "glad", "happiness", "happy", "icon", "icons", "insert", "like", "mood", "new", "person", "pleased", "plus", "smile", "smiling", "social", "survey", "symbol" ] -}, { - "name" : "follow_the_signs", - "tags" : [ "arrow", "body", "directional", "follow", "human", "people", "person", "right", "signs", "social", "the" ] -}, { - "name" : "attribution", - "tags" : [ "attribute", "attribution", "body", "copyright", "copywriter", "human", "people", "person" ] -}, { - "name" : "food_bank", - "tags" : [ "architecture", "bank", "building", "charity", "eat", "estate", "food", "fork", "house", "knife", "meal", "place", "real", "residence", "residential", "shelter", "utensils" ] -}, { - "name" : "closed_caption", - "tags" : [ "accessible", "alphabet", "caption", "cc", "character", "closed", "decoder", "font", "language", "letter", "media", "movies", "subtitle", "subtitles", "symbol", "text", "tv", "type" ] -}, { - "name" : "gif", - "tags" : [ "alphabet", "animated", "animation", "bitmap", "character", "font", "format", "gif", "graphics", "interchange", "letter", "symbol", "text", "type" ] -}, { - "name" : "phonelink", - "tags" : [ "Android", "OS", "chrome", "computer", "connect", "desktop", "device", "hardware", "iOS", "link", "mac", "mobile", "phone", "phonelink", "sync", "tablet", "web", "windows" ] -}, { - "name" : "grain", - "tags" : [ "dots", "edit", "editing", "effect", "filter", "grain", "image", "images", "photography", "picture", "pictures" ] -}, { - "name" : "personal_injury", - "tags" : [ "accident", "aid", "arm", "bandage", "body", "broke", "cast", "fracture", "health", "human", "injury", "medical", "patient", "people", "person", "personal", "sling", "social" ] -}, { - "name" : "flip_camera_android", - "tags" : [ "android", "camera", "center", "edit", "editing", "flip", "image", "mobile", "orientation", "rotate", "turn" ] -}, { - "name" : "museum", - "tags" : [ "architecture", "attraction", "building", "estate", "event", "exhibition", "explore", "local", "museum", "places", "real", "see", "shop", "store", "tour" ] -}, { - "name" : "north_west", - "tags" : [ "arrow", "directional", "left", "maps", "navigation", "north", "up", "west" ] -}, { - "name" : "gite", - "tags" : [ "architecture", "estate", "gite", "home", "hostel", "house", "maps", "place", "real", "residence", "residential", "stay", "traveling" ] -}, { - "name" : "highlight", - "tags" : [ "color", "doc", "edit", "editing", "editor", "emphasize", "fill", "flash", "format", "highlight", "light", "paint", "sheet", "spreadsheet", "style", "text", "type", "writing" ] -}, { - "name" : "brightness_1", - "tags" : [ "1", "brightness", "circle", "control", "crescent", "level", "moon", "screen" ] -}, { - "name" : "plus_one", - "tags" : [ "1", "add", "digit", "increase", "number", "one", "plus", "symbol" ] -}, { - "name" : "villa", - "tags" : [ "architecture", "beach", "estate", "home", "house", "maps", "place", "real", "residence", "residential", "traveling", "vacation stay", "villa" ] -}, { - "name" : "fmd_bad", - "tags" : [ "!", "alert", "attention", "bad", "caution", "danger", "destination", "direction", "error", "exclamation", "fmd", "important", "location", "maps", "mark", "notification", "pin", "place", "symbol", "warning" ] -}, { - "name" : "flashlight_on", - "tags" : [ "disabled", "enabled", "flash", "flashlight", "light", "off", "on", "slash" ] -}, { - "name" : "flip", - "tags" : [ "edit", "editing", "flip", "image", "orientation", "scan scanning" ] -}, { - "name" : "nightlife", - "tags" : [ "alcohol", "bar", "bottle", "club", "cocktail", "dance", "drink", "food", "glass", "liquor", "music", "nightlife", "note", "wine" ] -}, { - "name" : "present_to_all", - "tags" : [ "all", "arrow", "present", "presentation", "screen", "share", "site", "slides", "to", "web", "website" ] -}, { - "name" : "do_disturb", - "tags" : [ "cancel", "close", "denied", "deny", "disturb", "do", "remove", "silence", "stop" ] -}, { - "name" : "outbound", - "tags" : [ "arrow", "circle", "directional", "outbound", "right", "up" ] -}, { - "name" : "local_pharmacy", - "tags" : [ "911", "aid", "cross", "emergency", "first", "hospital", "local", "medicine", "pharmacy", "places" ] -}, { - "name" : "splitscreen", - "tags" : [ "column", "grid", "layout", "multitasking", "row", "screen", "split", "splitscreen", "two" ] -}, { - "name" : "waterfall_chart", - "tags" : [ "analytics", "bar", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "statistics", "tracking", "waterfall" ] -}, { - "name" : "switch_left", - "tags" : [ "arrows", "directional", "left", "navigation", "switch", "toggle" ] -}, { - "name" : "domain_verification", - "tags" : [ "app", "application desktop", "approve", "check", "complete", "design", "domain", "done", "interface", "internet", "layout", "mark", "ok", "screen", "select", "site", "tick", "ui", "ux", "validate", "verification", "verified", "web", "website", "window", "www", "yes" ] -}, { - "name" : "fireplace", - "tags" : [ "chimney", "fire", "fireplace", "flame", "home", "house", "living", "pit", "place", "room", "warm", "winter" ] -}, { - "name" : "video_settings", - "tags" : [ "change", "details", "gear", "info", "information", "options", "play", "screen", "service", "setting", "settings", "video", "window" ] -}, { - "name" : "disabled_visible", - "tags" : [ "cancel", "close", "disabled", "exit", "eye", "no", "on", "quit", "remove", "reveal", "see", "show", "stop", "view", "visibility", "visible" ] -}, { - "name" : "network_wifi", - "tags" : [ "cell", "cellular", "data", "internet", "mobile", "network", "phone", "speed", "wifi", "wireless" ] -}, { - "name" : "quickreply", - "tags" : [ "bolt", "bubble", "chat", "comment", "communicate", "fast", "lightning", "message", "quick", "quickreply", "reply", "speech", "thunderbolt" ] -}, { - "name" : "swap_vertical_circle", - "tags" : [ "arrow", "arrows", "circle", "down", "swap", "up", "vertical" ] -}, { - "name" : "format_align_justify", - "tags" : [ "align", "alignment", "density", "doc", "edit", "editing", "editor", "extra", "format", "justify", "sheet", "small", "spreadsheet", "text", "type", "writing" ] -}, { - "name" : "settings_input_composite", - "tags" : [ "component", "composite", "connection", "connectivity", "input", "plug", "points", "settings" ] -}, { - "name" : "loupe", - "tags" : [ "+", "add", "details", "focus", "glass", "loupe", "magnifying", "new", "plus", "symbol" ] -}, { - "name" : "123", - "tags" : [ "1", "2", "3", "digit", "number", "symbol" ] -}, { - "name" : "network_check", - "tags" : [ "check", "connect", "connection", "internet", "meter", "network", "signal", "speed", "tick", "wifi", "wireless" ] -}, { - "name" : "sms_failed", - "tags" : [ "!", "alert", "attention", "bubbles", "caution", "chat", "communication", "conversation", "danger", "error", "exclamation", "failed", "feedback", "important", "mark", "message", "notification", "service", "sms", "speech", "symbol", "warning" ] -}, { - "name" : "cancel_schedule_send", - "tags" : [ "cancel", "email", "mail", "no", "quit", "remove", "schedule", "send", "share", "stop", "x" ] -}, { - "name" : "work_history", - "tags" : [ "back", "backwards", "bag", "baggage", "briefcase", "business", "case", "clock", "date", "history", "job", "pending", "recent", "schedule", "suitcase", "time", "updates", "work" ] -}, { - "name" : "electric_bolt", - "tags" : [ "bolt", "electric", "energy", "fast", "lightning", "nest", "thunderbolt" ] -}, { - "name" : "view_day", - "tags" : [ "cards", "carousel", "day", "design", "format", "grid", "layout", "view", "website" ] -}, { - "name" : "night_shelter", - "tags" : [ "architecture", "bed", "building", "estate", "homeless", "house", "night", "place", "real", "shelter", "sleep" ] -}, { - "name" : "monitor", - "tags" : [ "Android", "OS", "chrome", "device", "display", "hardware", "iOS", "mac", "monitor", "screen", "web", "window" ] -}, { - "name" : "clean_hands", - "tags" : [ "bacteria", "clean", "disinfect", "germs", "gesture", "hand", "hands", "sanitize", "sanitizer" ] -}, { - "name" : "mark_chat_read", - "tags" : [ "approve", "bubble", "chat", "check", "comment", "communicate", "complete", "done", "mark", "message", "ok", "read", "select", "sent", "speech", "tick", "verified", "yes" ] -}, { - "name" : "comment_bank", - "tags" : [ "archive", "bank", "bookmark", "bubble", "cchat", "comment", "communicate", "favorite", "label", "library", "message", "remember", "ribbon", "save", "speech", "tag" ] -}, { - "name" : "sim_card_download", - "tags" : [ "arrow", "camera", "card", "chip", "device", "down", "download", "memory", "phone", "sim", "storage" ] -}, { - "name" : "lan", - "tags" : [ "computer", "connection", "data", "internet", "lan", "network", "service" ] -}, { - "name" : "piano", - "tags" : [ "instrument", "keyboard", "keys", "music", "musical", "piano", "social" ] -}, { - "name" : "add_road", - "tags" : [ "+", "add", "destination", "direction", "highway", "maps", "new", "plus", "road", "stop", "street", "symbol", "traffic" ] -}, { - "name" : "add_ic_call", - "tags" : [ "+", "add", "call", "cell", "contact", "device", "hardware", "mobile", "new", "phone", "plus", "symbol", "telephone" ] -}, { - "name" : "rule_folder", - "tags" : [ "approve", "cancel", "check", "close", "complete", "data", "doc", "document", "done", "drive", "exit", "file", "folder", "mark", "no", "ok", "remove", "rule", "select", "sheet", "slide", "storage", "tick", "validate", "verified", "x", "yes" ] -}, { - "name" : "switch_access_shortcut", - "tags" : [ "access", "arrow", "arrows", "direction", "navigation", "new", "north", "shortcut", "switch", "symbol", "up" ] -}, { - "name" : "hardware", - "tags" : [ "break", "construction", "hammer", "hardware", "nail", "repair", "tool" ] -}, { - "name" : "line_weight", - "tags" : [ "height", "line", "size", "spacing", "style", "thickness", "weight" ] -}, { - "name" : "image_not_supported", - "tags" : [ "disabled", "enabled", "image", "landscape", "mountain", "mountains", "not", "off", "on", "photo", "photography", "picture", "slash", "supported" ] -}, { - "name" : "flip_camera_ios", - "tags" : [ "DISABLE_IOS", "android", "camera", "disable_ios", "edit", "editing", "flip", "image", "ios", "mobile", "orientation", "rotate", "turn" ] -}, { - "name" : "phone_callback", - "tags" : [ "arrow", "call", "callback", "cell", "contact", "device", "down", "hardware", "mobile", "phone", "telephone" ] -}, { - "name" : "access_time_filled", - "tags" : [ ] -}, { - "name" : "dining", - "tags" : [ "cafe", "cafeteria", "cutlery", "diner", "dining", "eat", "eating", "fork", "room", "spoon" ] -}, { - "name" : "scale", - "tags" : [ "measure", "monitor", "scale", "weight" ] -}, { - "name" : "airplanemode_active", - "tags" : [ "active", "airplane", "airplanemode", "flight", "mode", "on", "signal" ] -}, { - "name" : "set_meal", - "tags" : [ "chopsticks", "dinner", "fish", "food", "lunch", "meal", "restaurant", "set", "teishoku" ] -}, { - "name" : "mobile_friendly", - "tags" : [ "Android", "OS", "approve", "cell", "check", "complete", "device", "done", "friendly", "hardware", "iOS", "mark", "mobile", "ok", "phone", "select", "tablet", "tick", "validate", "verified", "yes" ] -}, { - "name" : "assured_workload", - "tags" : [ "assured", "compliance", "confidential", "federal", "government", "secure", "sensitive regulatory", "workload" ] -}, { - "name" : "wallet", - "tags" : [ ] -}, { - "name" : "merge_type", - "tags" : [ "arrow", "combine", "direction", "format", "merge", "text", "type" ] -}, { - "name" : "view_timeline", - "tags" : [ "grid", "layout", "pattern", "squares", "timeline", "view" ] -}, { - "name" : "departure_board", - "tags" : [ "automobile", "board", "bus", "car", "cars", "clock", "departure", "maps", "public", "schedule", "time", "transportation", "travel", "vehicle" ] -}, { - "name" : "event_repeat", - "tags" : [ "around", "calendar", "date", "day", "event", "inprogress", "load", "loading refresh", "month", "renew", "rotate", "schedule", "turn" ] -}, { - "name" : "sanitizer", - "tags" : [ "bacteria", "bottle", "clean", "covid", "disinfect", "germs", "pump", "sanitizer" ] -}, { - "name" : "surfing", - "tags" : [ "athlete", "athletic", "beach", "body", "entertainment", "exercise", "hobby", "human", "people", "person", "sea", "social sports", "sports", "summer", "surfing", "water" ] -}, { - "name" : "pix", - "tags" : [ "bill", "brazil", "card", "cash", "commerce", "credit", "currency", "finance", "money", "payment" ] -}, { - "name" : "phonelink_ring", - "tags" : [ "Android", "OS", "cell", "connection", "data", "device", "hardware", "iOS", "mobile", "network", "phone", "phonelink", "ring", "service", "signal", "tablet", "wireless" ] -}, { - "name" : "display_settings", - "tags" : [ "Android", "OS", "application", "change", "chrome", "desktop", "details", "device", "display", "gear", "hardware", "iOS", "info", "information", "mac", "monitor", "options", "personal", "screen", "service", "settings", "web", "window" ] -}, { - "name" : "sports_motorsports", - "tags" : [ "athlete", "athletic", "automobile", "bike", "drive", "driving", "entertainment", "helmet", "hobby", "motorcycle", "motorsports", "protect", "social", "sports", "vehicle" ] -}, { - "name" : "horizontal_split", - "tags" : [ "bars", "format", "horizontal", "layout", "lines", "split", "stacked" ] -}, { - "name" : "view_comfy", - "tags" : [ "comfy", "grid", "layout", "pattern", "squares", "view" ] -}, { - "name" : "polymer", - "tags" : [ "emblem", "logo", "mark", "polymer" ] -}, { - "name" : "golf_course", - "tags" : [ "athlete", "athletic", "ball", "club", "course", "entertainment", "flag", "golf", "golfer", "golfing", "hobby", "hole", "places", "putt", "sports" ] -}, { - "name" : "batch_prediction", - "tags" : [ "batch", "bulb", "idea", "light", "prediction" ] -}, { - "name" : "filter_1", - "tags" : [ "1", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "settings", "stack", "symbol" ] -}, { - "name" : "stay_current_portrait", - "tags" : [ "Android", "OS", "current", "device", "hardware", "iOS", "mobile", "phone", "portrait", "stay", "tablet" ] -}, { - "name" : "usb", - "tags" : [ "cable", "connection", "device", "usb", "wire" ] -}, { - "name" : "featured_play_list", - "tags" : [ "collection", "featured", "highlighted", "list", "music", "play", "playlist", "recommended" ] -}, { - "name" : "data_object", - "tags" : [ "brackets", "code", "coder", "data", "object", "parentheses" ] -}, { - "name" : "co_present", - "tags" : [ "arrow", "co-present", "presentation", "screen", "share", "site", "slides", "togather", "web", "website" ] -}, { - "name" : "ev_station", - "tags" : [ "automobile", "car", "cars", "charging", "electric", "electricity", "ev", "maps", "places", "station", "transportation", "vehicle" ] -}, { - "name" : "send_and_archive", - "tags" : [ "archive", "arrow", "down", "download", "email", "letter", "mail", "save", "send", "share" ] -}, { - "name" : "send_to_mobile", - "tags" : [ "Android", "OS", "arrow", "device", "export", "forward", "hardware", "iOS", "mobile", "phone", "right", "send", "share", "tablet", "to" ] -}, { - "name" : "local_see", - "tags" : [ "camera", "lens", "local", "photo", "photography", "picture", "see" ] -}, { - "name" : "satellite_alt", - "tags" : [ "alternative", "artificial", "communication", "satellite", "space", "space station", "television" ] -}, { - "name" : "flatware", - "tags" : [ "cafe", "cafeteria", "cutlery", "diner", "dining", "eat", "eating", "fork", "room", "spoon" ] -}, { - "name" : "speaker", - "tags" : [ "box", "electronic", "loud", "music", "sound", "speaker", "stereo", "system", "video" ] -}, { - "name" : "adb", - "tags" : [ "adb", "android", "bridge", "debug" ] -}, { - "name" : "movie_creation", - "tags" : [ "cinema", "clapperboard", "creation", "film", "movie", "movies", "slate", "video" ] -}, { - "name" : "picture_in_picture", - "tags" : [ "crop", "cropped", "overlap", "photo", "picture", "position", "shape" ] -}, { - "name" : "call_received", - "tags" : [ "arrow", "call", "device", "mobile", "received" ] -}, { - "name" : "battery_alert", - "tags" : [ "!", "alert", "attention", "battery", "caution", "cell", "charge", "danger", "error", "exclamation", "important", "mark", "mobile", "notification", "power", "symbol", "warning" ] -}, { - "name" : "system_update", - "tags" : [ "Android", "OS", "arrow", "arrows", "cell", "device", "direction", "down", "download", "hardware", "iOS", "install", "mobile", "phone", "system", "tablet", "update" ] -}, { - "name" : "webhook", - "tags" : [ "api", "developer", "development", "enterprise", "software", "webhook" ] -}, { - "name" : "add_chart", - "tags" : [ "+", "add", "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "new", "plus", "statistics", "symbol", "tracking" ] -}, { - "name" : "pan_tool_alt", - "tags" : [ "fingers", "gesture", "hand", "hands", "human", "move", "pan", "scan", "stop", "tool" ] -}, { - "name" : "sports_handball", - "tags" : [ "athlete", "athletic", "ball", "body", "entertainment", "exercise", "game", "handball", "hobby", "human", "people", "person", "social", "sports" ] -}, { - "name" : "electric_car", - "tags" : [ "automobile", "car", "cars", "electric", "electricity", "maps", "transportation", "travel", "vehicle" ] -}, { - "name" : "phone_forwarded", - "tags" : [ "arrow", "call", "cell", "contact", "device", "direction", "forwarded", "hardware", "mobile", "phone", "right", "telephone" ] -}, { - "name" : "add_to_photos", - "tags" : [ "add", "collection", "image", "landscape", "mountain", "mountains", "photo", "photography", "photos", "picture", "plus", "to" ] -}, { - "name" : "power_off", - "tags" : [ "charge", "cord", "disabled", "electric", "electrical", "enabled", "off", "on", "outlet", "plug", "power", "slash" ] -}, { - "name" : "noise_control_off", - "tags" : [ "audio", "aware", "cancel", "cancellation", "control", "disabled", "enabled", "music", "noise", "note", "off", "offline", "on", "slash", "sound" ] -}, { - "name" : "code_off", - "tags" : [ "brackets", "code", "css", "develop", "developer", "disabled", "enabled", "engineer", "engineering", "html", "off", "on", "platform", "slash" ] -}, { - "name" : "bookmark_remove", - "tags" : [ "bookmark", "delete", "favorite", "minus", "remember", "remove", "ribbon", "save", "subtract" ] -}, { - "name" : "screen_search_desktop", - "tags" : [ "Android", "OS", "arrow", "desktop", "device", "hardware", "iOS", "lock", "monitor", "rotate", "screen", "web" ] -}, { - "name" : "panorama", - "tags" : [ "angle", "image", "mountain", "mountains", "panorama", "photo", "photography", "picture", "view", "wide" ] -}, { - "name" : "settings_bluetooth", - "tags" : [ "bluetooth", "connect", "connection", "connectivity", "device", "settings", "signal", "symbol" ] -}, { - "name" : "sports_baseball", - "tags" : [ "athlete", "athletic", "ball", "baseball", "entertainment", "exercise", "game", "hobby", "social", "sports" ] -}, { - "name" : "festival", - "tags" : [ "circus", "event", "festival", "local", "maps", "places", "tent", "tour", "travel" ] -}, { - "name" : "lens_blur", - "tags" : [ "blur", "camera", "dim", "dot", "effect", "foggy", "fuzzy", "image", "lens", "photo", "soften" ] -}, { - "name" : "plumbing", - "tags" : [ "build", "construction", "fix", "handyman", "plumbing", "repair", "tools", "wrench" ] -}, { - "name" : "toys", - "tags" : [ "car", "games", "kids", "toy", "toys", "windmill" ] -}, { - "name" : "coffee_maker", - "tags" : [ "appliances", "beverage", "coffee", "cup", "drink", "machine", "maker", "mug" ] -}, { - "name" : "edit_notifications", - "tags" : [ "active", "alarm", "alert", "bell", "chime", "compose", "create", "draft", "edit", "editing", "input", "new", "notifications", "notify", "pen", "pencil", "reminder", "ring", "sound", "write", "writing" ] -}, { - "name" : "personal_video", - "tags" : [ "Android", "OS", "cam", "chrome", "desktop", "device", "hardware", "iOS", "mac", "monitor", "personal", "television", "tv", "video", "web", "window" ] -}, { - "name" : "animation", - "tags" : [ "animation", "circles", "film", "motion", "movement", "sequence", "video" ] -}, { - "name" : "bedtime", - "tags" : [ "bedtime", "nightime", "sleep" ] -}, { - "name" : "gamepad", - "tags" : [ "buttons", "console", "controller", "device", "game", "gamepad", "gaming", "playstation", "video" ] -}, { - "name" : "diversity_1", - "tags" : [ "committee", "diverse", "diversity", "family", "friends", "group", "groups", "heart", "humans", "network", "people", "persons", "social", "team" ] -}, { - "name" : "center_focus_weak", - "tags" : [ "camera", "center", "focus", "image", "lens", "photo", "photography", "weak", "zoom" ] -}, { - "name" : "signal_wifi_statusbar_4_bar", - "tags" : [ "4", "bar", "cell", "cellular", "data", "internet", "mobile", "network", "phone", "signal", "speed", "statusbar", "wifi", "wireless" ] -}, { - "name" : "manage_history", - "tags" : [ "application", "arrow", "back", "backwards", "change", "clock", "date", "details", "gear", "history", "options", "refresh", "renew", "reverse", "rotate", "schedule", "settings", "time", "turn" ] -}, { - "name" : "folder_zip", - "tags" : [ "compress", "data", "doc", "document", "drive", "file", "folder", "folders", "open", "sheet", "slide", "storage", "zip" ] -}, { - "name" : "flag_circle", - "tags" : [ "circle", "country", "flag", "goal", "mark", "nation", "report", "round", "start" ] -}, { - "name" : "south_west", - "tags" : [ "arrow", "directional", "down", "left", "maps", "navigation", "south", "west" ] -}, { - "name" : "looks_4", - "tags" : [ "4", "digit", "looks", "numbers", "square", "symbol" ] -}, { - "name" : "cloud_circle", - "tags" : [ "app", "application", "backup", "circle", "cloud", "connection", "drive", "files", "folders", "internet", "network", "sky", "storage", "upload" ] -}, { - "name" : "format_shapes", - "tags" : [ "alphabet", "character", "color", "doc", "edit", "editing", "editor", "fill", "font", "format", "letter", "paint", "shapes", "sheet", "spreadsheet", "style", "symbol", "text", "type", "writing" ] -}, { - "name" : "car_rental", - "tags" : [ "automobile", "car", "cars", "key", "maps", "rental", "transportation", "vehicle" ] -}, { - "name" : "movie_filter", - "tags" : [ "ai", "artificial", "automatic", "automation", "clapperboard", "creation", "custom", "film", "filter", "genai", "intelligence", "magic", "movie", "movies", "slate", "smart", "spark", "sparkle", "star", "stars", "video" ] -}, { - "name" : "layers_clear", - "tags" : [ "arrange", "clear", "delete", "disabled", "enabled", "interaction", "layers", "maps", "off", "on", "overlay", "pages", "slash" ] -}, { - "name" : "phonelink_lock", - "tags" : [ "Android", "OS", "cell", "connection", "device", "erase", "hardware", "iOS", "lock", "locked", "mobile", "password", "phone", "phonelink", "privacy", "private", "protection", "safety", "secure", "security", "tablet" ] -}, { - "name" : "attractions", - "tags" : [ "amusement", "attractions", "entertainment", "ferris", "fun", "maps", "park", "places", "wheel" ] -}, { - "name" : "playlist_add_check_circle", - "tags" : [ "add", "album", "artist", "audio", "cd", "check", "circle", "collection", "list", "mark", "music", "playlist", "record", "sound", "track" ] -}, { - "name" : "hive", - "tags" : [ "bee", "honey", "honeycomb" ] -}, { - "name" : "no_photography", - "tags" : [ "camera", "disabled", "enabled", "image", "no", "off", "on", "photo", "photography", "picture", "slash" ] -}, { - "name" : "content_paste_go", - "tags" : [ "clipboard", "content", "disabled", "doc", "document", "enabled", "file", "go", "on", "paste", "slash" ] -}, { - "name" : "shop_two", - "tags" : [ "add", "arrow", "buy", "cart", "google", "play", "purchase", "shop", "shopping", "two" ] -}, { - "name" : "edit_location", - "tags" : [ "destination", "direction", "edit", "location", "maps", "pen", "pencil", "pin", "place", "stop" ] -}, { - "name" : "screen_rotation", - "tags" : [ "Android", "OS", "arrow", "device", "hardware", "iOS", "mobile", "phone", "rotate", "rotation", "screen", "tablet", "turn" ] -}, { - "name" : "numbers", - "tags" : [ "digit", "number", "numbers", "symbol" ] -}, { - "name" : "sim_card", - "tags" : [ "camera", "card", "chip", "device", "memory", "phone", "sim", "storage" ] -}, { - "name" : "control_camera", - "tags" : [ "adjust", "arrow", "arrows", "camera", "center", "control", "direction", "left", "move", "right" ] -}, { - "name" : "blender", - "tags" : [ "appliance", "blender", "cooking", "electric", "juicer", "kitchen", "machine", "vitamix" ] -}, { - "name" : "flip_to_front", - "tags" : [ "arrange", "arrangement", "back", "flip", "format", "front", "layout", "move", "order", "sort", "to" ] -}, { - "name" : "sports_volleyball", - "tags" : [ "athlete", "athletic", "ball", "entertainment", "exercise", "game", "hobby", "social", "sports", "volleyball" ] -}, { - "name" : "stairs", - "tags" : [ "down", "staircase", "stairs", "up" ] -}, { - "name" : "keyboard_alt", - "tags" : [ "alt", "computer", "device", "hardware", "input", "keyboard", "keypad", "letter", "office", "text", "type" ] -}, { - "name" : "crop_din", - "tags" : [ "adjust", "adjustments", "area", "crop", "din", "edit", "editing", "frame", "image", "images", "photo", "photos", "rectangle", "settings", "size", "square" ] -}, { - "name" : "html", - "tags" : [ "alphabet", "brackets", "character", "code", "css", "develop", "developer", "engineer", "engineering", "font", "html", "letter", "platform", "symbol", "text", "type" ] -}, { - "name" : "signal_wifi_statusbar_connected_no_internet_4", - "tags" : [ "!", "4", "alert", "attention", "caution", "cell", "cellular", "connected", "danger", "data", "error", "exclamation", "important", "internet", "mark", "mobile", "network", "no", "notification", "phone", "signal", "speed", "statusbar", "symbol", "warning", "wifi", "wireless" ] -}, { - "name" : "pivot_table_chart", - "tags" : [ "analytics", "arrow", "arrows", "bar", "bars", "chart", "data", "diagram", "direction", "drive", "edit", "editing", "graph", "grid", "infographic", "measure", "metrics", "pivot", "rotate", "sheet", "statistics", "table", "tracking" ] -}, { - "name" : "microwave", - "tags" : [ "appliance", "cooking", "electric", "heat", "home", "house", "kitchen", "machine", "microwave" ] -}, { - "name" : "folder_copy", - "tags" : [ "content", "copy", "cut", "data", "doc", "document", "drive", "duplicate", "file", "folder", "folders", "multiple", "paste", "sheet", "slide", "storage" ] -}, { - "name" : "output", - "tags" : [ ] -}, { - "name" : "gif_box", - "tags" : [ "alphabet", "animated", "animation", "bitmap", "character", "font", "format", "gif", "graphics", "interchange", "letter", "symbol", "text", "type" ] -}, { - "name" : "voice_chat", - "tags" : [ "bubble", "cam", "camera", "chat", "comment", "communicate", "facetime", "feedback", "message", "speech", "video", "voice" ] -}, { - "name" : "local_convenience_store", - "tags" : [ "--", "24", "bill", "building", "business", "card", "cash", "coin", "commerce", "company", "convenience", "credit", "currency", "dollars", "local", "maps", "market", "money", "new", "online", "pay", "payment", "plus", "shop", "shopping", "store", "storefront", "symbol" ] -}, { - "name" : "gps_not_fixed", - "tags" : [ "destination", "direction", "disabled", "enabled", "gps", "location", "maps", "not fixed", "off", "on", "online", "place", "pointer", "slash", "tracking" ] -}, { - "name" : "high_quality", - "tags" : [ "alphabet", "character", "definition", "display", "font", "high", "hq", "letter", "movie", "movies", "quality", "resolution", "screen", "symbol", "text", "tv", "type" ] -}, { - "name" : "switch_right", - "tags" : [ "arrows", "directional", "navigation", "right", "switch", "toggle" ] -}, { - "name" : "pages", - "tags" : [ "article", "gplus", "pages", "paper", "post", "star" ] -}, { - "name" : "table_restaurant", - "tags" : [ "bar", "dining", "table" ] -}, { - "name" : "speaker_notes_off", - "tags" : [ "bubble", "chat", "comment", "communicate", "disabled", "enabled", "format", "list", "message", "notes", "off", "on", "slash", "speaker", "speech", "text" ] -}, { - "name" : "phone_disabled", - "tags" : [ "call", "cell", "contact", "device", "disabled", "enabled", "hardware", "mobile", "off", "offline", "on", "phone", "slash", "telephone" ] -}, { - "name" : "eject", - "tags" : [ "disc", "drive", "dvd", "eject", "remove", "triangle", "usb" ] -}, { - "name" : "control_point_duplicate", - "tags" : [ "+", "add", "circle", "control", "duplicate", "multiple", "new", "plus", "point", "symbol" ] -}, { - "name" : "filter", - "tags" : [ "edit", "editing", "effect", "filter", "image", "landscape", "mountain", "mountains", "photo", "photography", "picture", "settings" ] -}, { - "name" : "pest_control", - "tags" : [ "bug", "control", "exterminator", "insects", "pest" ] -}, { - "name" : "backpack", - "tags" : [ "back", "backpack", "bag", "book", "bookbag", "knapsack", "pack", "storage", "travel" ] -}, { - "name" : "leak_add", - "tags" : [ "add", "connection", "data", "leak", "link", "network", "service", "signals", "synce", "wireless" ] -}, { - "name" : "zoom_in_map", - "tags" : [ "arrow", "arrows", "destination", "in", "location", "maps", "move", "place", "stop", "zoom" ] -}, { - "name" : "brightness_7", - "tags" : [ "7", "brightness", "circle", "control", "crescent", "level", "moon", "screen", "sun" ] -}, { - "name" : "system_security_update_good", - "tags" : [ "Android", "OS", "approve", "cell", "check", "complete", "device", "done", "good", "hardware", "iOS", "mark", "mobile", "ok", "phone", "security", "select", "system", "tablet", "tick", "update", "validate", "verified", "yes" ] -}, { - "name" : "ring_volume", - "tags" : [ "call", "calling", "cell", "contact", "device", "hardware", "incoming", "mobile", "phone", "ring", "ringer", "sound", "telephone", "volume" ] -}, { - "name" : "money_off_csred", - "tags" : [ "bill", "card", "cart", "cash", "coin", "commerce", "credit", "csred", "currency", "disabled", "dollars", "enabled", "money", "off", "on", "online", "pay", "payment", "shopping", "slash", "symbol" ] -}, { - "name" : "sports_football", - "tags" : [ "athlete", "athletic", "ball", "entertainment", "exercise", "football", "game", "hobby", "social", "sports" ] -}, { - "name" : "nature", - "tags" : [ "forest", "nature", "outdoor", "outside", "park", "tree", "wilderness" ] -}, { - "name" : "vibration", - "tags" : [ "Android", "OS", "alert", "cell", "device", "hardware", "iOS", "mobile", "mode", "motion", "notification", "phone", "silence", "silent", "tablet", "vibrate", "vibration" ] -}, { - "name" : "snippet_folder", - "tags" : [ "data", "doc", "document", "drive", "file", "folder", "sheet", "slide", "snippet", "storage" ] -}, { - "name" : "edit_road", - "tags" : [ "destination", "direction", "edit", "highway", "maps", "pen", "pencil", "road", "street", "traffic" ] -}, { - "name" : "run_circle", - "tags" : [ "body", "circle", "exercise", "human", "people", "person", "run", "running" ] -}, { - "name" : "dry_cleaning", - "tags" : [ "cleaning", "dry", "hanger", "hotel", "laundry", "places", "service", "towel" ] -}, { - "name" : "alarm_off", - "tags" : [ "alarm", "alert", "bell", "clock", "disabled", "duration", "enabled", "notification", "off", "on", "slash", "time", "timer", "watch" ] -}, { - "name" : "perm_data_setting", - "tags" : [ "data", "gear", "info", "information", "perm", "settings" ] -}, { - "name" : "bedroom_parent", - "tags" : [ "bed", "bedroom", "double", "full", "furniture", "home", "hotel", "house", "king", "night", "parent", "pillows", "queen", "rest", "room", "sizem master", "sleep" ] -}, { - "name" : "airline_seat_recline_normal", - "tags" : [ "airline", "body", "extra", "feet", "human", "leg", "legroom", "normal", "people", "person", "recline", "seat", "sitting", "space", "travel" ] -}, { - "name" : "currency_bitcoin", - "tags" : [ "bill", "blockchain", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "digital", "dollars", "finance", "franc", "money", "online", "pay", "payment", "price", "shopping", "symbol" ] -}, { - "name" : "do_disturb_alt", - "tags" : [ "cancel", "close", "denied", "deny", "disturb", "do", "remove", "silence", "stop" ] -}, { - "name" : "sensor_window", - "tags" : [ "alarm", "security", "security system" ] -}, { - "name" : "incomplete_circle", - "tags" : [ "chart", "circle", "incomplete" ] -}, { - "name" : "settings_input_hdmi", - "tags" : [ "cable", "connection", "connectivity", "definition", "hdmi", "high", "input", "plug", "plugin", "points", "settings", "video", "wire" ] -}, { - "name" : "camera_indoor", - "tags" : [ "architecture", "building", "camera", "estate", "film", "filming", "home", "house", "image", "indoor", "inside", "motion", "nest", "picture", "place", "real", "residence", "residential", "shelter", "video", "videography" ] -}, { - "name" : "edit_location_alt", - "tags" : [ "alt", "edit", "location", "pen", "pencil", "pin" ] -}, { - "name" : "texture", - "tags" : [ "diagonal", "lines", "pattern", "stripes", "texture" ] -}, { - "name" : "location_off", - "tags" : [ "destination", "direction", "location", "maps", "off", "pin", "place", "room", "stop" ] -}, { - "name" : "edit_attributes", - "tags" : [ "approve", "attribution", "check", "complete", "done", "edit", "mark", "ok", "select", "tick", "validate", "verified", "yes" ] -}, { - "name" : "duo", - "tags" : [ "call", "chat", "conference", "device", "duo", "video" ] -}, { - "name" : "slow_motion_video", - "tags" : [ "arrow", "control", "controls", "motion", "music", "play", "slow", "speed", "video" ] -}, { - "name" : "perm_scan_wifi", - "tags" : [ "alert", "announcement", "connection", "info", "information", "internet", "network", "perm", "scan", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "phonelink_setup", - "tags" : [ "Android", "OS", "call", "chat", "device", "hardware", "iOS", "info", "mobile", "phone", "phonelink", "settings", "setup", "tablet", "text" ] -}, { - "name" : "hourglass_disabled", - "tags" : [ "clock", "countdown", "disabled", "empty", "enabled", "hourglass", "loading", "minute", "minutes", "off", "on", "slash", "time", "wait", "waiting" ] -}, { - "name" : "add_to_queue", - "tags" : [ "+", "Android", "OS", "add", "chrome", "desktop", "device", "display", "hardware", "iOS", "mac", "monitor", "new", "plus", "queue", "screen", "symbol", "to", "web", "window" ] -}, { - "name" : "pie_chart_outline", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "outline", "pie", "statistics", "tracking" ] -}, { - "name" : "playlist_remove", - "tags" : [ "-", "collection", "list", "minus", "music", "playlist", "remove" ] -}, { - "name" : "next_week", - "tags" : [ "arrow", "bag", "baggage", "briefcase", "business", "case", "next", "suitcase", "week" ] -}, { - "name" : "church", - "tags" : [ "christian", "christianity", "religion", "spiritual", "worship" ] -}, { - "name" : "medical_information", - "tags" : [ "badge", "card", "health", "id", "information", "medical", "services" ] -}, { - "name" : "view_compact", - "tags" : [ "compact", "grid", "layout", "pattern", "squares", "view" ] -}, { - "name" : "timer_off", - "tags" : [ "alarm", "alert", "bell", "clock", "disabled", "duration", "enabled", "notification", "off", "on", "slash", "stop", "time", "timer", "watch" ] -}, { - "name" : "bluetooth_connected", - "tags" : [ "bluetooth", "cast", "connect", "connection", "device", "paring", "streaming", "symbol", "wireless" ] -}, { - "name" : "photo_size_select_actual", - "tags" : [ "actual", "image", "mountain", "mountains", "photo", "photography", "picture", "select", "size" ] -}, { - "name" : "short_text", - "tags" : [ "brief", "comment", "doc", "document", "note", "short", "text", "write", "writing" ] -}, { - "name" : "bedroom_baby", - "tags" : [ "babies", "baby", "bedroom", "child", "children", "home", "horse", "house", "infant", "kid", "newborn", "rocking", "room", "toddler", "young" ] -}, { - "name" : "video_camera_back", - "tags" : [ "back", "camera", "image", "landscape", "mountain", "mountains", "photo", "photography", "picture", "rear", "video" ] -}, { - "name" : "bathroom", - "tags" : [ "bath", "bathroom", "closet", "home", "house", "place", "plumbing", "room", "shower", "sprinkler", "wash", "water", "wc" ] -}, { - "name" : "downhill_skiing", - "tags" : [ "athlete", "athletic", "body", "downhill", "entertainment", "exercise", "hobby", "human", "people", "person", "ski social", "skiing", "snow", "sports", "travel", "winter" ] -}, { - "name" : "filter_list_off", - "tags" : [ "alt", "disabled", "edit", "filter", "list", "off", "offline", "options", "refine", "sift", "slash" ] -}, { - "name" : "connected_tv", - "tags" : [ "Android", "OS", "airplay", "chrome", "connect", "connected", "desktop", "device", "display", "hardware", "iOS", "mac", "monitor", "screen", "screencast", "streaming", "television", "tv", "web", "window", "wireless" ] -}, { - "name" : "format_indent_increase", - "tags" : [ "align", "alignment", "doc", "edit", "editing", "editor", "format", "increase", "indent", "indentation", "paragraph", "sheet", "spreadsheet", "text", "type", "writing" ] -}, { - "name" : "settings_cell", - "tags" : [ "Android", "OS", "cell", "device", "hardware", "iOS", "mobile", "phone", "settings", "tablet" ] -}, { - "name" : "remember_me", - "tags" : [ "Android", "OS", "avatar", "device", "hardware", "human", "iOS", "identity", "me", "mobile", "people", "person", "phone", "profile", "remember", "tablet", "user" ] -}, { - "name" : "kayaking", - "tags" : [ "athlete", "athletic", "body", "canoe", "entertainment", "exercise", "hobby", "human", "kayak", "kayaking", "lake", "paddle", "paddling", "people", "person", "rafting", "river", "row", "social", "sports", "summer", "travel", "water" ] -}, { - "name" : "switch_access_shortcut_add", - "tags" : [ "+", "access", "add", "arrow", "arrows", "direction", "navigation", "new", "north", "plus", "shortcut", "switch", "symbol", "up" ] -}, { - "name" : "app_blocking", - "tags" : [ "Android", "OS", "app", "application", "block", "blocking", "cancel", "cell", "device", "hardware", "iOS", "mobile", "phone", "stop", "stopped", "tablet" ] -}, { - "name" : "elevator", - "tags" : [ "body", "down", "elevator", "human", "people", "person", "up" ] -}, { - "name" : "work_off", - "tags" : [ "bag", "baggage", "briefcase", "business", "case", "disabled", "enabled", "job", "off", "on", "slash", "suitcase", "work" ] -}, { - "name" : "sensors_off", - "tags" : [ "connection", "disabled", "enabled", "network", "off", "on", "scan", "sensors", "signal", "slash", "wireless" ] -}, { - "name" : "stay_primary_portrait", - "tags" : [ "Android", "OS", "current", "device", "hardware", "iOS", "mobile", "phone", "portrait", "primary", "stay", "tablet" ] -}, { - "name" : "cell_tower", - "tags" : [ "broadcast", "casting", "cell", "network", "signal", "tower", "transmitting", "wireless" ] -}, { - "name" : "moped", - "tags" : [ "automobile", "bike", "car", "cars", "maps", "scooter", "transportation", "vehicle", "vespa" ] -}, { - "name" : "wrong_location", - "tags" : [ "cancel", "close", "destination", "direction", "exit", "location", "maps", "no", "pin", "place", "quit", "remove", "stop", "wrong", "x" ] -}, { - "name" : "groups_2", - "tags" : [ "body", "club", "collaboration", "crowd", "gathering", "groups", "hair", "human", "meeting", "people", "person", "social", "teams" ] -}, { - "name" : "public_off", - "tags" : [ "disabled", "earth", "enabled", "global", "globe", "map", "network", "off", "on", "planet", "public", "slash", "social", "space", "web", "world" ] -}, { - "name" : "picture_in_picture_alt", - "tags" : [ "crop", "cropped", "overlap", "photo", "picture", "position", "shape" ] -}, { - "name" : "chair_alt", - "tags" : [ "cahir", "furniture", "home", "house", "kitchen", "lounging", "seating", "table" ] -}, { - "name" : "car_repair", - "tags" : [ "automobile", "car", "cars", "maps", "repair", "transportation", "vehicle" ] -}, { - "name" : "airplay", - "tags" : [ "airplay", "arrow", "connect", "control", "desktop", "device", "display", "monitor", "screen", "signal" ] -}, { - "name" : "nfc", - "tags" : [ "communication", "data", "field", "mobile", "near", "nfc", "wireless" ] -}, { - "name" : "line_style", - "tags" : [ "dash", "dotted", "line", "rule", "spacing", "style" ] -}, { - "name" : "transform", - "tags" : [ "adjust", "crop", "edit", "editing", "image", "photo", "picture", "transform" ] -}, { - "name" : "single_bed", - "tags" : [ "bed", "bedroom", "double", "furniture", "home", "hotel", "house", "king", "night", "pillows", "queen", "rest", "room", "single", "sleep", "twin" ] -}, { - "name" : "pattern", - "tags" : [ "key", "login", "password", "pattern", "pin", "security", "star", "unlock" ] -}, { - "name" : "local_movies", - "tags" : [ ] -}, { - "name" : "repeat_one", - "tags" : [ "1", "arrow", "arrows", "control", "controls", "digit", "media", "music", "number", "one", "repeat", "symbol", "video" ] -}, { - "name" : "swap_calls", - "tags" : [ "arrow", "arrows", "calls", "device", "direction", "mobile", "share", "swap" ] -}, { - "name" : "do_not_disturb_alt", - "tags" : [ "cancel", "close", "denied", "deny", "disturb", "do", "remove", "silence", "stop" ] -}, { - "name" : "smoking_rooms", - "tags" : [ "allowed", "cigarette", "places", "rooms", "smoke", "smoking", "tobacco", "zone" ] -}, { - "name" : "remove_moderator", - "tags" : [ "certified", "disabled", "enabled", "moderator", "off", "on", "privacy", "private", "protect", "protection", "remove", "security", "shield", "slash", "verified" ] -}, { - "name" : "perm_device_information", - "tags" : [ "Android", "OS", "alert", "announcement", "device", "hardware", "i", "iOS", "info", "information", "mobile", "perm", "phone", "tablet" ] -}, { - "name" : "wash", - "tags" : [ "bathroom", "clean", "fingers", "gesture", "hand", "wash", "wc" ] -}, { - "name" : "mode_standby", - "tags" : [ "disturb", "mode", "power", "sleep", "standby", "target" ] -}, { - "name" : "door_sliding", - "tags" : [ "auto", "automatic", "door", "doorway", "double", "entrance", "exit", "glass", "home", "house", "sliding", "two" ] -}, { - "name" : "skateboarding", - "tags" : [ "athlete", "athletic", "body", "entertainment", "exercise", "hobby", "human", "people", "person", "skate", "skateboarder", "skateboarding", "social", "sports" ] -}, { - "name" : "difference", - "tags" : [ "compare", "content", "copy", "cut", "diff", "difference", "doc", "document", "duplicate", "file", "multiple", "past" ] -}, { - "name" : "group_remove", - "tags" : [ "accounts", "committee", "face", "family", "friends", "group", "humans", "network", "people", "persons", "profiles", "remove", "social", "team", "users" ] -}, { - "name" : "brightness_high", - "tags" : [ "auto", "brightness", "control", "high", "mobile", "monitor", "phone", "sun" ] -}, { - "name" : "cabin", - "tags" : [ "architecture", "cabin", "camping", "cottage", "estate", "home", "house", "log", "maps", "place", "real", "residence", "residential", "stay", "traveling", "wood" ] -}, { - "name" : "camera_outdoor", - "tags" : [ "architecture", "building", "camera", "estate", "film", "filming", "home", "house", "image", "motion", "nest", "outdoor", "outside", "picture", "place", "real", "residence", "residential", "shelter", "video", "videography" ] -}, { - "name" : "troubleshoot", - "tags" : [ "analytics", "chart", "data", "diagram", "find", "glass", "graph", "infographic", "line", "look", "magnify", "magnifying", "measure", "metrics", "search", "see", "statistics", "tracking", "troubleshoot" ] -}, { - "name" : "tablet_android", - "tags" : [ "OS", "android", "device", "hardware", "iOS", "ipad", "mobile", "tablet", "web" ] -}, { - "name" : "house_siding", - "tags" : [ "architecture", "building", "construction", "estate", "exterior", "facade", "home", "house", "real", "residential", "siding" ] -}, { - "name" : "satellite", - "tags" : [ "bluetooth", "connect", "connection", "connectivity", "data", "device", "image", "internet", "landscape", "location", "maps", "mountain", "mountains", "network", "photo", "photography", "picture", "satellite", "scan", "service", "signal", "symbol", "wireless-- wifi" ] -}, { - "name" : "motion_photos_on", - "tags" : [ "animation", "circle", "disabled", "enabled", "motion", "off", "on", "photos", "play", "slash", "video" ] -}, { - "name" : "door_back", - "tags" : [ "back", "closed", "door", "doorway", "entrance", "exit", "home", "house", "way" ] -}, { - "name" : "strikethrough_s", - "tags" : [ "alphabet", "character", "cross", "doc", "edit", "editing", "editor", "font", "letter", "out", "s", "sheet", "spreadsheet", "strikethrough", "styles", "symbol", "text", "type", "writing" ] -}, { - "name" : "co2", - "tags" : [ "carbon", "chemical", "co2", "dioxide", "gas" ] -}, { - "name" : "notifications_paused", - "tags" : [ "active", "alarm", "alert", "bell", "chime", "ignore", "notifications", "notify", "paused", "quiet", "reminder", "ring --- pause", "sleep", "snooze", "sound", "z", "zzz" ] -}, { - "name" : "currency_yen", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "price", "shopping", "symbol", "yen" ] -}, { - "name" : "call_to_action", - "tags" : [ "action", "alert", "bar", "call", "components", "cta", "design", "info", "information", "interface", "layout", "message", "notification", "screen", "site", "to", "ui", "ux", "web", "website", "window" ] -}, { - "name" : "photo_camera_front", - "tags" : [ "account", "camera", "face", "front", "human", "image", "people", "person", "photo", "photography", "picture", "portrait", "profile", "user" ] -}, { - "name" : "directions_boat_filled", - "tags" : [ "automobile", "boat", "car", "cars", "direction", "directions", "ferry", "filled", "maps", "public", "transportation", "vehicle" ] -}, { - "name" : "subtitles_off", - "tags" : [ "accessibility", "accessible", "caption", "cc", "closed", "disabled", "enabled", "language", "off", "on", "slash", "subtitle", "subtitles", "translate", "video" ] -}, { - "name" : "rotate_90_degrees_ccw", - "tags" : [ "90", "arrow", "arrows", "ccw", "degrees", "direction", "edit", "editing", "image", "photo", "rotate", "turn" ] -}, { - "name" : "vertical_align_center", - "tags" : [ "align", "alignment", "arrow", "center", "doc", "down", "edit", "editing", "editor", "sheet", "spreadsheet", "text", "type", "up", "vertical", "writing" ] -}, { - "name" : "living", - "tags" : [ "chair", "comfort", "couch", "decoration", "furniture", "home", "house", "living", "lounging", "loveseat", "room", "seat", "seating", "sofa" ] -}, { - "name" : "battery_saver", - "tags" : [ "+", "add", "battery", "charge", "charging", "new", "plus", "power", "saver", "symbol" ] -}, { - "name" : "hot_tub", - "tags" : [ "bath", "bathing", "bathroom", "bathtub", "hot", "hotel", "human", "jacuzzi", "person", "shower", "spa", "steam", "travel", "tub", "water" ] -}, { - "name" : "play_lesson", - "tags" : [ "audio", "book", "bookmark", "digital", "ebook", "lesson", "multimedia", "play", "play lesson", "read", "reading", "ribbon" ] -}, { - "name" : "update_disabled", - "tags" : [ "arrow", "back", "backwards", "clock", "date", "disabled", "enabled", "forward", "history", "load", "off", "on", "refresh", "reverse", "rotate", "schedule", "slash", "time", "update" ] -}, { - "name" : "psychology_alt", - "tags" : [ "?", "assistance", "behavior", "body", "brain", "cognitive", "function", "gear", "head", "help", "human", "info", "information", "intellectual", "mental", "mind", "people", "person", "preferences", "psychiatric", "psychology", "punctuation", "question mark", "science", "settings", "social", "support", "symbol", "therapy", "thinking", "thoughts" ] -}, { - "name" : "cast_connected", - "tags" : [ "Android", "OS", "airplay", "cast", "chrome", "connect", "connected", "desktop", "device", "display", "hardware", "iOS", "mac", "monitor", "screen", "screencast", "streaming", "television", "tv", "web", "window", "wireless" ] -}, { - "name" : "format_color_reset", - "tags" : [ "clear", "color", "disabled", "doc", "droplet", "edit", "editing", "editor", "enabled", "fill", "format", "off", "on", "paint", "reset", "sheet", "slash", "spreadsheet", "style", "text", "type", "water", "writing" ] -}, { - "name" : "snooze", - "tags" : [ "alarm", "bell", "clock", "duration", "notification", "snooze", "time", "timer", "watch", "z" ] -}, { - "name" : "person_remove_alt_1", - "tags" : [ ] -}, { - "name" : "align_horizontal_left", - "tags" : [ "align", "alignment", "format", "horizontal", "layout", "left", "lines", "paragraph", "rule", "rules", "style", "text" ] -}, { - "name" : "boy", - "tags" : [ "body", "boy", "gender", "human", "male", "man", "people", "person", "social", "symbol" ] -}, { - "name" : "battery_5_bar", - "tags" : [ "5", "bar", "battery", "cell", "charge", "mobile", "power" ] -}, { - "name" : "mic_external_on", - "tags" : [ "audio", "disabled", "enabled", "external", "mic", "microphone", "off", "on", "slash", "sound", "voice" ] -}, { - "name" : "voicemail", - "tags" : [ "call", "device", "message", "missed", "mobile", "phone", "recording", "voice", "voicemail" ] -}, { - "name" : "join_full", - "tags" : [ "circle", "combine", "command", "full", "join", "left", "outer", "overlap", "right", "sql" ] -}, { - "name" : "looks_5", - "tags" : [ "5", "digit", "looks", "numbers", "square", "symbol" ] -}, { - "name" : "countertops", - "tags" : [ "counter", "countertops", "home", "house", "kitchen", "sink", "table", "tops" ] -}, { - "name" : "energy_savings_leaf", - "tags" : [ "eco", "energy", "leaf", "leaves", "nest", "savings", "usage" ] -}, { - "name" : "safety_divider", - "tags" : [ "apart", "distance", "divider", "safety", "separate", "social", "space" ] -}, { - "name" : "move_up", - "tags" : [ "arrow", "direction", "jump", "move", "navigation", "transfer", "up" ] -}, { - "name" : "storm", - "tags" : [ "forecast", "hurricane", "storm", "temperature", "twister", "weather", "wind" ] -}, { - "name" : "sync_disabled", - "tags" : [ "360", "around", "arrow", "arrows", "direction", "disabled", "enabled", "inprogress", "load", "loading refresh", "off", "on", "renew", "rotate", "slash", "sync", "turn" ] -}, { - "name" : "javascript", - "tags" : [ "alphabet", "brackets", "character", "code", "css", "develop", "developer", "engineer", "engineering", "font", "html", "javascript", "letter", "platform", "symbol", "text", "type" ] -}, { - "name" : "tram", - "tags" : [ "automobile", "car", "cars", "direction", "maps", "public", "rail", "subway", "train", "tram", "transportation", "vehicle" ] -}, { - "name" : "app_shortcut", - "tags" : [ "app", "bookmarked", "favorite", "highlight", "important", "marked", "mobile", "save", "saved", "shortcut", "software", "special", "star" ] -}, { - "name" : "data_saver_off", - "tags" : [ "analytics", "bar", "bars", "chart", "data", "diagram", "donut", "graph", "infographic", "measure", "metrics", "off", "on", "ring", "saver", "statistics", "tracking" ] -}, { - "name" : "laptop_windows", - "tags" : [ "Android", "OS", "chrome", "device", "display", "hardware", "iOS", "laptop", "mac", "monitor", "screen", "web", "window", "windows" ] -}, { - "name" : "doorbell", - "tags" : [ "alarm", "bell", "door", "doorbell", "home", "house", "ringing" ] -}, { - "name" : "hd", - "tags" : [ "alphabet", "character", "definition", "display", "font", "hd", "high", "letter", "movie", "movies", "resolution", "screen", "symbol", "text", "tv", "type" ] -}, { - "name" : "file_download_off", - "tags" : [ "arrow", "disabled", "down", "download", "drive", "enabled", "export", "file", "install", "off", "on", "save", "slash", "upload" ] -}, { - "name" : "apps_outage", - "tags" : [ "all", "applications", "apps", "circles", "collection", "components", "dots", "grid", "interface", "outage", "squares", "ui", "ux" ] -}, { - "name" : "taxi_alert", - "tags" : [ "!", "alert", "attention", "automobile", "cab", "car", "cars", "caution", "danger", "direction", "error", "exclamation", "important", "lyft", "maps", "mark", "notification", "public", "symbol", "taxi", "transportation", "uber", "vehicle", "warning", "yellow" ] -}, { - "name" : "breakfast_dining", - "tags" : [ "bakery", "bread", "breakfast", "butter", "dining", "food", "toast" ] -}, { - "name" : "brightness_medium", - "tags" : [ "auto", "brightness", "control", "medium", "mobile", "monitor", "phone", "sun" ] -}, { - "name" : "gradient", - "tags" : [ "color", "edit", "editing", "effect", "filter", "gradient", "image", "images", "photography", "picture", "pictures" ] -}, { - "name" : "swipe_left", - "tags" : [ "arrow", "arrows", "finger", "hand", "hit", "left", "navigation", "reject", "strike", "swing", "swipe", "take" ] -}, { - "name" : "soup_kitchen", - "tags" : [ "breakfast", "brunch", "dining", "food", "kitchen", "lunch", "meal", "soup" ] -}, { - "name" : "voice_over_off", - "tags" : [ "account", "disabled", "enabled", "face", "human", "off", "on", "over", "people", "person", "profile", "recording", "slash", "speak", "speaking", "speech", "transcript", "user", "voice" ] -}, { - "name" : "water_damage", - "tags" : [ "architecture", "building", "damage", "drop", "droplet", "estate", "house", "leak", "plumbing", "real", "residence", "residential", "shelter", "water" ] -}, { - "name" : "abc", - "tags" : [ "alphabet", "character", "font", "letter", "symbol", "text", "type" ] -}, { - "name" : "data_saver_on", - "tags" : [ "+", "add", "analytics", "chart", "data", "diagram", "graph", "infographic", "measure", "metrics", "new", "on", "plus", "ring", "saver", "statistics", "symbol", "tracking" ] -}, { - "name" : "signal_wifi_0_bar", - "tags" : [ "0", "bar", "cell", "cellular", "data", "internet", "mobile", "network", "phone", "signal", "wifi", "wireless" ] -}, { - "name" : "brightness_low", - "tags" : [ "auto", "brightness", "control", "low", "mobile", "monitor", "phone", "sun" ] -}, { - "name" : "device_unknown", - "tags" : [ "?", "Android", "OS", "assistance", "cell", "device", "hardware", "help", "iOS", "info", "information", "mobile", "phone", "punctuation", "question mark", "support", "symbol", "tablet", "unknown" ] -}, { - "name" : "fire_extinguisher", - "tags" : [ "emergency", "extinguisher", "fire", "water" ] -}, { - "name" : "fitbit", - "tags" : [ "athlete", "athletic", "exercise", "fitbit", "fitness", "hobby", "logo" ] -}, { - "name" : "bedroom_child", - "tags" : [ "bed", "bedroom", "child", "children", "furniture", "home", "hotel", "house", "kid", "night", "pillows", "rest", "room", "size", "sleep", "twin", "young" ] -}, { - "name" : "closed_caption_off", - "tags" : [ "accessible", "alphabet", "caption", "cc", "character", "closed", "decoder", "font", "language", "letter", "media", "movies", "off", "outline", "subtitle", "subtitles", "symbol", "text", "tv", "type" ] -}, { - "name" : "bluetooth_searching", - "tags" : [ "bluetooth", "connection", "device", "paring", "search", "searching", "symbol" ] -}, { - "name" : "content_paste_off", - "tags" : [ "clipboard", "content", "disabled", "doc", "document", "enabled", "file", "off", "on", "paste", "slash" ] -}, { - "name" : "hexagon", - "tags" : [ "hexagon", "shape", "six sides" ] -}, { - "name" : "tap_and_play", - "tags" : [ "Android", "OS wifi", "cell", "connection", "device", "hardware", "iOS", "internet", "mobile", "network", "phone", "play", "signal", "tablet", "tap", "to", "wireless" ] -}, { - "name" : "domain_add", - "tags" : [ "+", "add", "apartment", "architecture", "building", "business", "domain", "estate", "home", "new", "place", "plus", "real", "residence", "residential", "shelter", "symbol", "web", "www" ] -}, { - "name" : "signpost", - "tags" : [ "arrow", "direction", "left", "maps", "right", "signal", "signs", "street", "traffic" ] -}, { - "name" : "screenshot", - "tags" : [ "Android", "OS", "cell", "crop", "device", "hardware", "iOS", "mobile", "phone", "screen", "screenshot", "tablet" ] -}, { - "name" : "network_cell", - "tags" : [ "cell", "cellular", "data", "internet", "mobile", "network", "phone", "speed", "wifi", "wireless" ] -}, { - "name" : "repeat_on", - "tags" : [ "arrow", "arrows", "control", "controls", "media", "music", "on", "repeat", "video" ] -}, { - "name" : "charging_station", - "tags" : [ "Android", "OS", "battery", "bolt", "cell", "charging", "device", "electric", "hardware", "iOS", "lightning", "mobile", "phone", "station", "tablet", "thunderbolt" ] -}, { - "name" : "grid_4x4", - "tags" : [ "4", "by", "grid", "layout", "lines", "space" ] -}, { - "name" : "assistant_photo", - "tags" : [ "assistant", "flag", "photo", "recommendation", "smart", "star", "suggestion" ] -}, { - "name" : "carpenter", - "tags" : [ "building", "carpenter", "construction", "cutting", "handyman", "repair", "saw", "tool" ] -}, { - "name" : "private_connectivity", - "tags" : [ "connectivity", "lock", "locked", "password", "privacy", "private", "protection", "safety", "secure", "security" ] -}, { - "name" : "mobiledata_off", - "tags" : [ "arrow", "data", "disabled", "down", "enabled", "internet", "mobile", "network", "off", "on", "slash", "speed", "up", "wifi", "wireless" ] -}, { - "name" : "atm", - "tags" : [ "alphabet", "atm", "automated", "bill", "card", "cart", "cash", "character", "coin", "commerce", "credit", "currency", "dollars", "font", "letter", "machine", "money", "online", "pay", "payment", "shopping", "symbol", "teller", "text", "type" ] -}, { - "name" : "rv_hookup", - "tags" : [ "arrow", "attach", "automobile", "automotive", "back", "car", "cars", "connect", "direction", "hookup", "left", "maps", "public", "right", "rv", "trailer", "transportation", "travel", "truck", "van", "vehicle" ] -}, { - "name" : "replay_30", - "tags" : [ "30", "arrow", "arrows", "control", "controls", "digit", "music", "number", "refresh", "renew", "repeat", "replay", "symbol", "thirty", "video" ] -}, { - "name" : "offline_share", - "tags" : [ "Android", "OS", "arrow", "cell", "connect", "device", "direction", "hardware", "iOS", "link", "mobile", "multiple", "offline", "phone", "right", "share", "tablet" ] -}, { - "name" : "settings_input_svideo", - "tags" : [ "cable", "connection", "connectivity", "definition", "input", "plug", "plugin", "points", "settings", "standard", "svideo", "video" ] -}, { - "name" : "soap", - "tags" : [ "bathroom", "clean", "fingers", "gesture", "hand", "soap", "wash", "wc" ] -}, { - "name" : "baby_changing_station", - "tags" : [ "babies", "baby", "bathroom", "body", "changing", "child", "children", "father", "human", "infant", "kids", "mother", "newborn", "people", "person", "station", "toddler", "wc", "young" ] -}, { - "name" : "sports_cricket", - "tags" : [ "athlete", "athletic", "ball", "bat", "cricket", "entertainment", "exercise", "game", "hobby", "social", "sports" ] -}, { - "name" : "ad_units", - "tags" : [ "Android", "OS", "ad", "banner", "cell", "device", "hardware", "iOS", "mobile", "notification", "notifications", "phone", "tablet", "top", "units" ] -}, { - "name" : "wb_twilight", - "tags" : [ "balance", "light", "lighting", "noon", "sun", "sunset", "twilight", "wb", "white" ] -}, { - "name" : "no_encryption", - "tags" : [ "disabled", "enabled", "encryption", "lock", "no", "off", "on", "password", "safety", "security", "slash" ] -}, { - "name" : "table_bar", - "tags" : [ "bar", "cafe", "round", "table" ] -}, { - "name" : "diversity_2", - "tags" : [ "committee", "diverse", "diversity", "family", "friends", "group", "groups", "heart", "humans", "network", "people", "persons", "social", "team" ] -}, { - "name" : "subway", - "tags" : [ "automobile", "bike", "car", "cars", "maps", "rail", "scooter", "subway", "train", "transportation", "travel", "tunnel", "underground", "vehicle", "vespa" ] -}, { - "name" : "browser_updated", - "tags" : [ "Android", "OS", "arrow", "browser", "chrome", "desktop", "device", "display", "download", "hardware", "iOS", "mac", "monitor", "screen", "updated", "web", "window" ] -}, { - "name" : "currency_pound", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "pound", "price", "shopping", "symbol" ] -}, { - "name" : "transit_enterexit", - "tags" : [ "arrow", "direction", "enterexit", "maps", "navigation", "route", "transit", "transportation" ] -}, { - "name" : "contrast", - "tags" : [ "black", "contrast", "edit", "editing", "effect", "filter", "grayscale", "image", "images", "photography", "picture", "pictures", "settings", "white" ] -}, { - "name" : "lightbulb_circle", - "tags" : [ "alert", "announcement", "idea", "info", "information", "light", "lightbulb" ] -}, { - "name" : "rectangle", - "tags" : [ "four sides", "parallelograms", "polygons", "quadrilaterals", "recangle", "shape" ] -}, { - "name" : "call_merge", - "tags" : [ "arrow", "call", "device", "merge", "mobile" ] -}, { - "name" : "hide_image", - "tags" : [ "disabled", "enabled", "hide", "image", "landscape", "mountain", "mountains", "off", "on", "photo", "photography", "picture", "slash" ] -}, { - "name" : "shield_moon", - "tags" : [ "certified", "do not disturb", "moon", "night", "privacy", "private", "protect", "protection", "security", "shield", "verified" ] -}, { - "name" : "group_off", - "tags" : [ "body", "club", "collaboration", "crowd", "gathering", "group", "human", "meeting", "off", "people", "person", "social", "teams" ] -}, { - "name" : "music_off", - "tags" : [ "audio", "audiotrack", "disabled", "enabled", "key", "music", "note", "off", "on", "slash", "sound", "track" ] -}, { - "name" : "bluetooth_disabled", - "tags" : [ "bluetooth", "cast", "connect", "connection", "device", "disabled", "enabled", "off", "offline", "on", "paring", "slash", "streaming", "symbol", "wireless" ] -}, { - "name" : "flip_to_back", - "tags" : [ "arrange", "arrangement", "back", "flip", "format", "front", "layout", "move", "order", "sort", "to" ] -}, { - "name" : "sd_card", - "tags" : [ "camera", "card", "digital", "memory", "photos", "sd", "secure", "storage" ] -}, { - "name" : "exposure_plus_1", - "tags" : [ "1", "add", "brightness", "contrast", "digit", "edit", "editing", "effect", "exposure", "image", "number", "photo", "photography", "plus", "settings", "symbol" ] -}, { - "name" : "view_array", - "tags" : [ "array", "design", "format", "grid", "layout", "view", "website" ] -}, { - "name" : "sports_mma", - "tags" : [ "arts", "athlete", "athletic", "boxing", "combat", "entertainment", "exercise", "fighting", "game", "glove", "hobby", "martial", "mixed", "mma", "social", "sports" ] -}, { - "name" : "straight", - "tags" : [ "arrow", "arrows", "direction", "directions", "maps", "navigation", "path", "route", "sign", "straight", "traffic", "up" ] -}, { - "name" : "thermostat_auto", - "tags" : [ "A", "auto", "celsius", "fahrenheit", "meter", "temp", "temperature", "thermometer", "thermostat" ] -}, { - "name" : "mobile_screen_share", - "tags" : [ "Android", "OS", "cast", "cell", "device", "hardware", "iOS", "mirror", "mobile", "monitor", "phone", "screen", "screencast", "share", "stream", "streaming", "tablet", "tv", "wireless" ] -}, { - "name" : "phone_missed", - "tags" : [ "arrow", "call", "cell", "contact", "device", "hardware", "missed", "mobile", "phone", "telephone" ] -}, { - "name" : "brunch_dining", - "tags" : [ "breakfast", "brunch", "champagne", "dining", "drink", "food", "lunch", "meal" ] -}, { - "name" : "featured_video", - "tags" : [ "advertised", "advertisement", "featured", "highlighted", "recommended", "video", "watch" ] -}, { - "name" : "merge", - "tags" : [ "arrow", "arrows", "direction", "directions", "maps", "merge", "navigation", "path", "route", "sign", "traffic" ] -}, { - "name" : "open_in_new_off", - "tags" : [ "arrow", "box", "disabled", "enabled", "export", "in", "new", "off", "on", "open", "slash", "window" ] -}, { - "name" : "hdr_auto", - "tags" : [ "A", "alphabet", "auto", "camera", "character", "circle", "dynamic", "font", "hdr", "high", "letter", "photo", "range", "symbol", "text", "type" ] -}, { - "name" : "join_inner", - "tags" : [ "circle", "command", "inner", "join", "matching", "overlap", "sql", "values" ] -}, { - "name" : "solar_power", - "tags" : [ "eco", "energy", "heat", "nest", "power", "solar", "sun", "sunny" ] -}, { - "name" : "crop_16_9", - "tags" : [ "16", "9", "adjust", "adjustments", "area", "by", "crop", "edit", "editing", "frame", "image", "images", "photo", "photos", "rectangle", "settings", "size", "square" ] -}, { - "name" : "swipe_right", - "tags" : [ "accept", "arrows", "direction", "finger", "hands", "hit", "navigation", "right", "strike", "swing", "swpie", "take" ] -}, { - "name" : "phonelink_erase", - "tags" : [ "Android", "OS", "cancel", "cell", "close", "connection", "device", "erase", "exit", "hardware", "iOS", "mobile", "no", "phone", "phonelink", "remove", "stop", "tablet", "x" ] -}, { - "name" : "smoke_free", - "tags" : [ "cigarette", "disabled", "enabled", "free", "never", "no", "off", "on", "places", "prohibited", "slash", "smoke", "smoking", "tobacco", "warning", "zone" ] -}, { - "name" : "install_desktop", - "tags" : [ "Android", "OS", "chrome", "desktop", "device", "display", "fix", "hardware", "iOS", "install", "mac", "monitor", "place", "pwa", "screen", "web", "window" ] -}, { - "name" : "shutter_speed", - "tags" : [ "aperture", "camera", "duration", "image", "lens", "photo", "photography", "photos", "picture", "setting", "shutter", "speed", "stop", "time", "timer", "watch" ] -}, { - "name" : "keyboard_hide", - "tags" : [ "arrow", "computer", "device", "down", "hardware", "hide", "input", "keyboard", "keypad", "text" ] -}, { - "name" : "exposure", - "tags" : [ "add", "brightness", "contrast", "edit", "editing", "effect", "exposure", "image", "minus", "photo", "photography", "picture", "plus", "settings", "subtract" ] -}, { - "name" : "nordic_walking", - "tags" : [ "athlete", "athletic", "body", "entertainment", "exercise", "hiking", "hobby", "human", "nordic", "people", "person", "social", "sports", "travel", "walker", "walking" ] -}, { - "name" : "umbrella", - "tags" : [ "beach", "protection", "rain", "sun", "sunny", "umbrella" ] -}, { - "name" : "move_down", - "tags" : [ "arrow", "direction", "down", "jump", "move", "navigation", "transfer" ] -}, { - "name" : "filter_2", - "tags" : [ "2", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "settings", "stack", "symbol" ] -}, { - "name" : "photo_album", - "tags" : [ "album", "archive", "bookmark", "image", "label", "library", "mountain", "mountains", "photo", "photography", "picture", "ribbon", "save", "tag" ] -}, { - "name" : "security_update_good", - "tags" : [ "Android", "OS", "checkmark", "device", "good", "hardware", "iOS", "mobile", "ok", "phone", "security", "tablet", "tick", "update" ] -}, { - "name" : "ssid_chart", - "tags" : [ "chart", "graph", "lines", "network", "ssid", "wifi" ] -}, { - "name" : "score", - "tags" : [ "2k", "alphabet", "analytics", "bar", "bars", "character", "chart", "data", "diagram", "digit", "font", "graph", "infographic", "letter", "measure", "metrics", "number", "score", "statistics", "symbol", "text", "tracking", "type" ] -}, { - "name" : "swipe_up", - "tags" : [ "arrows", "direction", "disable", "enable", "finger", "hands", "hit", "navigation", "strike", "swing", "swpie", "take", "up" ] -}, { - "name" : "battery_4_bar", - "tags" : [ "4", "bar", "battery", "cell", "charge", "mobile", "power" ] -}, { - "name" : "all_out", - "tags" : [ "all", "circle", "out", "shape" ] -}, { - "name" : "battery_unknown", - "tags" : [ "?", "assistance", "battery", "cell", "charge", "help", "info", "information", "mobile", "power", "punctuation", "question mark", "support", "symbol", "unknown" ] -}, { - "name" : "sports_golf", - "tags" : [ "athlete", "athletic", "ball", "club", "entertainment", "exercise", "game", "golf", "golfer", "golfing", "hobby", "social", "sports" ] -}, { - "name" : "sports_martial_arts", - "tags" : [ "arts", "athlete", "athletic", "entertainment", "exercise", "hobby", "human", "karate", "martial", "people", "person", "social", "sports" ] -}, { - "name" : "filter_tilt_shift", - "tags" : [ "blur", "center", "edit", "editing", "effect", "filter", "focus", "image", "images", "photography", "picture", "pictures", "shift", "tilt" ] -}, { - "name" : "electric_bike", - "tags" : [ "bike", "electric", "electricity", "maps", "scooter", "transportation", "travel", "vespa" ] -}, { - "name" : "border_all", - "tags" : [ "all", "border", "doc", "edit", "editing", "editor", "sheet", "spreadsheet", "stroke", "text", "type", "writing" ] -}, { - "name" : "auto_mode", - "tags" : [ "ai", "around", "arrow", "arrows", "artificial", "auto", "automatic", "automation", "custom", "direction", "genai", "inprogress", "intelligence", "load", "loading refresh", "magic", "mode", "navigation", "nest", "renew", "rotate", "smart", "spark", "sparkle", "star", "turn" ] -}, { - "name" : "hvac", - "tags" : [ "air", "conditioning", "heating", "hvac", "ventilation" ] -}, { - "name" : "scanner", - "tags" : [ "copy", "device", "hardware", "machine", "scan", "scanner" ] -}, { - "name" : "shuffle_on", - "tags" : [ "arrow", "arrows", "control", "controls", "music", "on", "random", "shuffle", "video" ] -}, { - "name" : "wifi_calling_3", - "tags" : [ "3", "calling", "cell", "cellular", "data", "internet", "mobile", "network", "phone", "speed", "wifi", "wireless" ] -}, { - "name" : "signal_wifi_off", - "tags" : [ "cell", "cellular", "data", "disabled", "enabled", "internet", "mobile", "network", "off", "on", "phone", "signal", "slash", "speed", "wifi", "wireless" ] -}, { - "name" : "girl", - "tags" : [ "body", "female", "gender", "girl", "human", "lady", "people", "person", "social", "symbol", "woman", "women" ] -}, { - "name" : "shop_2", - "tags" : [ "2", "add", "arrow", "buy", "cart", "google", "play", "purchase", "shop", "shopping" ] -}, { - "name" : "hdr_strong", - "tags" : [ "circles", "dots", "dynamic", "enhance", "hdr", "high", "range", "strong" ] -}, { - "name" : "directions_transit", - "tags" : [ "automobile", "car", "cars", "direction", "directions", "maps", "public", "rail", "subway", "train", "transit", "transportation", "vehicle" ] -}, { - "name" : "label_off", - "tags" : [ "disabled", "enabled", "favorite", "indent", "label", "library", "mail", "off", "on", "remember", "save", "slash", "stamp", "sticker", "tag", "wing" ] -}, { - "name" : "tablet", - "tags" : [ "Android", "OS", "device", "hardware", "iOS", "ipad", "mobile", "tablet", "web" ] -}, { - "name" : "5g", - "tags" : [ "5g", "alphabet", "cellular", "character", "data", "digit", "font", "letter", "mobile", "network", "number", "phone", "signal", "speed", "symbol", "text", "type", "wifi" ] -}, { - "name" : "vrpano", - "tags" : [ "angle", "image", "landscape", "mountain", "mountains", "panorama", "photo", "photography", "picture", "view", "vrpano", "wide" ] -}, { - "name" : "forward_30", - "tags" : [ "30", "arrow", "control", "controls", "digit", "fast", "forward", "music", "number", "seconds", "symbol", "video" ] -}, { - "name" : "battery_0_bar", - "tags" : [ "0", "bar", "battery", "cell", "charge", "mobile", "power" ] -}, { - "name" : "airline_seat_recline_extra", - "tags" : [ "airline", "body", "extra", "feet", "human", "leg", "legroom", "people", "person", "seat", "sitting", "space", "travel" ] -}, { - "name" : "looks", - "tags" : [ "circle", "half", "looks", "rainbow" ] -}, { - "name" : "linked_camera", - "tags" : [ "camera", "connect", "connection", "lens", "linked", "network", "photo", "photography", "picture", "signal", "signals", "sync", "wireless" ] -}, { - "name" : "paragliding", - "tags" : [ "athlete", "athletic", "body", "entertainment", "exercise", "fly", "gliding", "hobby", "human", "parachute", "paragliding", "people", "person", "sky", "skydiving", "social", "sports", "travel" ] -}, { - "name" : "electric_scooter", - "tags" : [ "bike", "electric", "maps", "scooter", "transportation", "vehicle", "vespa" ] -}, { - "name" : "settings_system_daydream", - "tags" : [ "backup", "cloud", "daydream", "drive", "settings", "storage", "system" ] -}, { - "name" : "format_indent_decrease", - "tags" : [ "align", "alignment", "decrease", "doc", "edit", "editing", "editor", "format", "indent", "indentation", "paragraph", "sheet", "spreadsheet", "text", "type", "writing" ] -}, { - "name" : "tapas", - "tags" : [ "appetizer", "brunch", "dinner", "food", "lunch", "restaurant", "snack", "tapas" ] -}, { - "name" : "brightness_3", - "tags" : [ "3", "brightness", "circle", "control", "crescent", "level", "moon", "screen" ] -}, { - "name" : "tab_unselected", - "tags" : [ "browser", "computer", "document", "documents", "folder", "internet", "tab", "tabs", "unselected", "web", "website", "window", "windows" ] -}, { - "name" : "density_small", - "tags" : [ "density", "horizontal", "lines", "rule", "rules", "small" ] -}, { - "name" : "blur_circular", - "tags" : [ "blur", "circle", "circular", "dots", "edit", "editing", "effect", "enhance", "filter" ] -}, { - "name" : "rice_bowl", - "tags" : [ "bowl", "dinner", "food", "lunch", "meal", "restaurant", "rice" ] -}, { - "name" : "rounded_corner", - "tags" : [ "adjust", "corner", "edit", "rounded", "shape", "square", "transform" ] -}, { - "name" : "person_add_disabled", - "tags" : [ "+", "account", "add", "disabled", "enabled", "face", "human", "new", "off", "offline", "on", "people", "person", "plus", "profile", "slash", "symbol", "user" ] -}, { - "name" : "music_video", - "tags" : [ "band", "music", "recording", "screen", "tv", "video", "watch" ] -}, { - "name" : "looks_6", - "tags" : [ "6", "digit", "looks", "numbers", "square", "symbol" ] -}, { - "name" : "do_not_touch", - "tags" : [ "disabled", "do", "enabled", "fingers", "gesture", "hand", "not", "off", "on", "slash", "touch" ] -}, { - "name" : "playlist_add_circle", - "tags" : [ "add", "album", "artist", "audio", "cd", "check", "circle", "collection", "list", "mark", "music", "playlist", "record", "sound", "track" ] -}, { - "name" : "domain_disabled", - "tags" : [ "apartment", "architecture", "building", "business", "company", "disabled", "domain", "enabled", "estate", "home", "internet", "maps", "off", "office", "offline", "on", "place", "real", "residence", "residential", "slash", "web", "website" ] -}, { - "name" : "flash_auto", - "tags" : [ "a", "auto", "bolt", "electric", "fast", "flash", "lightning", "thunderbolt" ] -}, { - "name" : "6_ft_apart", - "tags" : [ "6", "apart", "body", "covid", "distance", "feet", "ft", "human", "people", "person", "social" ] -}, { - "name" : "signal_wifi_bad", - "tags" : [ "bad", "bar", "cancel", "cell", "cellular", "close", "data", "exit", "internet", "mobile", "network", "no", "phone", "quit", "remove", "signal", "stop", "wifi", "wireless", "x" ] -}, { - "name" : "crisis_alert", - "tags" : [ "!", "alert", "attention", "bullseye", "caution", "crisis", "danger", "error", "exclamation", "important", "mark", "notification", "symbol", "target", "warning" ] -}, { - "name" : "queue_play_next", - "tags" : [ "+", "add", "arrow", "desktop", "device", "display", "hardware", "monitor", "new", "next", "play", "plus", "queue", "screen", "steam", "symbol", "tv" ] -}, { - "name" : "format_clear", - "tags" : [ "T", "alphabet", "character", "clear", "disabled", "doc", "edit", "editing", "editor", "enabled", "font", "format", "letter", "off", "on", "sheet", "slash", "spreadsheet", "style", "symbol", "text", "type", "writing" ] -}, { - "name" : "bus_alert", - "tags" : [ "!", "alert", "attention", "automobile", "bus", "car", "cars", "caution", "danger", "error", "exclamation", "important", "maps", "mark", "notification", "symbol", "transportation", "vehicle", "warning" ] -}, { - "name" : "party_mode", - "tags" : [ "camera", "lens", "mode", "party", "photo", "photography", "picture" ] -}, { - "name" : "snowboarding", - "tags" : [ "athlete", "athletic", "body", "entertainment", "exercise", "hobby", "human", "people", "person", "snow", "snowboarding", "social", "sports", "travel", "winter" ] -}, { - "name" : "text_rotate_vertical", - "tags" : [ "A", "alphabet", "arrow", "character", "down", "field", "font", "letter", "move", "rotate", "symbol", "text", "type", "vertical" ] -}, { - "name" : "motion_photos_auto", - "tags" : [ "A", "alphabet", "animation", "auto", "automatic", "character", "circle", "font", "gif", "letter", "live", "motion", "photos", "symbol", "text", "type", "video" ] -}, { - "name" : "crop_portrait", - "tags" : [ "adjust", "adjustments", "area", "crop", "edit", "editing", "frame", "image", "images", "photo", "photos", "portrait", "rectangle", "settings", "size", "square" ] -}, { - "name" : "thunderstorm", - "tags" : [ "bolt", "climate", "cloud", "cloudy", "lightning", "rain", "rainfall", "rainstorm", "storm", "thunder", "thunderstorm", "weather" ] -}, { - "name" : "battery_6_bar", - "tags" : [ "6", "bar", "battery", "cell", "charge", "mobile", "power" ] -}, { - "name" : "space_bar", - "tags" : [ "bar", "keyboard", "line", "space" ] -}, { - "name" : "replay_5", - "tags" : [ "5", "arrow", "arrows", "control", "controls", "digit", "five", "music", "number", "refresh", "renew", "repeat", "replay", "symbol", "video" ] -}, { - "name" : "local_car_wash", - "tags" : [ "automobile", "car", "cars", "local", "maps", "transportation", "travel", "vehicle", "wash" ] -}, { - "name" : "folder_delete", - "tags" : [ "bin", "can", "data", "delete", "doc", "document", "drive", "file", "folder", "folders", "garbage", "remove", "sheet", "slide", "storage", "trash" ] -}, { - "name" : "data_thresholding", - "tags" : [ "data", "hidden", "privacy", "thresholding", "thresold" ] -}, { - "name" : "connecting_airports", - "tags" : [ "airplane", "airplanes", "airport", "airports", "connecting", "flight", "plane", "transportation", "travel", "trip" ] -}, { - "name" : "access_alarms", - "tags" : [ ] -}, { - "name" : "tty", - "tags" : [ "call", "cell", "contact", "deaf", "device", "hardware", "impaired", "mobile", "phone", "speech", "talk", "telephone", "text", "tty" ] -}, { - "name" : "audio_file", - "tags" : [ "audio", "doc", "document", "key", "music", "note", "sound", "track" ] -}, { - "name" : "egg", - "tags" : [ "breakfast", "brunch", "egg", "food" ] -}, { - "name" : "balcony", - "tags" : [ "architecture", "balcony", "doors", "estate", "home", "house", "maps", "out", "outside", "place", "real", "residence", "residential", "stay", "terrace", "window" ] -}, { - "name" : "kitesurfing", - "tags" : [ "athlete", "athletic", "beach", "body", "entertainment", "exercise", "hobby", "human", "kitesurfing", "people", "person", "social", "sports", "surf", "travel", "water" ] -}, { - "name" : "call_missed_outgoing", - "tags" : [ "arrow", "call", "device", "missed", "mobile", "outgoing" ] -}, { - "name" : "local_hotel", - "tags" : [ "body", "hotel", "human", "local", "people", "person", "sleep", "stay", "travel", "trip" ] -}, { - "name" : "text_increase", - "tags" : [ "+", "add", "alphabet", "character", "font", "increase", "letter", "new", "plus", "resize", "symbol", "text", "type" ] -}, { - "name" : "speaker_phone", - "tags" : [ "Android", "OS", "cell", "device", "hardware", "iOS", "mobile", "phone", "sound", "speaker", "tablet", "volume" ] -}, { - "name" : "no_food", - "tags" : [ "disabled", "drink", "enabled", "fastfood", "food", "hamburger", "meal", "no", "off", "on", "slash" ] -}, { - "name" : "brightness_2", - "tags" : [ "2", "brightness", "circle", "control", "crescent", "level", "moon", "screen" ] -}, { - "name" : "mode_of_travel", - "tags" : [ "arrow", "destination", "direction", "location", "maps", "mode", "of", "pin", "place", "stop", "transportation", "travel", "trip" ] -}, { - "name" : "format_line_spacing", - "tags" : [ "align", "alignment", "doc", "edit", "editing", "editor", "format", "line", "sheet", "spacing", "spreadsheet", "text", "type", "writing" ] -}, { - "name" : "iso", - "tags" : [ "add", "edit", "editing", "effect", "image", "iso", "minus", "photography", "picture", "plus", "sensor", "shutter", "speed", "subtract" ] -}, { - "name" : "explore_off", - "tags" : [ "compass", "destination", "direction", "disabled", "east", "enabled", "explore", "location", "maps", "needle", "north", "off", "on", "slash", "south", "travel", "west" ] -}, { - "name" : "drive_file_move_rtl", - "tags" : [ "arrow", "arrows", "data", "direction", "doc", "document", "drive", "file", "folder", "folders", "left", "move", "rtl", "sheet", "side", "slide", "storage" ] -}, { - "name" : "cell_wifi", - "tags" : [ "cell", "connection", "data", "internet", "mobile", "network", "phone", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "tonality", - "tags" : [ "circle", "edit", "editing", "filter", "image", "photography", "picture", "tonality" ] -}, { - "name" : "spoke", - "tags" : [ "connection", "network", "radius", "spoke" ] -}, { - "name" : "photo_filter", - "tags" : [ "ai", "artificial", "automatic", "automation", "custom", "filter", "filters", "genai", "image", "intelligence", "magic", "photo", "photography", "picture", "smart", "spark", "sparkle", "star" ] -}, { - "name" : "desktop_access_disabled", - "tags" : [ "Android", "OS", "access", "chrome", "desktop", "device", "disabled", "display", "enabled", "hardware", "iOS", "mac", "monitor", "off", "offline", "on", "screen", "slash", "web", "window" ] -}, { - "name" : "sports_gymnastics", - "tags" : [ "athlete", "athletic", "entertainment", "exercise", "gymnastics", "hobby", "social", "sports" ] -}, { - "name" : "houseboat", - "tags" : [ "architecture", "beach", "boat", "estate", "floating", "home", "house", "houseboat", "maps", "place", "real", "residence", "residential", "sea", "stay", "traveling", "vacation" ] -}, { - "name" : "fence", - "tags" : [ "backyard", "barrier", "boundaries", "boundary", "fence", "home", "house", "protection", "yard" ] -}, { - "name" : "commit", - "tags" : [ "accomplish", "bind", "circle", "commit", "dedicate", "execute", "line", "perform", "pledge" ] -}, { - "name" : "photo_size_select_small", - "tags" : [ "adjust", "album", "edit", "editing", "image", "large", "library", "mountain", "mountains", "photo", "photography", "picture", "select", "size", "small" ] -}, { - "name" : "signal_wifi_connected_no_internet_4", - "tags" : [ "4", "cell", "cellular", "connected", "data", "internet", "mobile", "network", "no", "offline", "phone", "signal", "wifi", "wireless", "x" ] -}, { - "name" : "horizontal_distribute", - "tags" : [ "alignment", "distribute", "format", "horizontal", "layout", "lines", "paragraph", "rule", "rules", "style", "text" ] -}, { - "name" : "report_off", - "tags" : [ "!", "alert", "attention", "caution", "danger", "disabled", "enabled", "error", "exclamation", "important", "mark", "notification", "octagon", "off", "offline", "on", "report", "slash", "symbol", "warning" ] -}, { - "name" : "polyline", - "tags" : [ "compose", "create", "design", "draw", "line", "polyline", "vector" ] -}, { - "name" : "art_track", - "tags" : [ "album", "art", "artist", "audio", "image", "music", "photo", "photography", "picture", "sound", "track", "tracks" ] -}, { - "name" : "crop_7_5", - "tags" : [ "5", "7", "adjust", "adjustments", "area", "by", "crop", "editing", "frame", "image", "images", "photo", "photos", "rectangle", "settings", "size", "square" ] -}, { - "name" : "filter_hdr", - "tags" : [ "camera", "edit", "editing", "effect", "filter", "hdr", "image", "mountain", "mountains", "photo", "photography", "picture" ] -}, { - "name" : "text_rotation_none", - "tags" : [ "A", "alphabet", "arrow", "character", "field", "font", "letter", "move", "none", "rotate", "symbol", "text", "type" ] -}, { - "name" : "battery_3_bar", - "tags" : [ "3", "bar", "battery", "cell", "charge", "mobile", "power" ] -}, { - "name" : "align_vertical_bottom", - "tags" : [ "align", "alignment", "bottom", "format", "layout", "lines", "paragraph", "rule", "rules", "style", "text", "vertical" ] -}, { - "name" : "stop_screen_share", - "tags" : [ "Android", "OS", "arrow", "cast", "chrome", "device", "disabled", "display", "enabled", "hardware", "iOS", "laptop", "mac", "mirror", "monitor", "off", "offline", "on", "screen", "share", "slash", "steam", "stop", "streaming", "web", "window" ] -}, { - "name" : "imagesearch_roller", - "tags" : [ "art", "image", "imagesearch", "paint", "roller", "search" ] -}, { - "name" : "bento", - "tags" : [ "bento", "box", "dinner", "food", "lunch", "meal", "restaurant", "takeout" ] -}, { - "name" : "rotate_90_degrees_cw", - "tags" : [ "90", "arrow", "arrows", "ccw", "degrees", "direction", "edit", "editing", "image", "photo", "rotate", "turn" ] -}, { - "name" : "install_mobile", - "tags" : [ "Android", "OS", "cell", "device", "hardware", "iOS", "install", "mobile", "phone", "pwa", "tablet" ] -}, { - "name" : "hearing_disabled", - "tags" : [ "accessibility", "accessible", "aid", "disabled", "ear", "enabled", "handicap", "hearing", "help", "impaired", "listen", "off", "on", "slash", "sound", "volume" ] -}, { - "name" : "video_file", - "tags" : [ "camera", "doc", "document", "film", "filming", "hardware", "image", "motion", "picture", "video", "videography" ] -}, { - "name" : "mms", - "tags" : [ "bubble", "chat", "comment", "communicate", "feedback", "image", "landscape", "message", "mms", "mountain", "mountains", "multimedia", "photo", "photography", "picture", "speech" ] -}, { - "name" : "crop_rotate", - "tags" : [ "adjust", "adjustments", "area", "arrow", "arrows", "crop", "edit", "editing", "frame", "image", "images", "photo", "photos", "rotate", "settings", "size", "turn" ] -}, { - "name" : "wheelchair_pickup", - "tags" : [ "accessibility", "accessible", "body", "handicap", "help", "human", "person", "pickup", "wheelchair" ] -}, { - "name" : "aod", - "tags" : [ "Android", "OS", "always", "aod", "device", "display", "hardware", "homescreen", "iOS", "mobile", "on", "phone", "tablet" ] -}, { - "name" : "castle", - "tags" : [ "castle", "fort", "fortress", "mansion", "palace" ] -}, { - "name" : "interpreter_mode", - "tags" : [ "interpreter", "language", "microphone", "mode", "person", "speaking", "symbol" ] -}, { - "name" : "access_alarm", - "tags" : [ ] -}, { - "name" : "forward_5", - "tags" : [ "10", "5", "arrow", "control", "controls", "digit", "fast", "forward", "music", "number", "seconds", "symbol", "video" ] -}, { - "name" : "add_to_home_screen", - "tags" : [ "Android", "OS", "add to", "arrow", "cell", "device", "hardware", "home", "iOS", "mobile", "phone", "screen", "tablet", "up" ] -}, { - "name" : "not_accessible", - "tags" : [ "accessibility", "accessible", "body", "handicap", "help", "human", "not", "person", "wheelchair" ] -}, { - "name" : "signal_cellular_0_bar", - "tags" : [ "0", "bar", "cell", "cellular", "data", "internet", "mobile", "network", "phone", "signal", "speed", "wifi", "wireless" ] -}, { - "name" : "stadium", - "tags" : [ "activity", "amphitheater", "arena", "coliseum", "event", "local", "stadium", "star", "things", "ticket" ] -}, { - "name" : "photo_size_select_large", - "tags" : [ "adjust", "album", "edit", "editing", "image", "large", "library", "mountain", "mountains", "photo", "photography", "picture", "select", "size" ] -}, { - "name" : "groups_3", - "tags" : [ "abstract", "body", "club", "collaboration", "crowd", "gathering", "groups", "human", "meeting", "people", "person", "social", "teams" ] -}, { - "name" : "snowshoeing", - "tags" : [ "body", "human", "people", "person", "snow", "snowshoe", "snowshoeing", "sports", "travel", "walking", "winter" ] -}, { - "name" : "view_kanban", - "tags" : [ "grid", "kanban", "layout", "pattern", "squares", "view" ] -}, { - "name" : "candlestick_chart", - "tags" : [ "analytics", "candlestick", "chart", "data", "diagram", "finance", "graph", "infographic", "measure", "metrics", "statistics", "tracking" ] -}, { - "name" : "filter_3", - "tags" : [ "3", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "settings", "stack", "symbol" ] -}, { - "name" : "arrow_outward", - "tags" : [ "app", "application", "arrow", "arrows", "components", "direction", "forward", "interface", "navigation", "right", "screen", "site", "ui", "ux", "web", "website" ] -}, { - "name" : "align_horizontal_center", - "tags" : [ "align", "alignment", "center", "format", "horizontal", "layout", "lines", "paragraph", "rule", "rules", "style", "text" ] -}, { - "name" : "flashlight_off", - "tags" : [ "disabled", "enabled", "flash", "flashlight", "light", "off", "on", "slash" ] -}, { - "name" : "security_update", - "tags" : [ "Android", "OS", "arrow", "device", "down", "download", "hardware", "iOS", "mobile", "phone", "security", "tablet", "update" ] -}, { - "name" : "iron", - "tags" : [ "appliance", "clothes", "electric", "iron", "ironing", "machine", "object" ] -}, { - "name" : "print_disabled", - "tags" : [ "disabled", "enabled", "off", "on", "paper", "print", "printer", "slash" ] -}, { - "name" : "pin_invoke", - "tags" : [ "action", "arrow", "dot", "invoke", "pin" ] -}, { - "name" : "speaker_group", - "tags" : [ "box", "electronic", "group", "loud", "multiple", "music", "sound", "speaker", "stereo", "system", "video" ] -}, { - "name" : "exposure_zero", - "tags" : [ "0", "brightness", "contrast", "digit", "edit", "editing", "effect", "exposure", "image", "number", "photo", "photography", "settings", "symbol", "zero" ] -}, { - "name" : "bungalow", - "tags" : [ "architecture", "bungalow", "cottage", "estate", "home", "house", "maps", "place", "real", "residence", "residential", "stay", "traveling" ] -}, { - "name" : "streetview", - "tags" : [ "maps", "street", "streetview", "view" ] -}, { - "name" : "swipe_down", - "tags" : [ "arrows", "direction", "disable", "down", "enable", "finger", "hands", "hit", "navigation", "strike", "swing", "swpie", "take" ] -}, { - "name" : "hdr_weak", - "tags" : [ "circles", "dots", "dynamic", "enhance", "hdr", "high", "range", "weak" ] -}, { - "name" : "css", - "tags" : [ "alphabet", "brackets", "character", "code", "css", "develop", "developer", "engineer", "engineering", "font", "html", "letter", "platform", "symbol", "text", "type" ] -}, { - "name" : "call_missed", - "tags" : [ "arrow", "call", "device", "missed", "mobile" ] -}, { - "name" : "gps_off", - "tags" : [ "destination", "direction", "disabled", "enabled", "gps", "location", "maps", "not fixed", "off", "offline", "on", "place", "pointer", "slash", "tracking" ] -}, { - "name" : "sports_hockey", - "tags" : [ "athlete", "athletic", "entertainment", "exercise", "game", "hobby", "hockey", "social", "sports", "sticks" ] -}, { - "name" : "ice_skating", - "tags" : [ "athlete", "athletic", "entertainment", "exercise", "hobby", "ice", "shoe", "skates", "skating", "social", "sports", "travel" ] -}, { - "name" : "keyboard_capslock", - "tags" : [ "arrow", "capslock", "keyboard", "up" ] -}, { - "name" : "earbuds", - "tags" : [ "accessory", "audio", "earbuds", "earphone", "headphone", "listen", "music", "sound" ] -}, { - "name" : "camera_front", - "tags" : [ "body", "camera", "front", "human", "lens", "mobile", "person", "phone", "photography", "portrait", "selfie" ] -}, { - "name" : "vertical_distribute", - "tags" : [ "alignment", "distribute", "format", "layout", "lines", "paragraph", "rule", "rules", "style", "text", "vertical" ] -}, { - "name" : "currency_ruble", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "price", "ruble", "shopping", "symbol" ] -}, { - "name" : "signal_wifi_statusbar_null", - "tags" : [ "cell", "cellular", "data", "internet", "mobile", "network", "null", "phone", "signal", "speed", "statusbar", "wifi", "wireless" ] -}, { - "name" : "align_horizontal_right", - "tags" : [ "align", "alignment", "format", "horizontal", "layout", "lines", "paragraph", "right", "rule", "rules", "style", "text" ] -}, { - "name" : "crop_5_4", - "tags" : [ "4", "5", "adjust", "adjustments", "area", "by", "crop", "edit", "editing settings", "frame", "image", "images", "photo", "photos", "rectangle", "size", "square" ] -}, { - "name" : "format_strikethrough", - "tags" : [ "alphabet", "character", "doc", "edit", "editing", "editor", "font", "format", "letter", "sheet", "spreadsheet", "strikethrough", "style", "symbol", "text", "type", "writing" ] -}, { - "name" : "face_6", - "tags" : [ "account", "emoji", "eyes", "face", "human", "lock", "log", "login", "logout", "people", "person", "profile", "recognition", "security", "social", "thumbnail", "unlock", "user" ] -}, { - "name" : "join_left", - "tags" : [ "circle", "command", "join", "left", "matching", "overlap", "sql", "values" ] -}, { - "name" : "explicit", - "tags" : [ "adult", "alphabet", "character", "content", "e", "explicit", "font", "language", "letter", "media", "movies", "music", "symbol", "text", "type" ] -}, { - "name" : "extension_off", - "tags" : [ "disabled", "enabled", "extended", "extension", "jigsaw", "off", "on", "piece", "puzzle", "shape", "slash" ] -}, { - "name" : "perm_camera_mic", - "tags" : [ "camera", "image", "microphone", "min", "perm", "photo", "photography", "picture", "speaker" ] -}, { - "name" : "sports_rugby", - "tags" : [ "athlete", "athletic", "ball", "entertainment", "exercise", "game", "hobby", "rugby", "social", "sports" ] -}, { - "name" : "pause_presentation", - "tags" : [ "app", "application desktop", "device", "pause", "present", "presentation", "screen", "share", "site", "slides", "web", "website", "window", "www" ] -}, { - "name" : "south_america", - "tags" : [ "continent", "landscape", "place", "region", "south america" ] -}, { - "name" : "sd_storage", - "tags" : [ "camera", "card", "data", "digital", "memory", "sd", "secure", "storage" ] -}, { - "name" : "superscript", - "tags" : [ "2", "doc", "edit", "editing", "editor", "gmail", "novitas", "sheet", "spreadsheet", "style", "superscript", "symbol", "text", "writing", "x" ] -}, { - "name" : "4g_mobiledata", - "tags" : [ "4g", "alphabet", "cellular", "character", "digit", "font", "letter", "mobile", "mobiledata", "network", "number", "phone", "signal", "speed", "symbol", "text", "type", "wifi" ] -}, { - "name" : "pinch", - "tags" : [ "arrow", "arrows", "compress", "direction", "finger", "grasp", "hand", "navigation", "nip", "pinch", "squeeze", "tweak" ] -}, { - "name" : "lock_person", - "tags" : [ ] -}, { - "name" : "grid_3x3", - "tags" : [ "3", "grid", "layout", "line", "space" ] -}, { - "name" : "mark_unread_chat_alt", - "tags" : [ "bubble", "chat", "circle", "comment", "communicate", "mark", "message", "notification", "speech", "unread" ] -}, { - "name" : "web_stories", - "tags" : [ "google", "images", "logo", "stories", "web" ] -}, { - "name" : "safety_check", - "tags" : [ "certified", "check", "clock", "privacy", "private", "protect", "protection", "safety", "schedule", "security", "shield", "time", "verified" ] -}, { - "name" : "filter_frames", - "tags" : [ "boarders", "border", "camera", "center", "edit", "editing", "effect", "filter", "filters", "focus", "frame", "frames", "image", "options", "photo", "photography", "picture" ] -}, { - "name" : "spatial_audio_off", - "tags" : [ "audio", "disabled", "enabled", "music", "note", "off", "offline", "on", "slash", "sound", "spatial" ] -}, { - "name" : "directions_subway", - "tags" : [ "automobile", "car", "cars", "direction", "directions", "maps", "public", "rail", "subway", "train", "transportation", "vehicle" ] -}, { - "name" : "reset_tv", - "tags" : [ "arrow", "device", "hardware", "monitor", "reset", "television", "tv" ] -}, { - "name" : "4k", - "tags" : [ "4000", "4K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "burst_mode", - "tags" : [ "burst", "image", "landscape", "mode", "mountain", "mountains", "multiple", "photo", "photography", "picture" ] -}, { - "name" : "chalet", - "tags" : [ "architecture", "chalet", "cottage", "estate", "home", "house", "maps", "place", "real", "residence", "residential", "stay", "traveling" ] -}, { - "name" : "battery_1_bar", - "tags" : [ "1", "bar", "battery", "cell", "charge", "mobile", "power" ] -}, { - "name" : "elderly_woman", - "tags" : [ "body", "cane", "elderly", "female", "gender", "girl", "human", "lady", "old", "people", "person", "senior", "social", "symbol", "woman", "women" ] -}, { - "name" : "headset_off", - "tags" : [ "accessory", "audio", "chat", "device", "disabled", "ear", "earphone", "enabled", "headphones", "headset", "listen", "mic", "music", "off", "on", "slash", "sound", "talk" ] -}, { - "name" : "swipe_vertical", - "tags" : [ "arrows", "direction", "finger", "hands", "hit", "navigation", "strike", "swing", "swpie", "take", "verticle" ] -}, { - "name" : "crib", - "tags" : [ "babies", "baby", "bassinet", "bed", "child", "children", "cradle", "crib", "infant", "kid", "newborn", "sleeping", "toddler" ] -}, { - "name" : "video_label", - "tags" : [ "label", "screen", "video", "window" ] -}, { - "name" : "fiber_smart_record", - "tags" : [ "circle", "dot", "fiber", "play", "record", "smart", "watch" ] -}, { - "name" : "brightness_auto", - "tags" : [ "A", "auto", "brightness", "control", "display", "level", "mobile", "monitor", "phone", "screen", "sun" ] -}, { - "name" : "margin", - "tags" : [ "design", "layout", "margin", "padding", "size", "square" ] -}, { - "name" : "punch_clock", - "tags" : [ "clock", "date", "punch", "schedule", "time", "timer", "timesheet" ] -}, { - "name" : "compass_calibration", - "tags" : [ "calibration", "compass", "connection", "internet", "location", "maps", "network", "refresh", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "mosque", - "tags" : [ "islam", "islamic", "masjid", "muslim", "religion", "spiritual", "worship" ] -}, { - "name" : "medication_liquid", - "tags" : [ "+", "bottle", "doctor", "drug", "health", "hospital", "liquid", "medications", "medicine", "pharmacy", "spoon", "vessel" ] -}, { - "name" : "camera_roll", - "tags" : [ "camera", "film", "image", "library", "photo", "photography", "roll" ] -}, { - "name" : "pin_end", - "tags" : [ "action", "arrow", "dot", "end", "pin" ] -}, { - "name" : "dialer_sip", - "tags" : [ "alphabet", "call", "cell", "character", "contact", "device", "dialer", "font", "hardware", "initiation", "internet", "letter", "mobile", "over", "phone", "protocol", "routing", "session", "sip", "symbol", "telephone", "text", "type", "voice" ] -}, { - "name" : "oil_barrel", - "tags" : [ "barrel", "droplet", "gas", "gasoline", "nest", "oil", "water" ] -}, { - "name" : "disc_full", - "tags" : [ "!", "alert", "attention", "caution", "cd", "danger", "disc", "error", "exclamation", "full", "important", "mark", "music", "notification", "storage", "symbol", "warning" ] -}, { - "name" : "signal_cellular_connected_no_internet_4_bar", - "tags" : [ "!", "4", "alert", "attention", "bar", "caution", "cell", "cellular", "connected", "danger", "data", "error", "exclamation", "important", "internet", "mark", "mobile", "network", "no", "notification", "phone", "signal", "symbol", "warning", "wifi", "wireless" ] -}, { - "name" : "wind_power", - "tags" : [ "eco", "energy", "nest", "power", "wind", "windy" ] -}, { - "name" : "logo_dev", - "tags" : [ "dev", "dev.to", "logo" ] -}, { - "name" : "sledding", - "tags" : [ "athlete", "athletic", "body", "entertainment", "exercise", "hobby", "human", "people", "person", "sled", "sledding", "sledge", "snow", "social", "sports", "travel", "winter" ] -}, { - "name" : "invert_colors_off", - "tags" : [ "colors", "disabled", "drop", "droplet", "enabled", "hue", "invert", "inverted", "off", "offline", "on", "opacity", "palette", "slash", "tone", "water" ] -}, { - "name" : "wifi_lock", - "tags" : [ "cellular", "connection", "data", "internet", "lock", "locked", "mobile", "network", "password", "privacy", "private", "protection", "safety", "secure", "security", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "noise_aware", - "tags" : [ "audio", "aware", "cancellation", "music", "noise", "note", "sound" ] -}, { - "name" : "face_3", - "tags" : [ "account", "emoji", "eyes", "face", "human", "lock", "log", "login", "logout", "people", "person", "profile", "recognition", "security", "social", "thumbnail", "unlock", "user" ] -}, { - "name" : "car_crash", - "tags" : [ "accident", "automobile", "car", "cars", "collision", "crash", "direction", "maps", "public", "transportation", "vehicle" ] -}, { - "name" : "comments_disabled", - "tags" : [ "bubble", "chat", "comment", "comments", "communicate", "disabled", "enabled", "feedback", "message", "off", "offline", "on", "slash", "speech" ] -}, { - "name" : "data_array", - "tags" : [ "array", "brackets", "code", "coder", "data", "parentheses" ] -}, { - "name" : "do_not_disturb_on_total_silence", - "tags" : [ "busy", "disturb", "do", "mute", "no", "not", "on total", "quiet", "silence" ] -}, { - "name" : "filter_b_and_w", - "tags" : [ "and", "b", "black", "contrast", "edit", "editing", "effect", "filter", "grayscale", "image", "images", "photography", "picture", "pictures", "settings", "w", "white" ] -}, { - "name" : "no_encryption_gmailerrorred", - "tags" : [ "disabled", "enabled", "encryption", "error", "gmail", "lock", "locked", "no", "off", "on", "slash" ] -}, { - "name" : "blur_linear", - "tags" : [ "blur", "dots", "edit", "editing", "effect", "enhance", "filter", "linear" ] -}, { - "name" : "view_cozy", - "tags" : [ "comfy", "cozy", "design", "format", "layout", "view", "web" ] -}, { - "name" : "wifi_calling", - "tags" : [ "call", "calling", "cell", "connect", "connection", "connectivity", "contact", "device", "hardware", "mobile", "phone", "signal", "telephone", "wifi", "wireless" ] -}, { - "name" : "electric_rickshaw", - "tags" : [ "automobile", "car", "cars", "electric", "india", "maps", "rickshaw", "transportation", "truck", "vehicle" ] -}, { - "name" : "rtt", - "tags" : [ "call", "real", "rrt", "text", "time" ] -}, { - "name" : "join_right", - "tags" : [ "circle", "command", "join", "matching", "overlap", "right", "sql", "values" ] -}, { - "name" : "crop_3_2", - "tags" : [ "2", "3", "adjust", "adjustments", "area", "by", "crop", "edit", "editing", "frame", "image", "images", "photo", "photos", "rectangle", "settings", "size", "square" ] -}, { - "name" : "crop_landscape", - "tags" : [ "adjust", "adjustments", "area", "crop", "edit", "editing", "frame", "image", "images", "landscape", "photo", "photos", "settings", "size" ] -}, { - "name" : "nearby_error", - "tags" : [ "!", "alert", "attention", "caution", "danger", "error", "exclamation", "important", "mark", "nearby", "notification", "symbol", "warning" ] -}, { - "name" : "airplanemode_inactive", - "tags" : [ "airplane", "airplanemode", "airport", "disabled", "enabled", "flight", "fly", "inactive", "maps", "mode", "off", "offline", "on", "slash", "transportation", "travel" ] -}, { - "name" : "airline_stops", - "tags" : [ "airline", "arrow", "destination", "direction", "layover", "location", "maps", "place", "stops", "transportation", "travel", "trip" ] -}, { - "name" : "bluetooth_audio", - "tags" : [ "audio", "bluetooth", "connect", "connection", "device", "music", "signal", "sound", "symbol" ] -}, { - "name" : "portable_wifi_off", - "tags" : [ "connection", "data", "disabled", "enabled", "internet", "network", "off", "offline", "on", "portable", "service", "signal", "slash", "wifi", "wireless" ] -}, { - "name" : "turn_right", - "tags" : [ "arrow", "arrows", "direction", "directions", "maps", "navigation", "path", "right", "route", "sign", "traffic", "turn" ] -}, { - "name" : "1x_mobiledata", - "tags" : [ "1x", "alphabet", "cellular", "character", "digit", "font", "letter", "mobile", "mobiledata", "network", "number", "phone", "signal", "speed", "symbol", "text", "type", "wifi" ] -}, { - "name" : "do_not_step", - "tags" : [ "boot", "disabled", "do", "enabled", "feet", "foot", "not", "off", "on", "shoe", "slash", "sneaker", "step", "steps" ] -}, { - "name" : "sensor_occupied", - "tags" : [ "body", "body response", "connection", "fitbit", "human", "network", "people", "person", "scan", "sensors", "signal", "smart body scan sensor", "wireless" ] -}, { - "name" : "directions_railway", - "tags" : [ "automobile", "car", "cars", "direction", "directions", "maps", "public", "railway", "train", "transportation", "vehicle" ] -}, { - "name" : "security_update_warning", - "tags" : [ "!", "Android", "OS", "alert", "attention", "caution", "danger", "device", "download", "error", "exclamation", "hardware", "iOS", "important", "mark", "mobile", "notification", "phone", "security", "symbol", "tablet", "update", "warning" ] -}, { - "name" : "pentagon", - "tags" : [ "five sides", "pentagon", "shape" ] -}, { - "name" : "wrap_text", - "tags" : [ "arrow writing", "doc", "edit", "editing", "editor", "sheet", "spreadsheet", "text", "type", "wrap", "write", "writing" ] -}, { - "name" : "no_meeting_room", - "tags" : [ "building", "disabled", "door", "doorway", "enabled", "entrance", "home", "house", "interior", "meeting", "no", "off", "office", "on", "open", "places", "room", "slash" ] -}, { - "name" : "sd_card_alert", - "tags" : [ "!", "alert", "attention", "camera", "card", "caution", "danger", "digital", "error", "exclamation", "important", "mark", "memory", "notification", "photos", "sd", "secure", "storage", "symbol", "warning" ] -}, { - "name" : "deselect", - "tags" : [ "all", "disabled", "enabled", "off", "on", "selection", "slash", "square", "tool" ] -}, { - "name" : "switch_camera", - "tags" : [ "arrow", "arrows", "camera", "photo", "photography", "picture", "switch" ] -}, { - "name" : "text_rotate_up", - "tags" : [ "A", "alphabet", "arrow", "character", "field", "font", "letter", "move", "rotate", "symbol", "text", "type", "up" ] -}, { - "name" : "sync_lock", - "tags" : [ "around", "arrow", "arrows", "lock", "locked", "password", "privacy", "private", "protection", "renew", "rotate", "safety", "secure", "security", "sync", "turn" ] -}, { - "name" : "switch_video", - "tags" : [ "arrow", "arrows", "camera", "photography", "switch", "video", "videos" ] -}, { - "name" : "border_clear", - "tags" : [ "border", "clear", "doc", "edit", "editing", "editor", "sheet", "spreadsheet", "stroke", "text", "type", "writing" ] -}, { - "name" : "repeat_one_on", - "tags" : [ "arrow", "arrows", "control", "controls", "digit", "media", "music", "number", "on", "one", "repeat", "symbol", "video" ] -}, { - "name" : "no_meals", - "tags" : [ "dining", "disabled", "eat", "enabled", "food", "fork", "knife", "meal", "meals", "no", "off", "on", "restaurant", "slash", "spoon", "utensils" ] -}, { - "name" : "align_vertical_top", - "tags" : [ "align", "alignment", "format", "layout", "lines", "paragraph", "rule", "rules", "style", "text", "top", "vertical" ] -}, { - "name" : "subscript", - "tags" : [ "2", "doc", "edit", "editing", "editor", "gmail", "novitas", "sheet", "spreadsheet", "style", "subscript", "symbol", "text", "writing", "x" ] -}, { - "name" : "font_download_off", - "tags" : [ "alphabet", "character", "disabled", "download", "enabled", "font", "letter", "off", "on", "slash", "square", "symbol", "text", "type" ] -}, { - "name" : "scoreboard", - "tags" : [ "board", "points", "score", "scoreboard", "sports" ] -}, { - "name" : "swipe_right_alt", - "tags" : [ "accept", "alt", "arrows", "direction", "finger", "hands", "hit", "navigation", "right", "strike", "swing", "swpie", "take" ] -}, { - "name" : "align_vertical_center", - "tags" : [ "align", "alignment", "center", "format", "layout", "lines", "paragraph", "rule", "rules", "style", "text", "vertical" ] -}, { - "name" : "electric_meter", - "tags" : [ "bolt", "electric", "energy", "fast", "lightning", "measure", "meter", "nest", "thunderbolt", "usage", "voltage", "volts" ] -}, { - "name" : "contact_emergency", - "tags" : [ "account", "avatar", "call", "cell", "contacts", "face", "human", "info", "information", "mobile", "people", "person", "phone", "profile", "user" ] -}, { - "name" : "signal_cellular_connected_no_internet_0_bar", - "tags" : [ "!", "0", "alert", "attention", "bar", "caution", "cell", "cellular", "connected", "danger", "data", "error", "exclamation", "important", "internet", "mark", "mobile", "network", "no", "notification", "phone", "signal", "symbol", "warning", "wifi", "wireless" ] -}, { - "name" : "sim_card_alert", - "tags" : [ "!", "alert", "attention", "camera", "card", "caution", "danger", "digital", "error", "exclamation", "important", "mark", "memory", "notification", "photos", "sd", "secure", "storage", "symbol", "warning" ] -}, { - "name" : "battery_2_bar", - "tags" : [ "2", "bar", "battery", "cell", "charge", "mobile", "power" ] -}, { - "name" : "text_rotation_angleup", - "tags" : [ "A", "alphabet", "angleup", "arrow", "character", "field", "font", "letter", "move", "rotate", "symbol", "text", "type" ] -}, { - "name" : "text_rotation_down", - "tags" : [ "A", "alphabet", "arrow", "character", "dow", "field", "font", "letter", "move", "rotate", "symbol", "text", "type" ] -}, { - "name" : "railway_alert", - "tags" : [ "!", "alert", "attention", "automobile", "bike", "car", "cars", "caution", "danger", "direction", "error", "exclamation", "important", "maps", "mark", "notification", "public", "railway", "scooter", "subway", "symbol", "train", "transportation", "vehicle", "vespa", "warning" ] -}, { - "name" : "escalator", - "tags" : [ "down", "escalator", "staircase", "up" ] -}, { - "name" : "electric_moped", - "tags" : [ "automobile", "bike", "car", "cars", "electric", "maps", "moped", "scooter", "transportation", "travel", "vehicle", "vespa" ] -}, { - "name" : "closed_caption_disabled", - "tags" : [ "accessible", "alphabet", "caption", "cc", "character", "closed", "decoder", "disabled", "enabled", "font", "language", "letter", "media", "movies", "off", "on", "slash", "subtitle", "subtitles", "symbol", "text", "tv", "type" ] -}, { - "name" : "filter_7", - "tags" : [ "7", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "settings", "stack", "symbol" ] -}, { - "name" : "heat_pump", - "tags" : [ "air conditioner", "cool", "energy", "furnance", "heat", "nest", "pump", "usage" ] -}, { - "name" : "dry", - "tags" : [ "air", "bathroom", "dry", "dryer", "fingers", "gesture", "hand", "wc" ] -}, { - "name" : "fork_right", - "tags" : [ "arrow", "arrows", "direction", "directions", "fork", "maps", "navigation", "path", "right", "route", "sign", "traffic" ] -}, { - "name" : "text_rotation_angledown", - "tags" : [ "A", "alphabet", "angledown", "arrow", "character", "field", "font", "letter", "move", "rotate", "symbol", "text", "type" ] -}, { - "name" : "do_not_disturb_off", - "tags" : [ "cancel", "close", "denied", "deny", "disabled", "disturb", "do", "enabled", "off", "on", "remove", "silence", "slash", "stop" ] -}, { - "name" : "screen_lock_portrait", - "tags" : [ "Android", "OS", "device", "hardware", "iOS", "lock", "mobile", "phone", "portrait", "rotate", "screen", "tablet" ] -}, { - "name" : "send_time_extension", - "tags" : [ "deliver", "dispatch", "envelop", "extension", "mail", "message", "schedule", "send", "time" ] -}, { - "name" : "keyboard_command_key", - "tags" : [ "button", "command key", "control", "keyboard" ] -}, { - "name" : "remove_from_queue", - "tags" : [ "desktop", "device", "display", "from", "hardware", "monitor", "queue", "remove", "screen", "steam" ] -}, { - "name" : "filter_4", - "tags" : [ "4", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "settings", "stack", "symbol" ] -}, { - "name" : "filter_9_plus", - "tags" : [ "+", "9", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "plus", "settings", "stack", "symbol" ] -}, { - "name" : "exposure_plus_2", - "tags" : [ "2", "add", "brightness", "contrast", "digit", "edit", "editing", "effect", "exposure", "image", "number", "photo", "photography", "plus", "settings", "symbol" ] -}, { - "name" : "surround_sound", - "tags" : [ "circle", "signal", "sound", "speaker", "surround", "system", "volumn", "wireless" ] -}, { - "name" : "airline_seat_individual_suite", - "tags" : [ "airline", "body", "business", "class", "first", "human", "individual", "people", "person", "rest", "seat", "sleep", "suite", "travel" ] -}, { - "name" : "home_max", - "tags" : [ "device", "gadget", "hardware", "home", "internet", "iot", "max", "nest", "smart", "things" ] -}, { - "name" : "phone_paused", - "tags" : [ "call", "cell", "contact", "device", "hardware", "mobile", "pause", "paused", "phone", "telephone" ] -}, { - "name" : "local_play", - "tags" : [ ] -}, { - "name" : "stroller", - "tags" : [ "baby", "care", "carriage", "child", "children", "infant", "kid", "newborn", "stroller", "toddler", "young" ] -}, { - "name" : "wifi_password", - "tags" : [ "(scan)", "[cellular", "connection", "data", "internet", "lock", "mobile]", "network", "password", "secure", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "browse_gallery", - "tags" : [ "clock", "collection", "gallery", "library", "stack", "watch" ] -}, { - "name" : "system_security_update", - "tags" : [ "Android", "OS", "arrow", "cell", "device", "down", "hardware", "iOS", "mobile", "phone", "security", "system", "tablet", "update" ] -}, { - "name" : "person_2", - "tags" : [ "account", "face", "human", "people", "person", "profile", "user" ] -}, { - "name" : "screenshot_monitor", - "tags" : [ "Android", "OS", "chrome", "desktop", "device", "display", "hardware", "iOS", "mac", "monitor", "screen", "screengrab", "screenshot", "web", "window" ] -}, { - "name" : "wb_iridescent", - "tags" : [ "balance", "bright", "edit", "editing", "iridescent", "light", "lighting", "setting", "settings", "white", "wp" ] -}, { - "name" : "grid_off", - "tags" : [ "collage", "disabled", "enabled", "grid", "image", "layout", "off", "on", "slash", "view" ] -}, { - "name" : "system_security_update_warning", - "tags" : [ "!", "Android", "OS", "alert", "attention", "caution", "cell", "danger", "device", "error", "exclamation", "hardware", "iOS", "important", "mark", "mobile", "notification", "phone", "security", "symbol", "system", "tablet", "update", "warning" ] -}, { - "name" : "play_disabled", - "tags" : [ "control", "controls", "disabled", "enabled", "media", "music", "off", "on", "play", "slash", "video" ] -}, { - "name" : "php", - "tags" : [ "alphabet", "brackets", "character", "code", "css", "develop", "developer", "engineer", "engineering", "font", "html", "letter", "php", "platform", "symbol", "text", "type" ] -}, { - "name" : "phishing", - "tags" : [ "fish", "fishing", "fraud", "hook", "phishing", "scam" ] -}, { - "name" : "border_style", - "tags" : [ "border", "color", "doc", "edit", "editing", "editor", "sheet", "spreadsheet", "stroke", "style", "text", "type", "writing" ] -}, { - "name" : "motion_photos_paused", - "tags" : [ "animation", "circle", "motion", "pause", "paused", "photos", "video" ] -}, { - "name" : "headphones_battery", - "tags" : [ "accessory", "audio", "battery", "charging", "device", "ear", "earphone", "headphones", "headset", "listen", "music", "sound" ] -}, { - "name" : "monochrome_photos", - "tags" : [ "black", "camera", "image", "monochrome", "photo", "photography", "photos", "picture", "white" ] -}, { - "name" : "web_asset_off", - "tags" : [ "asset", "browser", "disabled", "enabled", "internet", "off", "on", "page", "screen", "slash", "web", "webpage", "website", "windows", "www" ] -}, { - "name" : "wifi_tethering_off", - "tags" : [ "cell", "cellular", "connection", "data", "disabled", "enabled", "internet", "mobile", "network", "off", "offline", "on", "phone", "scan", "service", "signal", "slash", "speed", "tethering", "wifi", "wireless" ] -}, { - "name" : "text_decrease", - "tags" : [ "-", "alphabet", "character", "decrease", "font", "letter", "minus", "remove", "resize", "subtract", "symbol", "text", "type" ] -}, { - "name" : "view_comfy_alt", - "tags" : [ "alt", "comfy", "cozy", "design", "format", "layout", "view", "web" ] -}, { - "name" : "photo_camera_back", - "tags" : [ "back", "camera", "image", "landscape", "mountain", "mountains", "photo", "photography", "picture", "rear" ] -}, { - "name" : "folder_off", - "tags" : [ "data", "disabled", "doc", "document", "drive", "enabled", "file", "folder", "folders", "off", "on", "online", "sheet", "slash", "slide", "storage" ] -}, { - "name" : "gas_meter", - "tags" : [ "droplet", "energy", "gas", "measure", "meter", "nest", "usage", "water" ] -}, { - "name" : "edgesensor_high", - "tags" : [ "Android", "OS", "cell", "device", "edge", "hardware", "high", "iOS", "mobile", "move", "phone", "sensitivity", "sensor", "tablet", "vibrate" ] -}, { - "name" : "filter_5", - "tags" : [ "5", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "settings", "stack", "symbol" ] -}, { - "name" : "stay_current_landscape", - "tags" : [ "Android", "OS", "current", "device", "hardware", "iOS", "landscape", "mobile", "phone", "stay", "tablet" ] -}, { - "name" : "sip", - "tags" : [ "alphabet", "call", "character", "dialer", "font", "initiation", "internet", "letter", "over", "phone", "protocol", "routing", "session", "sip", "symbol", "text", "type", "voice" ] -}, { - "name" : "power_input", - "tags" : [ "input", "lines", "power", "supply" ] -}, { - "name" : "smart_screen", - "tags" : [ "Android", "OS", "airplay", "cast", "cell", "connect", "device", "hardware", "iOS", "mobile", "phone", "screen", "screencast", "smart", "stream", "tablet", "video" ] -}, { - "name" : "mail_lock", - "tags" : [ "email", "envelop", "letter", "lock", "locked", "mail", "message", "password", "privacy", "private", "protection", "safety", "secure", "security", "send" ] -}, { - "name" : "dataset", - "tags" : [ ] -}, { - "name" : "nat", - "tags" : [ "communication", "nat" ] -}, { - "name" : "do_disturb_off", - "tags" : [ "cancel", "close", "denied", "deny", "disabled", "disturb", "do", "enabled", "off", "on", "remove", "silence", "slash", "stop" ] -}, { - "name" : "no_drinks", - "tags" : [ "alcohol", "beverage", "bottle", "cocktail", "drink", "drinks", "food", "liquor", "no", "wine" ] -}, { - "name" : "bike_scooter", - "tags" : [ "automobile", "bike", "car", "cars", "maps", "scooter", "transportation", "vehicle", "vespa" ] -}, { - "name" : "dock", - "tags" : [ "Android", "OS", "cell", "charging", "connector", "device", "dock", "hardware", "iOS", "mobile", "phone", "power", "station", "tablet" ] -}, { - "name" : "face_2", - "tags" : [ "account", "emoji", "eyes", "face", "human", "lock", "log", "login", "logout", "people", "person", "profile", "recognition", "security", "social", "thumbnail", "unlock", "user" ] -}, { - "name" : "face_retouching_off", - "tags" : [ "disabled", "edit", "editing", "effect", "emoji", "emotion", "enabled", "face", "faces", "image", "natural", "off", "on", "photo", "photography", "retouch", "retouching", "settings", "slash", "tag" ] -}, { - "name" : "auto_fix_off", - "tags" : [ "ai", "artificial", "auto", "automatic", "automation", "custom", "disabled", "edit", "enabled", "erase", "fix", "genai", "intelligence", "magic", "modify", "off", "on", "slash", "smart", "spark", "sparkle", "star", "wand" ] -}, { - "name" : "airline_seat_flat", - "tags" : [ "airline", "body", "business", "class", "first", "flat", "human", "people", "person", "rest", "seat", "sleep", "travel" ] -}, { - "name" : "phone_locked", - "tags" : [ "call", "cell", "contact", "device", "hardware", "lock", "locked", "mobile", "password", "phone", "privacy", "private", "protection", "safety", "secure", "security", "telephone" ] -}, { - "name" : "network_locked", - "tags" : [ "alert", "available", "cellular", "connection", "data", "error", "internet", "lock", "locked", "mobile", "network", "not", "privacy", "private", "protection", "restricted", "safety", "secure", "security", "service", "signal", "warning", "wifi", "wireless" ] -}, { - "name" : "padding", - "tags" : [ "design", "layout", "margin", "padding", "size", "square" ] -}, { - "name" : "browser_not_supported", - "tags" : [ "browser", "disabled", "enabled", "internet", "not", "off", "on", "page", "screen", "site", "slash", "supported", "web", "website", "www" ] -}, { - "name" : "border_outer", - "tags" : [ "border", "doc", "edit", "editing", "editor", "outer", "sheet", "spreadsheet", "stroke", "text", "type", "writing" ] -}, { - "name" : "exposure_neg_1", - "tags" : [ "1", "brightness", "contrast", "digit", "edit", "editing", "effect", "exposure", "image", "neg", "negative", "number", "photo", "photography", "settings", "symbol" ] -}, { - "name" : "view_compact_alt", - "tags" : [ "alt", "compact", "design", "format", "layout dense", "view", "web" ] -}, { - "name" : "pest_control_rodent", - "tags" : [ "control", "exterminator", "mice", "pest", "rodent" ] -}, { - "name" : "swipe_down_alt", - "tags" : [ "alt", "arrows", "direction", "disable", "down", "enable", "finger", "hands", "hit", "navigation", "strike", "swing", "swpie", "take" ] -}, { - "name" : "airlines", - "tags" : [ "airlines", "airplane", "airport", "flight", "plane", "transportation", "travel", "trip" ] -}, { - "name" : "turn_left", - "tags" : [ "arrow", "arrows", "direction", "directions", "left", "maps", "navigation", "path", "route", "sign", "traffic", "turn" ] -}, { - "name" : "sd", - "tags" : [ "alphabet", "camera", "card", "character", "data", "device", "digital", "drive", "flash", "font", "image", "letter", "memory", "photo", "sd", "secure", "symbol", "text", "type" ] -}, { - "name" : "near_me_disabled", - "tags" : [ "destination", "direction", "disabled", "enabled", "location", "maps", "me", "navigation", "near", "off", "on", "pin", "place", "point", "slash" ] -}, { - "name" : "face_4", - "tags" : [ "account", "emoji", "eyes", "face", "human", "lock", "log", "login", "logout", "people", "person", "profile", "recognition", "security", "social", "thumbnail", "unlock", "user" ] -}, { - "name" : "stay_primary_landscape", - "tags" : [ "Android", "OS", "current", "device", "hardware", "iOS", "landscape", "mobile", "phone", "primary", "stay", "tablet" ] -}, { - "name" : "4g_plus_mobiledata", - "tags" : [ "4g", "alphabet", "cellular", "character", "digit", "font", "letter", "mobile", "mobiledata", "network", "number", "phone", "plus", "signal", "speed", "symbol", "text", "type", "wifi" ] -}, { - "name" : "snowmobile", - "tags" : [ "automobile", "car", "direction", "skimobile", "snow", "snowmobile", "social", "sports", "transportation", "travel", "vehicle", "winter" ] -}, { - "name" : "sign_language", - "tags" : [ "communication", "deaf", "fingers", "gesture", "hand", "language", "sign" ] -}, { - "name" : "network_ping", - "tags" : [ "alert", "available", "cellular", "connection", "data", "internet", "ip", "mobile", "network", "ping", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "signal_cellular_off", - "tags" : [ "cell", "cellular", "data", "disabled", "enabled", "internet", "mobile", "network", "off", "offline", "on", "phone", "signal", "slash", "wifi", "wireless" ] -}, { - "name" : "signal_cellular_nodata", - "tags" : [ "cell", "cellular", "data", "internet", "mobile", "network", "no", "nodata", "offline", "phone", "quit", "signal", "wifi", "wireless", "x" ] -}, { - "name" : "no_sim", - "tags" : [ "camera", "card", "device", "eject", "insert", "memory", "no", "phone", "sim", "storage" ] -}, { - "name" : "signal_wifi_4_bar_lock", - "tags" : [ "4", "bar", "cell", "cellular", "data", "internet", "lock", "locked", "mobile", "network", "password", "phone", "privacy", "private", "protection", "safety", "secure", "security", "signal", "wifi", "wireless" ] -}, { - "name" : "missed_video_call", - "tags" : [ "arrow", "call", "camera", "film", "filming", "hardware", "image", "missed", "motion", "picture", "record", "video", "videography" ] -}, { - "name" : "lte_mobiledata", - "tags" : [ "alphabet", "character", "data", "font", "internet", "letter", "lte", "mobile", "network", "speed", "symbol", "text", "type", "wifi", "wireless" ] -}, { - "name" : "earbuds_battery", - "tags" : [ "accessory", "audio", "battery", "charging", "earbuds", "earphone", "headphone", "listen", "music", "sound" ] -}, { - "name" : "panorama_photosphere", - "tags" : [ "angle", "horizontal", "image", "panorama", "photo", "photography", "photosphere", "picture", "wide" ] -}, { - "name" : "no_crash", - "tags" : [ "accident", "auto", "automobile", "car", "cars", "check", "collision", "confirm", "correct", "crash", "direction", "done", "enter", "maps", "mark", "no", "ok", "okay", "select", "tick", "transportation", "vehicle", "yes" ] -}, { - "name" : "add_alarm", - "tags" : [ ] -}, { - "name" : "directions_transit_filled", - "tags" : [ "automobile", "car", "cars", "direction", "directions", "filled", "maps", "public", "rail", "subway", "train", "transit", "transportation", "vehicle" ] -}, { - "name" : "u_turn_left", - "tags" : [ "arrow", "arrows", "direction", "directions", "left", "maps", "navigation", "path", "route", "sign", "traffic", "u-turn" ] -}, { - "name" : "line_axis", - "tags" : [ "axis", "dash", "horizontal", "line", "stroke", "vertical" ] -}, { - "name" : "density_large", - "tags" : [ "density", "horizontal", "large", "lines", "rule", "rules" ] -}, { - "name" : "location_disabled", - "tags" : [ "destination", "direction", "disabled", "enabled", "location", "maps", "off", "on", "pin", "place", "pointer", "slash", "stop", "tracking" ] -}, { - "name" : "bluetooth_drive", - "tags" : [ "automobile", "bluetooth", "car", "cars", "cast", "connect", "connection", "device", "drive", "maps", "paring", "streaming", "symbol", "transportation", "travel", "vehicle", "wireless" ] -}, { - "name" : "30fps", - "tags" : [ "30fps", "alphabet", "camera", "character", "digit", "font", "fps", "frames", "letter", "number", "symbol", "text", "type", "video" ] -}, { - "name" : "no_luggage", - "tags" : [ "bag", "baggage", "carry", "disabled", "enabled", "luggage", "no", "off", "on", "slash", "suitcase", "travel" ] -}, { - "name" : "leak_remove", - "tags" : [ "connection", "data", "disabled", "enabled", "leak", "link", "network", "off", "offline", "on", "remove", "service", "signals", "slash", "synce", "wireless" ] -}, { - "name" : "filter_8", - "tags" : [ "8", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "settings", "stack", "symbol" ] -}, { - "name" : "mobile_off", - "tags" : [ "Android", "OS", "cell", "device", "disabled", "enabled", "hardware", "iOS", "mobile", "off", "on", "phone", "silence", "slash", "tablet" ] -}, { - "name" : "key_off", - "tags" : [ "disabled", "enabled", "key", "lock", "off", "offline", "on", "password", "slash", "unlock" ] -}, { - "name" : "signal_cellular_null", - "tags" : [ "cell", "cellular", "data", "internet", "mobile", "network", "null", "phone", "signal", "wifi", "wireless" ] -}, { - "name" : "phonelink_off", - "tags" : [ "Android", "OS", "chrome", "computer", "connect", "desktop", "device", "disabled", "enabled", "hardware", "iOS", "link", "mac", "mobile", "off", "on", "phone", "phonelink", "slash", "sync", "tablet", "web", "windows" ] -}, { - "name" : "filter_9", - "tags" : [ "9", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "settings", "stack", "symbol" ] -}, { - "name" : "home_mini", - "tags" : [ "Internet", "device", "gadget", "hardware", "home", "iot", "mini", "nest", "smart", "things" ] -}, { - "name" : "on_device_training", - "tags" : [ "arrow", "bulb", "call", "cell", "contact", "device", "hardware", "idea", "inprogress", "light", "load", "loading", "mobile", "model", "phone", "refresh", "renew", "restore", "reverse", "rotate", "telephone", "training" ] -}, { - "name" : "egg_alt", - "tags" : [ "breakfast", "brunch", "egg", "food" ] -}, { - "name" : "media_bluetooth_on", - "tags" : [ "bluetooth", "connect", "connection", "connectivity", "device", "disabled", "enabled", "media", "music", "note", "off", "on", "online", "paring", "signal", "slash", "symbol", "wireless" ] -}, { - "name" : "10k", - "tags" : [ "10000", "10K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "video_stable", - "tags" : [ "film", "filming", "recording", "setting", "stability", "stable", "taping", "video" ] -}, { - "name" : "add_home", - "tags" : [ ] -}, { - "name" : "no_transfer", - "tags" : [ "automobile", "bus", "car", "cars", "direction", "disabled", "enabled", "maps", "no", "off", "on", "public", "slash", "transfer", "transportation", "vehicle" ] -}, { - "name" : "timer_10", - "tags" : [ "10", "digits", "duration", "number", "numbers", "seconds", "time", "timer" ] -}, { - "name" : "directions_subway_filled", - "tags" : [ "automobile", "car", "cars", "direction", "directions", "filled", "maps", "public", "rail", "subway", "train", "transportation", "vehicle" ] -}, { - "name" : "wb_shade", - "tags" : [ "balance", "house", "light", "lighting", "shade", "wb", "white" ] -}, { - "name" : "swipe_left_alt", - "tags" : [ "alt", "arrow", "arrows", "finger", "hand", "hit", "left", "navigation", "reject", "strike", "swing", "swipe", "take" ] -}, { - "name" : "filter_6", - "tags" : [ "6", "digit", "edit", "editing", "effect", "filter", "image", "images", "multiple", "number", "photography", "picture", "pictures", "settings", "stack", "symbol" ] -}, { - "name" : "cyclone", - "tags" : [ "crisis", "disaster", "natural", "rain", "storm", "weather", "wind", "winds" ] -}, { - "name" : "network_wifi_1_bar", - "tags" : [ ] -}, { - "name" : "directions_railway_filled", - "tags" : [ "automobile", "car", "cars", "direction", "directions", "filled", "maps", "public", "railway", "train", "transportation", "vehicle" ] -}, { - "name" : "wifi_find", - "tags" : [ "(scan)", "[cellular", "connection", "data", "detect", "discover", "find", "internet", "look", "magnifying glass", "mobile]", "network", "notice", "search", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "blur_off", - "tags" : [ "blur", "disabled", "dots", "edit", "editing", "effect", "enabled", "enhance", "off", "on", "slash" ] -}, { - "name" : "motion_photos_off", - "tags" : [ "animation", "circle", "disabled", "enabled", "motion", "off", "on", "photos", "slash", "video" ] -}, { - "name" : "lyrics", - "tags" : [ "audio", "bubble", "chat", "comment", "communicate", "feedback", "key", "lyrics", "message", "music", "note", "song", "sound", "speech", "track" ] -}, { - "name" : "raw_on", - "tags" : [ "alphabet", "character", "disabled", "enabled", "font", "image", "letter", "off", "on", "original", "photo", "photography", "raw", "slash", "symbol", "text", "type" ] -}, { - "name" : "flight_class", - "tags" : [ "airplane", "business", "class", "first", "flight", "plane", "seat", "transportation", "travel", "trip", "window" ] -}, { - "name" : "insert_page_break", - "tags" : [ "break", "doc", "document", "file", "page", "paper" ] -}, { - "name" : "rsvp", - "tags" : [ "alphabet", "character", "font", "invitation", "invite", "letter", "plaît", "respond", "rsvp", "répondez", "sil", "symbol", "text", "type", "vous" ] -}, { - "name" : "tire_repair", - "tags" : [ "auto", "automobile", "car", "cars", "gauge", "mechanic", "pressure", "repair", "tire", "vehicle" ] -}, { - "name" : "swipe_up_alt", - "tags" : [ "alt", "arrows", "direction", "disable", "enable", "finger", "hands", "hit", "navigation", "strike", "swing", "swpie", "take", "up" ] -}, { - "name" : "3g_mobiledata", - "tags" : [ "3g", "alphabet", "cellular", "character", "digit", "font", "letter", "mobile", "mobiledata", "network", "number", "phone", "signal", "speed", "symbol", "text", "type", "wifi" ] -}, { - "name" : "tv_off", - "tags" : [ "Android", "OS", "chrome", "desktop", "device", "disabled", "enabled", "hardware", "iOS", "mac", "monitor", "off", "on", "slash", "television", "tv", "web", "window" ] -}, { - "name" : "hdr_on", - "tags" : [ "add", "alphabet", "character", "dynamic", "enhance", "font", "hdr", "high", "letter", "on", "plus", "range", "select", "symbol", "text", "type" ] -}, { - "name" : "add_home_work", - "tags" : [ ] -}, { - "name" : "motion_photos_pause", - "tags" : [ "animation", "circle", "motion", "pause", "paused", "photos", "video" ] -}, { - "name" : "edgesensor_low", - "tags" : [ "Android", "cell", "device", "edge", "hardware", "iOS", "low", "mobile", "move", "phone", "sensitivity", "sensor", "tablet", "vibrate" ] -}, { - "name" : "grid_goldenratio", - "tags" : [ "golden", "goldenratio", "grid", "layout", "lines", "ratio", "space" ] -}, { - "name" : "network_wifi_3_bar", - "tags" : [ ] -}, { - "name" : "temple_buddhist", - "tags" : [ "buddha", "buddhism", "buddhist", "monastery", "religion", "spiritual", "temple", "worship" ] -}, { - "name" : "airline_seat_flat_angled", - "tags" : [ "airline", "angled", "body", "business", "class", "first", "flat", "human", "people", "person", "rest", "seat", "sleep", "travel" ] -}, { - "name" : "fort", - "tags" : [ "castle", "fort", "fortress", "mansion", "palace" ] -}, { - "name" : "spatial_tracking", - "tags" : [ "audio", "disabled", "enabled", "music", "note", "off", "offline", "on", "slash", "sound", "spatial", "tracking" ] -}, { - "name" : "screen_lock_rotation", - "tags" : [ "Android", "OS", "arrow", "device", "hardware", "iOS", "lock", "mobile", "phone", "rotate", "rotation", "screen", "tablet", "turn" ] -}, { - "name" : "fiber_pin", - "tags" : [ "alphabet", "character", "fiber", "font", "letter", "network", "pin", "symbol", "text", "type" ] -}, { - "name" : "phone_bluetooth_speaker", - "tags" : [ "bluetooth", "call", "cell", "connect", "connection", "connectivity", "contact", "device", "hardware", "mobile", "phone", "signal", "speaker", "symbol", "telephone", "wireless" ] -}, { - "name" : "vignette", - "tags" : [ "border", "edit", "editing", "filter", "gradient", "image", "photo", "photography", "setting", "vignette" ] -}, { - "name" : "panorama_horizontal", - "tags" : [ "angle", "horizontal", "image", "panorama", "photo", "photography", "picture", "wide" ] -}, { - "name" : "propane_tank", - "tags" : [ "bbq", "gas", "grill", "nest", "propane", "tank" ] -}, { - "name" : "kebab_dining", - "tags" : [ "dining", "dinner", "food", "kebab", "meal", "meat", "skewer" ] -}, { - "name" : "developer_board_off", - "tags" : [ "board", "chip", "computer", "developer", "development", "disabled", "enabled", "hardware", "microchip", "off", "on", "processor", "slash" ] -}, { - "name" : "adf_scanner", - "tags" : [ "adf", "document", "feeder", "machine", "office", "scan", "scanner" ] -}, { - "name" : "no_cell", - "tags" : [ "Android", "OS", "cell", "device", "disabled", "enabled", "hardware", "iOS", "mobile", "no", "off", "on", "phone", "slash", "tablet" ] -}, { - "name" : "dirty_lens", - "tags" : [ "camera", "dirty", "lens", "photo", "photography", "picture", "splat" ] -}, { - "name" : "usb_off", - "tags" : [ "cable", "connection", "device", "off", "usb", "wire" ] -}, { - "name" : "image_aspect_ratio", - "tags" : [ "aspect", "image", "photo", "photography", "picture", "ratio", "rectangle", "square" ] -}, { - "name" : "30fps_select", - "tags" : [ "30", "camera", "digits", "fps", "frame", "frequency", "image", "numbers", "per", "rate", "second", "seconds", "select", "video" ] -}, { - "name" : "60fps", - "tags" : [ "60fps", "camera", "digit", "fps", "frames", "number", "symbol", "video" ] -}, { - "name" : "screen_lock_landscape", - "tags" : [ "Android", "OS", "device", "hardware", "iOS", "landscape", "lock", "mobile", "phone", "rotate", "screen", "tablet" ] -}, { - "name" : "lte_plus_mobiledata", - "tags" : [ "+", "alphabet", "character", "data", "font", "internet", "letter", "lte", "mobile", "network", "plus", "speed", "symbol", "text", "type", "wifi", "wireless" ] -}, { - "name" : "piano_off", - "tags" : [ "disabled", "enabled", "instrument", "keyboard", "keys", "music", "musical", "off", "on", "piano", "slash", "social" ] -}, { - "name" : "unfold_more_double", - "tags" : [ "arrow", "arrows", "chevron", "collapse", "direction", "double", "down", "expand", "expandable", "list", "more", "navigation", "unfold" ] -}, { - "name" : "deblur", - "tags" : [ "adjust", "deblur", "edit", "editing", "enhance", "face", "image", "lines", "photo", "photography", "sharpen" ] -}, { - "name" : "person_4", - "tags" : [ "account", "face", "human", "people", "person", "profile", "user" ] -}, { - "name" : "spatial_audio", - "tags" : [ "audio", "music", "note", "sound", "spatial" ] -}, { - "name" : "camera_rear", - "tags" : [ "camera", "front", "lens", "mobile", "phone", "photo", "photography", "picture", "portrait", "rear", "selfie" ] -}, { - "name" : "timer_10_select", - "tags" : [ "10", "alphabet", "camera", "character", "digit", "font", "letter", "number", "seconds", "select", "symbol", "text", "timer", "type" ] -}, { - "name" : "face_5", - "tags" : [ "account", "emoji", "eyes", "face", "human", "lock", "log", "login", "logout", "people", "person", "profile", "recognition", "security", "social", "thumbnail", "unlock", "user" ] -}, { - "name" : "minor_crash", - "tags" : [ "accident", "auto", "automobile", "car", "cars", "collision", "directions", "maps", "public", "transportation", "vehicle" ] -}, { - "name" : "sos", - "tags" : [ "font", "help", "letters", "save", "sos", "text", "type" ] -}, { - "name" : "videogame_asset_off", - "tags" : [ "asset", "console", "controller", "device", "disabled", "enabled", "game", "gamepad", "gaming", "off", "on", "playstation", "slash", "video", "videogame" ] -}, { - "name" : "flood", - "tags" : [ "crisis", "disaster", "natural", "rain", "storm", "weather" ] -}, { - "name" : "60fps_select", - "tags" : [ "60", "camera", "digits", "fps", "frame", "frequency", "numbers", "per", "rate", "second", "seconds", "select", "video" ] -}, { - "name" : "timer_3", - "tags" : [ "3", "digits", "duration", "number", "numbers", "seconds", "time", "timer" ] -}, { - "name" : "vpn_key_off", - "tags" : [ "code", "disabled", "enabled", "key", "lock", "network", "off", "offline", "on", "passcode", "password", "slash", "unlock", "vpn" ] -}, { - "name" : "directions_off", - "tags" : [ "arrow", "directions", "disabled", "enabled", "maps", "off", "on", "right", "route", "sign", "slash", "traffic" ] -}, { - "name" : "emergency_share", - "tags" : [ "alert", "attention", "caution", "danger", "emergency", "important", "notification", "share", "warning" ] -}, { - "name" : "panorama_wide_angle_select", - "tags" : [ "angle", "image", "panorama", "photo", "photography", "picture", "select", "wide" ] -}, { - "name" : "airline_seat_legroom_normal", - "tags" : [ "airline", "body", "feet", "human", "leg", "legroom", "normal", "people", "person", "seat", "sitting", "space", "travel" ] -}, { - "name" : "fiber_dvr", - "tags" : [ "alphabet", "character", "digital", "dvr", "electronics", "fiber", "font", "letter", "network", "record", "recorder", "symbol", "text", "tv", "type", "video" ] -}, { - "name" : "person_3", - "tags" : [ "account", "face", "human", "people", "person", "profile", "user" ] -}, { - "name" : "scuba_diving", - "tags" : [ "diving", "entertainment", "exercise", "hobby", "scuba", "social", "swim", "swimming" ] -}, { - "name" : "signal_cellular_no_sim", - "tags" : [ "camera", "card", "cellular", "chip", "device", "disabled", "enabled", "memory", "no", "off", "offline", "on", "phone", "signal", "sim", "slash", "storage" ] -}, { - "name" : "24mp", - "tags" : [ "24", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "exposure_neg_2", - "tags" : [ "2", "brightness", "contrast", "digit", "edit", "editing", "effect", "exposure", "image", "neg", "negative", "number", "photo", "photography", "settings", "symbol" ] -}, { - "name" : "network_wifi_2_bar", - "tags" : [ ] -}, { - "name" : "wifi_2_bar", - "tags" : [ "2", "bar", "cell", "cellular", "connection", "data", "internet", "mobile", "network", "phone", "scan", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "u_turn_right", - "tags" : [ "arrow", "arrows", "direction", "directions", "maps", "navigation", "path", "right", "route", "sign", "traffic", "u-turn" ] -}, { - "name" : "currency_yuan", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "money", "online", "pay", "payment", "price", "shopping", "symbol", "yuan" ] -}, { - "name" : "currency_lira", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "lira", "money", "online", "pay", "payment", "price", "shopping", "symbol" ] -}, { - "name" : "no_flash", - "tags" : [ "bolt", "camera", "disabled", "enabled", "flash", "image", "lightning", "no", "off", "on", "photo", "photography", "picture", "slash", "thunderbolt" ] -}, { - "name" : "temple_hindu", - "tags" : [ "hindu", "hinduism", "hindus", "mandir", "religion", "spiritual", "temple", "worship" ] -}, { - "name" : "mode_fan_off", - "tags" : [ "air conditioner", "cool", "disabled", "enabled", "fan", "nest", "off", "on", "slash" ] -}, { - "name" : "airline_seat_legroom_extra", - "tags" : [ "airline", "body", "extra", "feet", "human", "leg", "legroom", "people", "person", "seat", "sitting", "space", "travel" ] -}, { - "name" : "4k_plus", - "tags" : [ "+", "4000", "4K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "plus", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "border_inner", - "tags" : [ "border", "doc", "edit", "editing", "editor", "inner", "sheet", "spreadsheet", "stroke", "text", "type", "writing" ] -}, { - "name" : "wifi_tethering_error", - "tags" : [ "!", "alert", "attention", "caution", "cell", "cellular", "connection", "danger", "data", "error", "exclamation", "important", "internet", "mark", "mobile", "network", "notification", "phone", "rounded", "scan", "service", "signal", "speed", "symbol", "tethering", "warning", "wifi", "wireless" ] -}, { - "name" : "airline_seat_legroom_reduced", - "tags" : [ "airline", "body", "feet", "human", "leg", "legroom", "people", "person", "reduced", "seat", "sitting", "space", "travel" ] -}, { - "name" : "synagogue", - "tags" : [ "jew", "jewish", "religion", "shul", "spiritual", "temple", "worship" ] -}, { - "name" : "border_left", - "tags" : [ "border", "doc", "edit", "editing", "editor", "left", "sheet", "spreadsheet", "stroke", "text", "type", "writing" ] -}, { - "name" : "autofps_select", - "tags" : [ "A", "alphabet", "auto", "character", "font", "fps", "frame", "frequency", "letter", "per", "rate", "second", "seconds", "select", "symbol", "text", "type" ] -}, { - "name" : "signal_cellular_alt_2_bar", - "tags" : [ "2", "bar", "cell", "cellular", "data", "internet", "mobile", "network", "phone", "signal", "speed", "wifi", "wireless" ] -}, { - "name" : "g_mobiledata", - "tags" : [ "alphabet", "character", "data", "font", "g", "letter", "mobile", "network", "service", "symbol", "text", "type" ] -}, { - "name" : "1k", - "tags" : [ "1000", "1K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "format_textdirection_l_to_r", - "tags" : [ "align", "alignment", "doc", "edit", "editing", "editor", "format", "ltr", "sheet", "spreadsheet", "text", "textdirection", "type", "writing" ] -}, { - "name" : "border_bottom", - "tags" : [ "border", "bottom", "doc", "edit", "editing", "editor", "sheet", "spreadsheet", "stroke", "text", "type", "writing" ] -}, { - "name" : "fork_left", - "tags" : [ "arrow", "arrows", "direction", "directions", "fork", "left", "maps", "navigation", "path", "route", "sign", "traffic" ] -}, { - "name" : "severe_cold", - "tags" : [ "!", "alert", "attention", "caution", "climate", "cold", "crisis", "danger", "disaster", "error", "exclamation", "important", "notification", "severe", "snow", "snowflake", "warning", "weather", "winter" ] -}, { - "name" : "tsunami", - "tags" : [ "crisis", "disaster", "flood", "rain", "storm", "tsunami", "weather" ] -}, { - "name" : "signal_cellular_alt_1_bar", - "tags" : [ "1", "bar", "cell", "cellular", "data", "internet", "mobile", "network", "phone", "signal", "speed", "wifi", "wireless" ] -}, { - "name" : "border_vertical", - "tags" : [ "border", "doc", "edit", "editing", "editor", "sheet", "spreadsheet", "stroke", "text", "type", "vertical", "writing" ] -}, { - "name" : "turn_sharp_right", - "tags" : [ "arrow", "arrows", "direction", "directions", "maps", "navigation", "path", "right", "route", "sharp", "sign", "traffic", "turn" ] -}, { - "name" : "no_backpack", - "tags" : [ "accessory", "backpack", "bag", "bookbag", "knapsack", "no", "pack", "travel" ] -}, { - "name" : "remove_road", - "tags" : [ "-", "cancel", "close", "destination", "direction", "exit", "highway", "maps", "minus", "new", "no", "remove", "road", "stop", "street", "symbol", "traffic", "x" ] -}, { - "name" : "timer_3_select", - "tags" : [ "3", "alphabet", "camera", "character", "digit", "font", "letter", "number", "seconds", "select", "symbol", "text", "timer", "type" ] -}, { - "name" : "roller_skating", - "tags" : [ "athlete", "athletic", "entertainment", "exercise", "hobby", "roller", "shoe", "skate", "skates", "skating", "social", "sports", "travel" ] -}, { - "name" : "panorama_horizontal_select", - "tags" : [ "angle", "horizontal", "image", "panorama", "photo", "photography", "picture", "select", "wide" ] -}, { - "name" : "border_horizontal", - "tags" : [ "border", "doc", "edit", "editing", "editor", "horizontal", "sheet", "spreadsheet", "stroke", "text", "type", "writing" ] -}, { - "name" : "2k", - "tags" : [ "2000", "2K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "wifi_1_bar", - "tags" : [ "1", "bar", "cell", "cellular", "connection", "data", "internet", "mobile", "network", "phone", "scan", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "format_textdirection_r_to_l", - "tags" : [ "align", "alignment", "doc", "edit", "editing", "editor", "format", "rtl", "sheet", "spreadsheet", "text", "textdirection", "type", "writing" ] -}, { - "name" : "wifi_channel", - "tags" : [ "(scan)", "[cellular", "channel", "connection", "data", "internet", "mobile]", "network", "service", "signal", "wifi", "wireless" ] -}, { - "name" : "roundabout_right", - "tags" : [ "arrow", "arrows", "direction", "directions", "maps", "navigation", "path", "right", "roundabout", "route", "sign", "traffic" ] -}, { - "name" : "wb_auto", - "tags" : [ "A", "W", "alphabet", "auto", "automatic", "balance", "character", "edit", "editing", "font", "image", "letter", "photo", "photography", "symbol", "text", "type", "white", "wp" ] -}, { - "name" : "panorama_photosphere_select", - "tags" : [ "angle", "horizontal", "image", "panorama", "photo", "photography", "photosphere", "picture", "select", "wide" ] -}, { - "name" : "panorama_wide_angle", - "tags" : [ "angle", "image", "panorama", "photo", "photography", "picture", "wide" ] -}, { - "name" : "hdr_plus", - "tags" : [ "+", "add", "alphabet", "character", "circle", "dynamic", "enhance", "font", "hdr", "high", "letter", "plus", "range", "select", "symbol", "text", "type" ] -}, { - "name" : "panorama_vertical_select", - "tags" : [ "angle", "image", "panorama", "photo", "photography", "picture", "select", "vertical", "wide" ] -}, { - "name" : "border_top", - "tags" : [ "border", "doc", "edit", "editing", "editor", "sheet", "spreadsheet", "stroke", "text", "top", "type", "writing" ] -}, { - "name" : "mic_external_off", - "tags" : [ "audio", "disabled", "enabled", "external", "mic", "microphone", "off", "on", "slash", "sound", "voice" ] -}, { - "name" : "width_full", - "tags" : [ ] -}, { - "name" : "h_mobiledata", - "tags" : [ "alphabet", "character", "data", "font", "h", "letter", "mobile", "network", "service", "symbol", "text", "type" ] -}, { - "name" : "roller_shades", - "tags" : [ "blinds", "cover", "curtains", "nest", "open", "roller", "shade", "shutter", "sunshade" ] -}, { - "name" : "no_stroller", - "tags" : [ "baby", "care", "carriage", "child", "children", "disabled", "enabled", "infant", "kid", "newborn", "no", "off", "on", "parents", "slash", "stroller", "toddler", "young" ] -}, { - "name" : "tornado", - "tags" : [ "crisis", "disaster", "natural", "rain", "storm", "tornado", "weather", "wind" ] -}, { - "name" : "keyboard_control_key", - "tags" : [ "control key", "keyboard" ] -}, { - "name" : "turn_slight_right", - "tags" : [ "arrow", "arrows", "direction", "directions", "maps", "navigation", "path", "right", "route", "sharp", "sign", "slight", "traffic", "turn" ] -}, { - "name" : "border_right", - "tags" : [ "border", "doc", "edit", "editing", "editor", "right", "sheet", "spreadsheet", "stroke", "text", "type", "writing" ] -}, { - "name" : "1k_plus", - "tags" : [ "+", "1000", "1K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "plus", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "turn_slight_left", - "tags" : [ "arrow", "arrows", "direction", "directions", "maps", "navigation", "path", "right", "route", "sign", "slight", "traffic", "turn" ] -}, { - "name" : "screen_rotation_alt", - "tags" : [ "Android", "OS", "arrow", "device", "hardware", "iOS", "mobile", "phone", "rotate", "rotation", "screen", "tablet", "turn" ] -}, { - "name" : "dataset_linked", - "tags" : [ ] -}, { - "name" : "unfold_less_double", - "tags" : [ "arrow", "arrows", "chevron", "collapse", "direction", "double", "expand", "expandable", "inward", "less", "list", "navigation", "unfold", "up" ] -}, { - "name" : "8k", - "tags" : [ "8000", "8K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "landslide", - "tags" : [ "crisis", "disaster", "natural", "rain", "storm", "weather" ] -}, { - "name" : "media_bluetooth_off", - "tags" : [ "bluetooth", "connect", "connection", "connectivity", "device", "disabled", "enabled", "media", "music", "note", "off", "offline", "on", "paring", "signal", "slash", "symbol", "wireless" ] -}, { - "name" : "fire_truck", - "tags" : [ ] -}, { - "name" : "e_mobiledata", - "tags" : [ "alphabet", "data", "e", "font", "letter", "mobile", "mobiledata", "text", "type" ] -}, { - "name" : "panorama_vertical", - "tags" : [ "angle", "image", "panorama", "photo", "photography", "picture", "vertical", "wide" ] -}, { - "name" : "r_mobiledata", - "tags" : [ "alphabet", "character", "data", "font", "letter", "mobile", "r", "symbol", "text", "type" ] -}, { - "name" : "12mp", - "tags" : [ "12", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "repartition", - "tags" : [ "arrow", "arrows", "data", "partition", "refresh", "renew", "repartition", "restore", "table" ] -}, { - "name" : "width_normal", - "tags" : [ ] -}, { - "name" : "h_plus_mobiledata", - "tags" : [ "+", "alphabet", "character", "data", "font", "h", "letter", "mobile", "network", "plus", "service", "symbol", "text", "type" ] -}, { - "name" : "hdr_enhanced_select", - "tags" : [ "add", "alphabet", "character", "dynamic", "enhance", "font", "hdr", "high", "letter", "plus", "range", "select", "symbol", "text", "type" ] -}, { - "name" : "mp", - "tags" : [ "alphabet", "character", "font", "image", "letter", "megapixel", "mp", "photo", "photography", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "shape_line", - "tags" : [ "circle", "draw", "edit", "editing", "line", "shape", "square" ] -}, { - "name" : "9k_plus", - "tags" : [ "+", "9000", "9K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "plus", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "5k", - "tags" : [ "5000", "5K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "hevc", - "tags" : [ "alphabet", "character", "coding", "efficiency", "font", "hevc", "high", "letter", "symbol", "text", "type", "video" ] -}, { - "name" : "currency_franc", - "tags" : [ "bill", "card", "cash", "coin", "commerce", "cost", "credit", "currency", "dollars", "finance", "franc", "money", "online", "pay", "payment", "price", "shopping", "symbol" ] -}, { - "name" : "8k_plus", - "tags" : [ "+", "7000", "8K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "plus", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "hdr_on_select", - "tags" : [ "+", "alphabet", "camera", "character", "circle", "dynamic", "font", "hdr", "high", "letter", "on", "photo", "range", "select", "symbol", "text", "type" ] -}, { - "name" : "3k", - "tags" : [ "3000", "3K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "transcribe", - "tags" : [ ] -}, { - "name" : "width_wide", - "tags" : [ ] -}, { - "name" : "hdr_auto_select", - "tags" : [ "+", "A", "alphabet", "auto", "camera", "character", "circle", "dynamic", "font", "hdr", "high", "letter", "photo", "range", "select", "symbol", "text", "type" ] -}, { - "name" : "hls", - "tags" : [ "alphabet", "character", "develop", "developer", "engineer", "engineering", "font", "hls", "letter", "platform", "symbol", "text", "type" ] -}, { - "name" : "5k_plus", - "tags" : [ "+", "5000", "5K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "plus", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "assist_walker", - "tags" : [ "accessibility", "accessible", "assist", "body", "disability", "handicap", "help", "human", "injured", "injury", "mobility", "person", "walk", "walker" ] -}, { - "name" : "hls_off", - "tags" : [ "alphabet", "character", "develop", "developer", "disabled", "enabled", "engineer", "engineering", "font", "hls", "letter", "off", "offline", "on", "platform", "slash", "symbol", "text", "type" ] -}, { - "name" : "18mp", - "tags" : [ "18", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "format_overline", - "tags" : [ "alphabet", "character", "doc", "edit", "editing", "editor", "font", "format", "letter", "line", "overline", "sheet", "spreadsheet", "style", "symbol", "text", "type", "under", "writing" ] -}, { - "name" : "volcano", - "tags" : [ "crisis", "disaster", "eruption", "lava", "magma", "natural", "volcano" ] -}, { - "name" : "vaping_rooms", - "tags" : [ "allowed", "e-cigarette", "never", "no", "places", "prohibited", "smoke", "smoking", "tobacco", "vape", "vaping", "vapor", "warning", "zone" ] -}, { - "name" : "watch_off", - "tags" : [ "Android", "OS", "ar", "clock", "close", "gadget", "iOS", "off", "shut", "time", "vr", "watch", "wearables", "web", "wristwatch" ] -}, { - "name" : "9k", - "tags" : [ "9000", "9K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "23mp", - "tags" : [ "23", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "propane", - "tags" : [ "gas", "nest", "propane" ] -}, { - "name" : "raw_off", - "tags" : [ "alphabet", "character", "disabled", "enabled", "font", "image", "letter", "off", "on", "original", "photo", "photography", "raw", "slash", "symbol", "text", "type" ] -}, { - "name" : "keyboard_option_key", - "tags" : [ "alt key", "key", "keyboard", "modifier key", "option" ] -}, { - "name" : "woman_2", - "tags" : [ "female", "gender", "girl", "lady", "social", "symbol", "woman", "women" ] -}, { - "name" : "2k_plus", - "tags" : [ "+", "2k", "alphabet", "character", "digit", "font", "letter", "number", "plus", "symbol", "text", "type" ] -}, { - "name" : "6k_plus", - "tags" : [ "+", "6000", "6K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "plus", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "broadcast_on_personal", - "tags" : [ ] -}, { - "name" : "10mp", - "tags" : [ "10", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "man_2", - "tags" : [ "boy", "gender", "male", "man", "social", "symbol" ] -}, { - "name" : "7k", - "tags" : [ "7000", "7K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "7k_plus", - "tags" : [ "+", "7000", "7K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "plus", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "nearby_off", - "tags" : [ "disabled", "enabled", "nearby", "off", "on", "slash" ] -}, { - "name" : "3k_plus", - "tags" : [ "+", "3000", "3K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "plus", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "6k", - "tags" : [ "6000", "6K", "alphabet", "character", "digit", "display", "font", "letter", "number", "pixel", "pixels", "resolution", "symbol", "text", "type", "video" ] -}, { - "name" : "hdr_off", - "tags" : [ "alphabet", "character", "disabled", "dynamic", "enabled", "enhance", "font", "hdr", "high", "letter", "off", "on", "range", "select", "slash", "symbol", "text", "type" ] -}, { - "name" : "roundabout_left", - "tags" : [ "arrow", "arrows", "direction", "directions", "left", "maps", "navigation", "path", "roundabout", "route", "sign", "traffic" ] -}, { - "name" : "hdr_off_select", - "tags" : [ "alphabet", "camera", "character", "circle", "disabled", "dynamic", "enabled", "font", "hdr", "high", "letter", "off", "on", "photo", "range", "select", "slash", "symbol", "text", "type" ] -}, { - "name" : "bedtime_off", - "tags" : [ "bedtime", "disabled", "lunar", "moon", "night", "nightime", "off", "offline", "slash", "sleep" ] -}, { - "name" : "18_up_rating", - "tags" : [ ] -}, { - "name" : "turn_sharp_left", - "tags" : [ "arrow", "arrows", "direction", "directions", "left", "maps", "navigation", "path", "route", "sharp", "sign", "traffic", "turn" ] -}, { - "name" : "11mp", - "tags" : [ "11", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "roller_shades_closed", - "tags" : [ "blinds", "closed", "cover", "curtains", "nest", "roller", "shade", "shutter", "sunshade" ] -}, { - "name" : "20mp", - "tags" : [ "20", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "blinds", - "tags" : [ "blinds", "cover", "curtains", "nest", "open", "shade", "shutter", "sunshade" ] -}, { - "name" : "3mp", - "tags" : [ "3", "camera", "digit", "font", "image", "letters", "megapixel", "megapixels", "mp", "number", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "blind", - "tags" : [ "accessibility", "accessible", "assist", "blind", "body", "cane", "disability", "handicap", "help", "human", "mobility", "person", "walk", "walker" ] -}, { - "name" : "emergency_recording", - "tags" : [ "alert", "attention", "camera", "caution", "danger", "emergency", "film", "filming", "hardware", "image", "important", "motion", "notification", "picture", "record", "video", "videography", "warning" ] -}, { - "name" : "curtains", - "tags" : [ "blinds", "cover", "curtains", "nest", "open", "shade", "shutter", "sunshade" ] -}, { - "name" : "13mp", - "tags" : [ "13", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "5mp", - "tags" : [ "5", "camera", "digit", "font", "image", "letters", "megapixel", "megapixels", "mp", "number", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "21mp", - "tags" : [ "21", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "blinds_closed", - "tags" : [ "blinds", "closed", "cover", "curtains", "nest", "shade", "shutter", "sunshade" ] -}, { - "name" : "16mp", - "tags" : [ "16", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "17mp", - "tags" : [ "17", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "2mp", - "tags" : [ "2", "camera", "digit", "font", "image", "letters", "megapixel", "megapixels", "mp", "number", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "15mp", - "tags" : [ "15", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "desk", - "tags" : [ ] -}, { - "name" : "no_adult_content", - "tags" : [ ] -}, { - "name" : "14mp", - "tags" : [ "14", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "22mp", - "tags" : [ "22", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "vertical_shades", - "tags" : [ "blinds", "cover", "curtains", "nest", "open", "shade", "shutter", "sunshade", "vertical" ] -}, { - "name" : "vertical_shades_closed", - "tags" : [ "blinds", "closed", "cover", "curtains", "nest", "roller", "shade", "shutter", "sunshade" ] -}, { - "name" : "curtains_closed", - "tags" : [ "blinds", "closed", "cover", "curtains", "nest", "shade", "shutter", "sunshade" ] -}, { - "name" : "broadcast_on_home", - "tags" : [ ] -}, { - "name" : "4mp", - "tags" : [ "4", "camera", "digit", "font", "image", "letters", "megapixel", "megapixels", "mp", "number", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "19mp", - "tags" : [ "19", "camera", "digits", "font", "image", "letters", "megapixel", "megapixels", "mp", "numbers", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "nest_cam_wired_stand", - "tags" : [ "camera", "film", "filming", "hardware", "image", "motion", "nest", "picture", "stand", "video", "videography", "wired" ] -}, { - "name" : "9mp", - "tags" : [ "9", "camera", "digit", "font", "image", "letters", "megapixel", "megapixels", "mp", "number", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "7mp", - "tags" : [ "7", "camera", "digit", "font", "image", "letters", "megapixel", "megapixels", "mp", "number", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "8mp", - "tags" : [ "8", "camera", "digit", "font", "image", "letters", "megapixel", "megapixels", "mp", "number", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "6mp", - "tags" : [ "6", "camera", "digit", "font", "image", "letters", "megapixel", "megapixels", "mp", "number", "pixel", "pixels", "quality", "resolution", "symbol", "text", "type" ] -}, { - "name" : "devices_fold", - "tags" : [ "Android", "OS", "cell", "device", "fold", "foldable", "hardware", "iOS", "mobile", "phone", "tablet" ] -}, { - "name" : "vape_free", - "tags" : [ "disabled", "e-cigarette", "enabled", "free", "never", "no", "off", "on", "places", "prohibited", "slash", "smoke", "smoking", "tobacco", "vape", "vaping", "vapor", "warning", "zone" ] -}, { - "name" : "ramp_left", - "tags" : [ "arrow", "arrows", "direction", "directions", "left", "maps", "navigation", "path", "ramp", "route", "sign", "traffic" ] -}, { - "name" : "ramp_right", - "tags" : [ "arrow", "arrows", "direction", "directions", "maps", "navigation", "path", "ramp", "right", "route", "sign", "traffic" ] -}, { - "name" : "video_chat", - "tags" : [ "bubble", "cam", "camera", "chat", "comment", "communicate", "facetime", "feedback", "message", "speech", "video", "voice" ] -}, { - "name" : "type_specimen", - "tags" : [ ] -}, { - "name" : "man_4", - "tags" : [ "abstract", "boy", "gender", "male", "man", "social", "symbol" ] -}, { - "name" : "fluorescent", - "tags" : [ "bright", "fluorescent", "lamp", "light", "lightbulb" ] -}, { - "name" : "man_3", - "tags" : [ "abstract", "boy", "gender", "male", "man", "social", "symbol" ] -}, { - "name" : "fire_hydrant_alt", - "tags" : [ ] -}, { - "name" : "macro_off", - "tags" : [ "camera", "disabled", "enabled", "flower", "garden", "image", "macro", "off", "offline", "on", "slash" ] -} ] \ No newline at end of file +[{"name":"more_horiz","tags":["3","DISABLE_IOS","app","application","components","disable_ios","dots","etc","horiz","horizontal","interface","ios","more","screen","site","three","ui","ux","web","website"]},{"name":"more_vert","tags":["3","DISABLE_IOS","android","app","application","components","disable_ios","dots","etc","interface","more","screen","site","three","ui","ux","vert","vertical","web","website"]},{"name":"open_in_new","tags":["app","application","arrow","box","components","in","interface","new","open","right","screen","site","ui","up","ux","web","website","window"]},{"name":"visibility","tags":["eye","on","reveal","see","show","view","visibility"]},{"name":"play_arrow","tags":["arrow","control","controls","media","music","play","video"]},{"name":"arrow_back","tags":["DISABLE_IOS","app","application","arrow","back","components","direction","disable_ios","interface","left","navigation","previous","screen","site","ui","ux","web","website"]},{"name":"arrow_downward","tags":["app","application","arrow","components","direction","down","downward","interface","navigation","screen","site","ui","ux","web","website"]},{"name":"arrow_forward","tags":["app","application","arrow","arrows","components","direction","forward","interface","navigation","right","screen","site","ui","ux","web","website"]},{"name":"arrow_upward","tags":["app","application","arrow","components","direction","interface","navigation","screen","site","ui","up","upward","ux","web","website"]},{"name":"close","tags":["cancel","close","exit","stop","x"]},{"name":"refresh","tags":["around","arrow","arrows","direction","inprogress","load","loading refresh","navigation","refresh","renew","right","rotate","turn"]},{"name":"menu","tags":["app","application","components","hamburger","interface","line","lines","menu","screen","site","ui","ux","web","website"]},{"name":"show_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","line","measure","metrics","presentation","show chart","statistics","tracking"]},{"name":"multiline_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","line","measure","metrics","multiple","statistics","tracking"]},{"name":"pie_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","pie","statistics","tracking"]},{"name":"insert_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","insert","measure","metrics","statistics","tracking"]},{"name":"people","tags":["accounts","committee","face","family","friends","humans","network","people","persons","profiles","social","team","users"]},{"name":"person","tags":["account","face","human","people","person","profile","user"]},{"name":"domain","tags":["apartment","architecture","building","business","domain","estate","home","place","real","residence","residential","shelter","web","www"]},{"name":"devices_other","tags":["Android","OS","ar","cell","chrome","desktop","device","gadget","hardware","iOS","ipad","mac","mobile","monitor","other","phone","tablet","vr","watch","wearables","window"]},{"name":"widgets","tags":["app","box","menu","setting","squares","ui","widgets"]},{"name":"dashboard","tags":["cards","dashboard","format","layout","rectangle","shapes","square","web","website"]},{"name":"map","tags":["destination","direction","location","map","maps","pin","place","route","stop","travel"]},{"name":"pin_drop","tags":["destination","direction","drop","location","maps","navigation","pin","place","stop"]},{"name":"gps_fixed","tags":["destination","direction","fixed","gps","location","maps","pin","place","pointer","stop","tracking"]},{"name":"extension","tags":["app","extended","extension","game","jigsaw","plugin add","puzzle","shape"]},{"name":"search","tags":["filter","find","glass","look","magnify","magnifying","search","see"]},{"name":"settings","tags":["application","change","details","gear","info","information","options","personal","service","settings"]},{"name":"notifications","tags":["active","alarm","alert","bell","chime","notifications","notify","reminder","ring","sound"]},{"name":"notifications_active","tags":["active","alarm","alert","bell","chime","notifications","notify","reminder","ring","ringing","sound"]},{"name":"info","tags":["alert","announcement","assistance","details","help","i","info","information","service","support"]},{"name":"error_outline","tags":["!","alert","attention","caution","circle","danger","error","exclamation","important","mark","notification","outline","symbol","warning"]},{"name":"warning","tags":["!","alert","attention","caution","danger","error","exclamation","important","mark","notification","symbol","triangle","warning"]},{"name":"list","tags":["file","format","index","list","menu","options"]},{"name":"download","tags":["arrow","down","download","downloads","drive","install","upload"]},{"name":"import_export","tags":["arrow","arrows","direction","down","explort","import","up"]},{"name":"share","tags":["DISABLE_IOS","android","connect","contect","disable_ios","link","media","multimedia","multiple","network","options","share","shared","sharing","social"]},{"name":"add","tags":["+","add","new symbol","plus","symbol"]},{"name":"edit","tags":["compose","create","edit","editing","input","new","pen","pencil","write","writing"]},{"name":"check","tags":["DISABLE_IOS","check","confirm","correct","disable_ios","done","enter","mark","ok","okay","select","tick","yes"]},{"name":"delete","tags":["bin","can","delete","garbage","remove","trash"]},{"name":"thermostat","tags":["climate","forecast","temperature","thermostat","weather"]},{"name":"air","tags":["air","blowing","breeze","flow","wave","weather","wind"]},{"name":"lightbulb","tags":["alert","announcement","idea","info","information","light","lightbulb"]},{"name":"home","tags":["address","app","application--house","architecture","building","components","design","estate","home","interface","layout","place","real","residence","residential","screen","shelter","site","structure","ui","unit","ux","web","website","window"]},{"name":"account_circle","tags":["account","avatar","circle","face","human","people","person","profile","thumbnail","user"]},{"name":"done","tags":["DISABLE_IOS","approve","check","complete","disable_ios","done","mark","ok","select","tick","validate","verified","yes"]},{"name":"check_circle","tags":["approve","check","circle","complete","done","mark","ok","select","tick","validate","verified","yes"]},{"name":"expand_more","tags":["arrow","arrows","chevron","collapse","direction","down","expand","expandable","list","more"]},{"name":"shopping_cart","tags":["add","bill","buy","card","cart","cash","checkout","coin","commerce","credit","currency","dollars","money","online","pay","payment","shopping"]},{"name":"email","tags":["email","envelop","letter","mail","message","send"]},{"name":"favorite","tags":["appreciate","favorite","heart","like","love","remember","save","shape"]},{"name":"description","tags":["article","data","description","doc","document","drive","file","folder","folders","notes","page","paper","sheet","slide","text","writing"]},{"name":"logout","tags":["app","application","arrow","components","design","exit","interface","leave","log","login","logout","right","screen","site","ui","ux","web","website"]},{"name":"favorite_border","tags":["border","favorite","heart","like","love","outline","remember","save","shape"]},{"name":"chevron_right","tags":["arrow","arrows","chevron","direction","right"]},{"name":"lock","tags":["lock","locked","password","privacy","private","protection","safety","secure","security"]},{"name":"location_on","tags":["destination","direction","location","maps","on","pin","place","room","stop"]},{"name":"schedule","tags":["clock","date","schedule","time"]},{"name":"local_shipping","tags":["automobile","car","cars","delivery","letter","local","mail","maps","office","package","parcel","post","postal","send","shipping","shopping","stamp","transportation","truck","vehicle"]},{"name":"language","tags":["globe","internet","language","planet","website","world","www"]},{"name":"call","tags":["call","cell","contact","device","hardware","mobile","phone","telephone"]},{"name":"file_download","tags":["arrow","arrows","down","download","downloads","drive","export","file","install","upload"]},{"name":"arrow_forward_ios","tags":["app","application","arrow","chevron","components","direction","forward","interface","ios","navigation","next","right","screen","site","ui","ux","web","website"]},{"name":"arrow_back_ios","tags":["DISABLE_IOS","app","application","arrow","back","chevron","components","direction","disable_ios","interface","ios","left","navigation","previous","screen","site","ui","ux","web","website"]},{"name":"groups","tags":["body","club","collaboration","crowd","gathering","groups","human","meeting","people","person","social","teams"]},{"name":"cancel","tags":["cancel","circle","close","exit","stop","x"]},{"name":"help_outline","tags":["?","assistance","circle","help","info","information","outline","punctuation","question mark","recent","restore","shape","support","symbol"]},{"name":"arrow_drop_down","tags":["app","application","arrow","components","direction","down","drop","interface","navigation","screen","site","ui","ux","web","website"]},{"name":"face","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"manage_accounts","tags":["accounts","change","details service-human","face","gear","manage","options","people","person","profile","settings","user"]},{"name":"place","tags":["destination","direction","location","maps","navigation","pin","place","point","stop"]},{"name":"verified","tags":["approve","badge","burst","check","complete","done","mark","ok","select","star","tick","validate","verified","yes"]},{"name":"add_circle_outline","tags":["+","add","circle","create","new","outline","plus"]},{"name":"filter_alt","tags":["alt","edit","filter","funnel","options","refine","sift"]},{"name":"thumb_up","tags":["favorite","fingers","gesture","hand","hands","like","rank","ranking","rate","rating","thumb","up"]},{"name":"event","tags":["calendar","date","day","event","mark","month","range","remember","reminder","today","week"]},{"name":"star","tags":["best","bookmark","favorite","highlight","ranking","rate","rating","save","star","toggle"]},{"name":"fingerprint","tags":["finger","fingerprint","id","identification","identity","print","reader","thumbprint","verification"]},{"name":"content_copy","tags":["content","copy","cut","doc","document","duplicate","file","multiple","past"]},{"name":"login","tags":["access","app","application","arrow","components","design","enter","in","interface","left","log","login","screen","sign","site","ui","ux","web","website"]},{"name":"add_circle","tags":["+","add","circle","create","new","plus"]},{"name":"visibility_off","tags":["disabled","enabled","eye","off","on","reveal","see","show","slash","view","visibility"]},{"name":"check_circle_outline","tags":["approve","check","circle","complete","done","finished","mark","ok","outline","select","tick","validate","verified","yes"]},{"name":"chevron_left","tags":["DISABLE_IOS","arrow","arrows","chevron","direction","disable_ios","left"]},{"name":"calendar_today","tags":["calendar","date","day","event","month","schedule","today"]},{"name":"send","tags":["email","mail","message","paper","plane","reply","right","send","share"]},{"name":"check_box","tags":["approved","box","button","check","component","control","form","mark","ok","select","selected","selection","tick","toggle","ui","yes"]},{"name":"highlight_off","tags":["cancel","close","exit","highlight","no","off","quit","remove","stop","x"]},{"name":"navigate_next","tags":["arrow","arrows","direction","navigate","next","right"]},{"name":"help","tags":["?","assistance","circle","help","info","information","punctuation","question mark","recent","restore","shape","support","symbol"]},{"name":"phone","tags":["call","cell","contact","device","hardware","mobile","phone","telephone"]},{"name":"paid","tags":["circle","currency","money","paid","payment","transaction"]},{"name":"task_alt","tags":["approve","check","circle","complete","done","mark","ok","select","task","tick","validate","verified","yes"]},{"name":"question_answer","tags":["answer","bubble","chat","comment","communicate","conversation","feedback","message","question","speech","talk"]},{"name":"expand_less","tags":["arrow","arrows","chevron","collapse","direction","expand","expandable","less","list","up"]},{"name":"clear","tags":["back","cancel","clear","correct","delete","erase","exit","x"]},{"name":"date_range","tags":["calendar","date","day","event","month","range","remember","reminder","schedule","time","today","week"]},{"name":"article","tags":["article","doc","document","file","page","paper","text","writing"]},{"name":"error","tags":["!","alert","attention","caution","circle","danger","error","exclamation","important","mark","notification","symbol","warning"]},{"name":"photo_camera","tags":["camera","image","photo","photography","picture"]},{"name":"check_box_outline_blank","tags":["blank","box","button","check","component","control","deselected","empty","form","outline","select","selection","square","tick","toggle","ui"]},{"name":"image","tags":["disabled","enabled","hide","image","landscape","mountain","mountains","off","on","photo","photography","picture","slash"]},{"name":"shopping_bag","tags":["bag","bill","business","buy","card","cart","cash","coin","commerce","credit","currency","dollars","money","online","pay","payment","shop","shopping","store","storefront"]},{"name":"person_outline","tags":["account","face","human","outline","people","person","profile","user"]},{"name":"school","tags":["academy","achievement","cap","class","college","education","graduation","hat","knowledge","learning","school","university"]},{"name":"file_upload","tags":["arrow","arrows","download","drive","export","file","up","upload"]},{"name":"perm_identity","tags":["account","avatar","face","human","identity","people","perm","person","profile","thumbnail","user"]},{"name":"credit_card","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","shopping","symbol"]},{"name":"history","tags":["arrow","back","backwards","clock","date","history","refresh","renew","reverse","rotate","schedule","time","turn"]},{"name":"trending_up","tags":["analytics","arrow","data","diagram","graph","infographic","measure","metrics","movement","rate","rating","statistics","tracking","trending","up"]},{"name":"support_agent","tags":["agent","care","customer","face","headphone","person","representative","service","support"]},{"name":"account_balance","tags":["account","balance","bank","bill","card","cash","coin","commerce","credit","currency","dollars","finance","money","online","pay","payment"]},{"name":"delete_outline","tags":["bin","can","delete","garbage","outline","remove","trash"]},{"name":"attach_money","tags":["attach","attachment","bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","symbol"]},{"name":"person_add","tags":["+","account","add","avatar","face","human","new","people","person","plus","profile","symbol","user"]},{"name":"public","tags":["earth","global","globe","map","network","planet","public","social","space","web","world"]},{"name":"save","tags":["data","disk","document","drive","file","floppy","multimedia","save","storage"]},{"name":"mail","tags":["email","envelop","letter","mail","message","send"]},{"name":"report_problem","tags":["!","alert","attention","caution","danger","error","exclamation","feedback","important","mark","notification","problem","report","symbol","triangle","warning"]},{"name":"fact_check","tags":["approve","check","complete","done","fact","list","mark","ok","select","tick","validate","verified","yes"]},{"name":"radio_button_unchecked","tags":["bullet","button","circle","deselected","form","off","on","point","radio","record","select","toggle","unchecked"]},{"name":"verified_user","tags":["approve","certified","check","complete","done","mark","ok","privacy","private","protect","protection","security","select","shield","tick","user","validate","verified","yes"]},{"name":"assignment","tags":["assignment","clipboard","doc","document","text","writing"]},{"name":"link","tags":["chain","clip","connection","link","linked","links","multimedia","url"]},{"name":"play_circle_filled","tags":["arrow","circle","control","controls","media","music","play","video"]},{"name":"emoji_events","tags":["achievement","award","chalice","champion","cup","emoji","events","first","prize","reward","sport","trophy","winner"]},{"name":"remove","tags":["can","delete","minus","negative","remove","substract","trash"]},{"name":"star_rate","tags":["achievement","bookmark","favorite","highlight","important","marked","ranking","rate","rating rank","reward","save","saved","shape","special","star"]},{"name":"apps","tags":["all","applications","apps","circles","collection","components","dots","grid","interface","squares","ui","ux"]},{"name":"business","tags":["apartment","architecture","building","business","company","estate","home","place","real","residence","residential","shelter"]},{"name":"filter_list","tags":["filter","lines","list","organize","sort"]},{"name":"arrow_right_alt","tags":["alt","arrow","arrows","direction","east","navigation","pointing","right"]},{"name":"chat","tags":["bubble","chat","comment","communicate","feedback","message","speech"]},{"name":"account_balance_wallet","tags":["account","balance","bank","bill","card","cash","coin","commerce","credit","currency","dollars","finance","money","online","pay","payment","wallet"]},{"name":"payments","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","layer","money","multiple","online","pay","payment","payments","price","shopping","symbol"]},{"name":"menu_book","tags":["book","dining","food","meal","menu","restaurant"]},{"name":"folder","tags":["data","doc","document","drive","file","folder","folders","sheet","slide","storage"]},{"name":"keyboard_arrow_down","tags":["arrow","arrows","down","keyboard"]},{"name":"autorenew","tags":["around","arrow","arrows","autorenew","cache","cached","direction","inprogress","load","loading refresh","navigation","renew","rotate","turn"]},{"name":"build","tags":["adjust","build","fix","home","nest","repair","tool","tools","wrench"]},{"name":"videocam","tags":["cam","camera","conference","film","filming","hardware","image","motion","picture","video","videography"]},{"name":"view_list","tags":["design","format","grid","layout","lines","list","stacked","view","website"]},{"name":"print","tags":["draft","fax","ink","machine","office","paper","print","printer","send"]},{"name":"work","tags":["bag","baggage","briefcase","business","case","job","suitcase","work"]},{"name":"store","tags":["bill","building","business","card","cash","coin","commerce","company","credit","currency","dollars","market","money","online","pay","payment","shop","shopping","store","storefront"]},{"name":"analytics","tags":["analytics","assessment","bar","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"radio_button_checked","tags":["app","application","bullet","button","checked","circle","components","design","form","interface","off","on","point","radio","record","screen","select","selected","site","toggle","ui","ux","web","website"]},{"name":"phone_iphone","tags":["Android","OS","cell","device","hardware","iOS","iphone","mobile","phone","tablet"]},{"name":"play_circle","tags":["arrow","circle","control","controls","media","music","play","video"]},{"name":"tune","tags":["adjust","audio","controls","custom","customize","edit","editing","filter","filters","instant","mix","music","options","setting","settings","slider","sliders","switches","tune"]},{"name":"delete_forever","tags":["bin","can","cancel","delete","exit","forever","garbage","remove","trash","x"]},{"name":"today","tags":["calendar","date","day","event","mark","month","remember","reminder","schedule","time","today"]},{"name":"grid_view","tags":["app","application square","blocks","components","dashboard","design","grid","interface","layout","screen","site","tiles","ui","ux","view","web","website","window"]},{"name":"east","tags":["arrow","directional","east","maps","navigation","right"]},{"name":"inventory_2","tags":["archive","box","file","inventory","organize","packages","product","stock","storage","supply"]},{"name":"mail_outline","tags":["email","envelop","letter","mail","message","outline","send"]},{"name":"admin_panel_settings","tags":["account","admin","avatar","certified","face","human","panel","people","person","privacy","private","profile","protect","protection","security","settings","shield","user","verified"]},{"name":"mic","tags":["hear","hearing","mic","microphone","noise","record","sound","voice"]},{"name":"calendar_month","tags":["calendar","date","day","event","month","schedule","today"]},{"name":"group","tags":["accounts","committee","face","family","friends","group","humans","network","people","persons","profiles","social","team","users"]},{"name":"picture_as_pdf","tags":["alphabet","as","character","document","file","font","image","letter","multiple","pdf","photo","photography","picture","symbol","text","type"]},{"name":"lock_open","tags":["lock","open","password","privacy","private","protection","safety","secure","security","unlocked"]},{"name":"volume_up","tags":["audio","control","music","sound","speaker","tv","up","volume"]},{"name":"watch_later","tags":["clock","date","later","schedule","time","watch"]},{"name":"grade","tags":["'favorite_news' .","'star_outline'","Duplicate of 'star_boarder'","star_border_purple500'"]},{"name":"receipt_long","tags":["bill","check","document","list","long","paper","paperwork","receipt","record","store","transaction"]},{"name":"local_offer","tags":["deal","discount","offer","price","shop","shopping","store","tag"]},{"name":"room","tags":["destination","direction","location","maps","pin","place","room","stop"]},{"name":"update","tags":["arrow","back","backwards","clock","forward","history","load","refresh","reverse","schedule","time","update"]},{"name":"badge","tags":["account","avatar","badge","card","certified","employee","face","human","identification","name","people","person","profile","security","user","work"]},{"name":"savings","tags":["bank","bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","pig","piggy","savings","symbol"]},{"name":"code","tags":["brackets","code","css","develop","developer","engineer","engineering","html","platform"]},{"name":"light_mode","tags":["bright","brightness","day","device","light","lighting","mode","morning","sky","sun","sunny"]},{"name":"receipt","tags":[]},{"name":"circle","tags":["circle","full","geometry","moon"]},{"name":"inventory","tags":["archive","box","clipboard","doc","document","file","inventory","organize","packages","product","stock","supply"]},{"name":"add_shopping_cart","tags":["add","card","cart","cash","checkout","coin","commerce","credit","currency","dollars","money","online","pay","payment","plus","shopping"]},{"name":"contact_support","tags":["?","bubble","chat","comment","communicate","contact","help","info","information","mark","message","punctuation","question","question mark","speech","support","symbol"]},{"name":"category","tags":["categories","category","circle","collection","items","product","sort","square","triangle"]},{"name":"edit_note","tags":["compose","create","draft","edit","editing","input","lines","note","pen","pencil","text","write","writing"]},{"name":"insights","tags":["ai","analytics","artificial","automatic","automation","bar","bars","chart","custom","data","diagram","genai","graph","infographic","insights","intelligence","magic","measure","metrics","smart","spark","sparkle","star","stars","statistics","tracking"]},{"name":"power_settings_new","tags":["info","information","off","on","power","save","settings","shutdown"]},{"name":"campaign","tags":["alert","announcement","campaign","loud","megaphone","microphone","notification","speaker"]},{"name":"format_list_bulleted","tags":["align","alignment","bulleted","doc","edit","editing","editor","format","list","notes","sheet","spreadsheet","text","type","writing"]},{"name":"star_border","tags":["best","bookmark","border","favorite","highlight","outline","ranking","rate","rating","save","star","toggle"]},{"name":"pause","tags":["control","controls","media","music","pause","video"]},{"name":"remove_circle_outline","tags":["block","can","circle","delete","minus","negative","outline","remove","substract","trash"]},{"name":"warning_amber","tags":["!","alert","amber","attention","caution","danger","error","exclamation","important","mark","notification","symbol","triangle","warning"]},{"name":"wifi","tags":["connection","data","internet","network","scan","service","signal","wifi","wireless"]},{"name":"arrow_back_ios_new","tags":["DISABLE_IOS","app","application","arrow","back","chevron","components","direction","disable_ios","interface","ios","left","navigation","new","previous","screen","site","ui","ux","web","website"]},{"name":"restart_alt","tags":["alt","around","arrow","inprogress","load","loading refresh","reboot","renew","repeat","reset","restart"]},{"name":"done_all","tags":["all","approve","check","complete","done","layers","mark","multiple","ok","select","stack","tick","validate","verified","yes"]},{"name":"pets","tags":["animal","cat","dog","hand","paw","pet"]},{"name":"storefront","tags":["business","buy","cafe","commerce","front","market","places","restaurant","retail","sell","shop","shopping","store","storefront"]},{"name":"sort","tags":["filter","find","lines","list","organize","sort"]},{"name":"mode_edit","tags":["compose","create","draft","draw","edit","mode","pen","pencil","write"]},{"name":"list_alt","tags":["alt","box","contained","format","lines","list","order","reorder","stacked","title"]},{"name":"toggle_on","tags":["active","app","application","components","configuration","control","design","disable","inable","inactive","interface","off","on","selection","settings","site","slider","switch","toggle","ui","ux","web","website"]},{"name":"dark_mode","tags":["app","application","dark","device","interface","mode","moon","night","silent","theme","ui","ux","website"]},{"name":"engineering","tags":["body","cogs","cogwheel","construction","engineering","fixing","gears","hat","helmet","human","maintenance","people","person","setting","worker"]},{"name":"explore","tags":["compass","destination","direction","east","explore","location","maps","needle","north","south","travel","west"]},{"name":"bolt","tags":["bolt","electric","energy","fast","flash","lightning","power","thunderbolt"]},{"name":"construction","tags":["build","carpenter","construction","equipment","fix","hammer","improvement","industrial","industry","repair","tools","wrench"]},{"name":"qr_code_scanner","tags":["barcode","camera","code","media","product","qr","quick","response","scanner","smartphone","url","urls"]},{"name":"bookmark","tags":["archive","bookmark","favorite","label","library","read","reading","remember","ribbon","save","tag"]},{"name":"vpn_key","tags":["code","key","lock","network","passcode","password","unlock","vpn"]},{"name":"monetization_on","tags":["bill","card","cash","circle","coin","commerce","cost","credit","currency","dollars","finance","monetization","money","on","online","pay","payment","shopping","symbol"]},{"name":"attach_file","tags":["add","attach","attachment","clip","file","link","mail","media"]},{"name":"timer","tags":["alarm","alert","bell","clock","disabled","duration","enabled","notification","off","on","slash","stop","time","timer","watch"]},{"name":"account_box","tags":["account","avatar","box","face","human","people","person","profile","square","thumbnail","user"]},{"name":"note_add","tags":["+","-doc","add","data","document","drive","file","folder","folders","new","note","page","paper","plus","sheet","slide","symbol","writing"]},{"name":"reorder","tags":["format","lines","list","order","reorder","stacked"]},{"name":"bookmark_border","tags":["archive","bookmark","border","favorite","label","library","read","reading","remember","ribbon","save","tag"]},{"name":"arrow_right","tags":["app","application","arrow","components","direction","interface","navigation","right","screen","site","ui","ux","web","website"]},{"name":"pending_actions","tags":["actions","clipboard","clock","date","doc","document","pending","remember","schedule","time"]},{"name":"smartphone","tags":["Android","OS","call","cell","chat","device","hardware","iOS","mobile","phone","smartphone","tablet","text"]},{"name":"upload_file","tags":["arrow","data","doc","document","download","drive","file","folder","folders","page","paper","sheet","slide","up","upload","writing"]},{"name":"account_tree","tags":["account","analytics","chart","connect","data","diagram","flow","graph","infographic","measure","metrics","process","square","statistics","structure","tracking","tree"]},{"name":"shopping_basket","tags":["add","basket","bill","buy","card","cart","cash","checkout","coin","commerce","credit","currency","dollars","money","online","pay","payment","shopping"]},{"name":"flag","tags":["country","flag","goal","mark","nation","report","start"]},{"name":"apartment","tags":["accommodation","apartment","architecture","building","city","company","estate","flat","home","house","office","places","real","residence","residential","shelter","units","workplace"]},{"name":"restaurant","tags":["breakfast","dining","dinner","eat","food","fork","knife","local","lunch","meal","places","restaurant","spoon","utensils"]},{"name":"people_alt","tags":["accounts","committee","face","family","friends","humans","network","people","persons","profiles","social","team","users"]},{"name":"reply","tags":["arrow","backward","left","mail","message","reply","send","share"]},{"name":"play_circle_outline","tags":["arrow","circle","control","controls","media","music","outline","play","video"]},{"name":"payment","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","shopping","symbol"]},{"name":"sync","tags":["360","around","arrow","arrows","direction","inprogress","load","loading refresh","renew","rotate","sync","turn"]},{"name":"task","tags":["approve","check","complete","data","doc","document","done","drive","file","folder","folders","mark","ok","page","paper","select","sheet","slide","task","tick","validate","verified","writing","yes"]},{"name":"launch","tags":["app","application","arrow","box","components","interface","launch","new","open","screen","site","ui","ux","web","website","window"]},{"name":"menu_open","tags":["app","application","arrow","components","hamburger","interface","left","line","lines","menu","open","screen","site","ui","ux","web","website"]},{"name":"add_box","tags":["add","box","new square","plus","symbol"]},{"name":"drag_indicator","tags":["app","application","circles","components","design","dots","drag","drop","indicator","interface","layout","mobile","monitor","move","phone","screen","shape","shift","site","tablet","ui","ux","web","website","window"]},{"name":"supervisor_account","tags":["account","avatar","control","face","human","parental","parental control","parents","people","person","profile","supervised","supervisor","user"]},{"name":"touch_app","tags":["app","command","fingers","gesture","hand","press","tap","touch"]},{"name":"pending","tags":["circle","dots","loading","pending","progress","wait","waiting"]},{"name":"zoom_in","tags":["big","bigger","find","glass","grow","in","look","magnify","magnifying","plus","scale","search","see","size","zoom"]},{"name":"manage_search","tags":["glass","history","magnifying","manage","search","text"]},{"name":"remove_circle","tags":["block","can","circle","delete","minus","negative","remove","substract","trash"]},{"name":"group_add","tags":["accounts","add","committee","face","family","friends","group","humans","increase","more","network","people","persons","plus","profiles","social","team","users"]},{"name":"chat_bubble_outline","tags":["bubble","chat","comment","communicate","feedback","message","outline","speech"]},{"name":"assessment","tags":["analytics","assessment","bar","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"priority_high","tags":["!","alert","attention","caution","danger","error","exclamation","high","important","mark","notification","symbol","warning"]},{"name":"push_pin","tags":["location","marker","pin","place","push","remember","save"]},{"name":"feed","tags":["article","feed","headline","information","news","newspaper","paper","public","social","timeline"]},{"name":"leaderboard","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","leaderboard","measure","metrics","statistics","tracking"]},{"name":"summarize","tags":["doc","document","list","menu","note","report","summary"]},{"name":"block","tags":["avoid","block","cancel","close","entry","exit","no","prohibited","quit","remove","stop"]},{"name":"event_available","tags":["approve","available","calendar","check","complete","date","done","event","mark","ok","schedule","select","tick","time","validate","verified","yes"]},{"name":"thumb_up_off_alt","tags":["alt","disabled","enabled","favorite","fingers","gesture","hand","hands","like","off","offline","on","rank","ranking","rate","rating","slash","thumb","up"]},{"name":"directions_car","tags":["automobile","car","cars","direction","directions","maps","public","transportation","vehicle"]},{"name":"open_in_full","tags":["action","arrow","arrows","expand","full","grow","in","move","open"]},{"name":"auto_stories","tags":["auto","book","flipping","pages","stories"]},{"name":"post_add","tags":["+","add","data","doc","document","drive","file","folder","folders","page","paper","plus","post","sheet","slide","text","writing"]},{"name":"calculate","tags":["+","-","=","calculate","count","finance calculator","math"]},{"name":"alternate_email","tags":["@","address","alternate","contact","email","tag"]},{"name":"create","tags":["compose","create","edit","editing","input","new","pen","pencil","write","writing"]},{"name":"cloud_upload","tags":["app","application","arrow","backup","cloud","connection","download","drive","files","folders","internet","network","sky","storage","up","upload"]},{"name":"local_fire_department","tags":["911","climate","department","fire","firefighter","flame","heat","home","hot","nest","thermostat"]},{"name":"bar_chart","tags":["analytics","bar","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"password","tags":["key","login","password","pin","security","star","unlock"]},{"name":"collections","tags":["album","collections","gallery","image","landscape","library","mountain","mountains","photo","photography","picture","stack"]},{"name":"preview","tags":["design","eye","layout","preview","reveal","screen","see","show","site","view","web","website","window","www"]},{"name":"star_outline","tags":["bookmark","favorite","half","highlight","ranking","rate","rating","save","star","toggle"]},{"name":"exit_to_app","tags":["app","application","arrow","components","design","exit","export","interface","layout","leave","mobile","monitor","move","output","phone","screen","site","tablet","to","ui","ux","web","website","window"]},{"name":"done_outline","tags":["all","approve","check","complete","done","mark","ok","outline","select","tick","validate","verified","yes"]},{"name":"psychology","tags":["behavior","body","brain","cognitive","function","gear","head","human","intellectual","mental","mind","people","person","preferences","psychiatric","psychology","science","settings","social","therapy","thinking","thoughts"]},{"name":"assignment_ind","tags":["account","assignment","clipboard","doc","document","face","ind","people","person","profile","user"]},{"name":"volunteer_activism","tags":["activism","donation","fingers","gesture","giving","hand","hands","heart","love","sharing","volunteer"]},{"name":"navigate_before","tags":["arrow","arrows","before","direction","left","navigate"]},{"name":"published_with_changes","tags":["approve","arrow","arrows","changes","check","complete","done","inprogress","load","loading","mark","ok","published","refresh","renew","replace","rotate","select","tick","validate","verified","with","yes"]},{"name":"add_a_photo","tags":["+","a photo","add","camera","lens","new","photography","picture","plus","symbol"]},{"name":"auto_awesome","tags":["adjust","ai","artificial","automatic","automation","custom","edit","editing","enhance","genai","intelligence","magic","smart","spark","sparkle","star","stars"]},{"name":"card_giftcard","tags":["account","balance","bill","card","cart","cash","certificate","coin","commerce","credit","currency","dollars","gift","giftcard","money","online","pay","payment","present","shopping"]},{"name":"fullscreen","tags":["adjust","app","application","components","full","fullscreen","interface","screen","site","size","ui","ux","view","web","website"]},{"name":"sell","tags":["bill","card","cart","cash","coin","commerce","credit","currency","dollars","money","online","pay","payment","price","sell","shopping","tag"]},{"name":"checklist","tags":["align","alignment","approve","check","checklist","complete","doc","done","edit","editing","editor","format","list","mark","notes","ok","select","sheet","spreadsheet","text","tick","type","validate","verified","writing","yes"]},{"name":"view_in_ar","tags":["3d","ar","augmented","cube","daydream","headset","in","reality","square","view","vr"]},{"name":"undo","tags":["arrow","backward","mail","previous","redo","repeat","rotate","undo"]},{"name":"arrow_drop_up","tags":["app","application","arrow","components","direction","drop","interface","navigation","screen","site","ui","up","ux","web","website"]},{"name":"feedback","tags":["!","alert","announcement","attention","bubble","caution","chat","comment","communicate","danger","error","exclamation","feedback","important","mark","message","notification","speech","symbol","warning"]},{"name":"health_and_safety","tags":["+","add","and","certified","cross","health","home","nest","plus","privacy","private","protect","protection","safety","security","shield","symbol","verified"]},{"name":"work_outline","tags":["bag","baggage","briefcase","business","case","job","suitcase","work"]},{"name":"unfold_more","tags":["arrow","arrows","chevron","collapse","direction","down","expand","expandable","list","more","navigation","unfold"]},{"name":"travel_explore","tags":["earth","explore","find","glass","global","globe","look","magnify","magnifying","map","network","planet","search","see","social","space","travel","web","world"]},{"name":"palette","tags":["art","color","colors","filters","paint","palette"]},{"name":"keyboard_arrow_right","tags":["arrow","arrows","keyboard","right"]},{"name":"double_arrow","tags":["arrow","arrows","direction","double","multiple","navigation","right"]},{"name":"computer","tags":["Android","OS","chrome","computer","desktop","device","hardware","iOS","mac","monitor","web","window"]},{"name":"timeline","tags":["data","history","line","movement","point","points","timeline","tracking","trending","zigzag"]},{"name":"thumb_up_alt","tags":["agreed","approved","confirm","correct","favorite","feedback","good","happy","like","okay","positive","satisfaction","social","thumb","up","vote","yes"]},{"name":"signal_cellular_alt","tags":["alt","analytics","bar","cell","cellular","chart","data","diagram","graph","infographic","internet","measure","metrics","mobile","network","phone","signal","statistics","tracking","wifi","wireless"]},{"name":"replay","tags":["arrow","arrows","control","controls","music","refresh","renew","repeat","replay","video"]},{"name":"swap_horiz","tags":["arrow","arrows","back","forward","horizontal","swap"]},{"name":"volume_off","tags":["audio","control","disabled","enabled","low","music","off","on","slash","sound","speaker","tv","volume"]},{"name":"forum","tags":["bubble","chat","comment","communicate","community","conversation","feedback","forum","hub","message","speech"]},{"name":"skip_next","tags":["arrow","control","controls","music","next","play","previous","skip","video"]},{"name":"water_drop","tags":["drink","drop","droplet","eco","liquid","nature","ocean","rain","social","water"]},{"name":"assignment_turned_in","tags":["approve","assignment","check","clipboard","complete","doc","document","done","in","mark","ok","select","tick","turn","validate","verified","yes"]},{"name":"library_books","tags":["add","album","audio","book","books","collection","library","read","reading"]},{"name":"maps_home_work","tags":["building","home","house","maps","office","work"]},{"name":"dns","tags":["address","bars","dns","domain","information","ip","list","lookup","name","server","system"]},{"name":"sync_alt","tags":["alt","arrow","arrows","horizontal","internet","sync","technology","up","update","wifi"]},{"name":"how_to_reg","tags":["approve","ballot","check","complete","done","election","how","mark","ok","poll","register","registration","select","tick","to reg","validate","verified","vote","yes"]},{"name":"notifications_none","tags":["alarm","alert","bell","none","notifications","notify","reminder","sound"]},{"name":"stars","tags":["achievement","bookmark","circle","favorite","highlight","important","marked","ranking","rate","rating rank","reward","save","saved","shape","special","star"]},{"name":"flight_takeoff","tags":["airport","departed","departing","flight","fly","landing","plane","takeoff","transportation","travel"]},{"name":"label","tags":["favorite","indent","label","library","mail","remember","save","stamp","sticker","tag"]},{"name":"devices","tags":["Android","OS","computer","desktop","device","hardware","iOS","laptop","mobile","monitor","phone","tablet","watch","wearable","web"]},{"name":"chat_bubble","tags":["bubble","chat","comment","communicate","feedback","message","speech"]},{"name":"emoji_emotions","tags":["+","add","emoji","emotions","expressions","face","feelings","glad","happiness","happy","icon","icons","insert","like","mood","new","person","pleased","plus","smile","smiling","social","survey","symbol"]},{"name":"remove_red_eye","tags":["eye","iris","look","looking","preview","red","remove","see","sight","vision"]},{"name":"content_paste","tags":["clipboard","content","copy","cut","doc","document","file","multiple","past"]},{"name":"folder_open","tags":["data","doc","document","drive","file","folder","folders","open","sheet","slide","storage"]},{"name":"text_snippet","tags":["data","doc","document","file","note","notes","snippet","storage","text","writing"]},{"name":"tips_and_updates","tags":["ai","alert","and","announcement","artificial","automatic","automation","custom","electricity","genai","idea","info","information","intelligence","light","lightbulb","magic","smart","spark","sparkle","star","tips","updates"]},{"name":"my_location","tags":["destination","direction","location","maps","navigation","pin","place","point","stop"]},{"name":"textsms","tags":["bubble","chat","comment","communicate","dots","feedback","message","speech","textsms"]},{"name":"cloud","tags":["cloud","connection","internet","network","sky","upload"]},{"name":"sports_esports","tags":["controller","entertainment","esports","game","gamepad","gaming","hobby","online","social","sports","video"]},{"name":"security","tags":["certified","privacy","private","protect","protection","security","shield","verified"]},{"name":"request_quote","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","quote","request","shopping","symbol"]},{"name":"toggle_off","tags":["active","app","application","components","configuration","control","design","disable","inable","inactive","interface","off","on","selection","settings","site","slider","switch","toggle","ui","ux","web","website"]},{"name":"book","tags":["book","bookmark","favorite","label","library","read","reading","remember","ribbon","save","tag"]},{"name":"contact_page","tags":["account","avatar","contact","data","doc","document","drive","face","file","folder","folders","human","page","people","person","profile","sheet","slide","storage","user","writing"]},{"name":"speed","tags":["arrow","control","controls","fast","gauge","meter","motion","music","slow","speed","speedometer","velocity","video"]},{"name":"bug_report","tags":["animal","bug","fix","insect","issue","problem","report","testing","virus","warning"]},{"name":"space_dashboard","tags":["cards","dashboard","format","grid","layout","rectangle","shapes","space","squares","web","website"]},{"name":"fiber_manual_record","tags":["circle","dot","fiber","manual","play","record","watch"]},{"name":"report","tags":["!","alert","attention","caution","danger","error","exclamation","important","mark","notification","octagon","report","symbol","warning"]},{"name":"alarm","tags":["alarm","alert","bell","clock","countdown","date","notification","schedule","time"]},{"name":"cached","tags":["around","arrows","cache","cached","inprogress","load","loading refresh","renew","rotate"]},{"name":"translate","tags":["language","speaking","speech","translate","translator","words"]},{"name":"pan_tool","tags":["fingers","gesture","hand","hands","human","move","pan","scan","stop","tool"]},{"name":"gavel","tags":["agreement","contract","court","document","gavel","government","judge","law","mallet","official","police","rule","rules","terms"]},{"name":"settings_suggest","tags":["ai","artificial","automatic","automation","change","custom","details","gear","genai","intelligence","magic","options","recommendation","service","settings","smart","spark","sparkle","star","suggest","suggestion","system"]},{"name":"file_copy","tags":["content","copy","cut","doc","document","duplicate","file","multiple","past"]},{"name":"edit_calendar","tags":["calendar","compose","create","date","day","draft","edit","editing","event","month","pen","pencil","schedule","write","writing"]},{"name":"contact_mail","tags":["account","address","avatar","communicate","contact","email","face","human","info","information","mail","message","people","person","profile","user"]},{"name":"quiz","tags":["?","assistance","faq","help","info","information","punctuation","question mark","quiz","support","symbol","test"]},{"name":"supervised_user_circle","tags":["account","avatar","circle","control","face","human","parental","parents","people","person","profile","supervised","supervisor","user"]},{"name":"cloud_download","tags":["app","application","arrow","backup","cloud","connection","down","download","drive","files","folders","internet","network","sky","storage","upload"]},{"name":"stop","tags":["control","controls","music","pause","play","square","stop","video"]},{"name":"person_search","tags":["account","avatar","face","find","glass","human","look","magnify","magnifying","people","person","profile","search","user"]},{"name":"location_city","tags":["apartments","architecture","buildings","business","city","estate","home","landscape","location","place","real","residence","residential","shelter","town","urban"]},{"name":"sentiment_very_satisfied","tags":["emotions","expressions","face","feelings","glad","happiness","happy","like","mood","person","pleased","satisfied","sentiment","smile","smiling","survey","very"]},{"name":"ios_share","tags":["arrow","export","ios","send","share","up"]},{"name":"minimize","tags":["app","application","components","design","interface","line","minimize","screen","shape","site","ui","ux","web","website"]},{"name":"qr_code","tags":["barcode","camera","code","media","product","qr","quick","response","smartphone","url","urls"]},{"name":"sentiment_satisfied_alt","tags":["account","alt","emoji","face","happy","human","people","person","profile","satisfied","sentiment","smile","user"]},{"name":"local_mall","tags":["bag","bill","building","business","buy","card","cart","cash","coin","commerce","credit","currency","dollars","handbag","local","mall","money","online","pay","payment","shop","shopping","store","storefront"]},{"name":"qr_code_2","tags":["barcode","camera","code","media","product","qr","quick","response","smartphone","url","urls"]},{"name":"flight","tags":["air","airplane","airport","flight","plane","transportation","travel","trip"]},{"name":"desktop_windows","tags":["Android","OS","chrome","desktop","device","display","hardware","iOS","mac","monitor","screen","television","tv","web","window","windows"]},{"name":"music_note","tags":["audio","audiotrack","key","music","note","sound","track"]},{"name":"sentiment_satisfied","tags":["emotions","expressions","face","feelings","glad","happiness","happy","like","mood","person","pleased","satisfied","sentiment","smile","smiling","survey"]},{"name":"android","tags":["android","character","logo","mascot","toy"]},{"name":"accessibility","tags":["accessibility","accessible","body","handicap","help","human","people","person"]},{"name":"backspace","tags":["arrow","back","backspace","cancel","clear","correct","delete","erase","remove"]},{"name":"precision_manufacturing","tags":["arm","automatic","chain","conveyor","crane","factory","industry","machinery","manufacturing","mechanical","precision","production","repairing","robot","supply","warehouse"]},{"name":"drag_handle","tags":["app","application ui","components","design","drag","handle","interface","layout","menu","move","screen","site","ui","ux","web","website","window"]},{"name":"smart_display","tags":["airplay","cast","chrome","connect","device","display","play","screen","screencast","smart","stream","television","tv","video","wireless"]},{"name":"near_me","tags":["destination","direction","location","maps","me","navigation","near","pin","place","point","stop"]},{"name":"west","tags":["arrow","directional","left","maps","navigation","west"]},{"name":"get_app","tags":["app","arrow","arrows","down","download","downloads","export","get","install","play","upload"]},{"name":"person_add_alt","tags":["+","account","add","face","human","people","person","plus","profile","user"]},{"name":"fitness_center","tags":["athlete","center","dumbbell","exercise","fitness","gym","hobby","places","sport","weights","workout"]},{"name":"shield","tags":["certified","privacy","private","protect","protection","security","shield","verified"]},{"name":"message","tags":["bubble","chat","comment","communicate","feedback","message","speech"]},{"name":"rocket_launch","tags":["launch","rocket","space","spaceship","takeoff"]},{"name":"record_voice_over","tags":["account","face","human","over","people","person","profile","record","recording","speak","speaking","speech","transcript","user","voice"]},{"name":"add_task","tags":["+","add","approve","check","circle","completed","increase","mark","ok","plus","select","task","tick","yes"]},{"name":"drive_file_rename_outline","tags":["compose","create","draft","drive","edit","editing","file","input","marker","pen","pencil","rename","write","writing"]},{"name":"insert_drive_file","tags":["doc","drive","file","format","insert","sheet","slide"]},{"name":"question_mark","tags":["?","assistance","help","info","information","punctuation","question mark","support","symbol"]},{"name":"trending_flat","tags":["arrow","change","data","flat","metric","movement","rate","right","track","tracking","trending"]},{"name":"handyman","tags":["build","construction","fix","hammer","handyman","repair","screw","screwdriver","tools"]},{"name":"emoji_objects","tags":["bulb","creative","emoji","idea","light","objects","solution","thinking"]},{"name":"military_tech","tags":["army","award","badge","honor","medal","merit","military","order","privilege","prize","rank","reward","ribbon","soldier","star","status","tech","trophy","win","winner"]},{"name":"hourglass_empty","tags":["countdown","empty","hourglass","loading","minutes","time","wait","waiting"]},{"name":"help_center","tags":["?","assistance","center","help","info","information","punctuation","question mark","recent","restore","support","symbol"]},{"name":"science","tags":["beaker","chemical","chemistry","experiment","flask","glass","laboratory","research","science","tube"]},{"name":"storage","tags":["computer","data","drive","memory","storage"]},{"name":"movie","tags":["cinema","film","media","movie","slate","video"]},{"name":"accessibility_new","tags":["accessibility","accessible","body","handicap","help","human","new","people","person"]},{"name":"workspace_premium","tags":["certification","degree","ecommerce","guarantee","medal","permit","premium","ribbon","verification","workspace"]},{"name":"directions_run","tags":["body","directions","human","jogging","maps","people","person","route","run","running","walk"]},{"name":"rule","tags":["approve","check","complete","done","incomplete","line","mark","missing","no","ok","rule","select","tick","validate","verified","wrong","x","yes"]},{"name":"thumb_down","tags":["ate","dislike","down","favorite","fingers","gesture","hand","hands","like","rank","ranking","rating","thumb"]},{"name":"event_note","tags":["calendar","date","event","note","schedule","text","time","writing"]},{"name":"contacts","tags":["account","avatar","call","cell","contacts","face","human","info","information","mobile","people","person","phone","profile","user"]},{"name":"comment","tags":["bubble","chat","comment","communicate","feedback","message","outline","speech"]},{"name":"restaurant_menu","tags":["book","dining","eat","food","fork","knife","local","meal","menu","restaurant","spoon"]},{"name":"add_photo_alternate","tags":["+","add","alternate","image","landscape","mountain","mountains","new","photo","photography","picture","plus","symbol"]},{"name":"confirmation_number","tags":["admission","confirmation","entertainment","event","number","ticket"]},{"name":"sticky_note_2","tags":["2","bookmark","mark","message","note","paper","sticky","text","writing"]},{"name":"format_quote","tags":["doc","edit","editing","editor","format","quotation","quote","sheet","spreadsheet","text","type","writing"]},{"name":"history_edu","tags":["document","edu","education","feather","history","letter","paper","pen","quill","school","story","tools","write","writing"]},{"name":"business_center","tags":["bag","baggage","briefcase","business","case","center","places","purse","suitcase","work"]},{"name":"upload","tags":["arrow","arrows","download","drive","up","upload"]},{"name":"skip_previous","tags":["arrow","control","controls","music","next","play","previous","skip","video"]},{"name":"archive","tags":["archive","inbox","mail","store"]},{"name":"wb_sunny","tags":["balance","bright","light","lighting","sun","sunny","wb","white"]},{"name":"cake","tags":["add","baked","birthday","cake","candles","celebration","dessert","food","frosting","new","party","pastries","pastry","plus","social","sweet","symbol"]},{"name":"attachment","tags":["attach","attachment","clip","compose","file","image","link"]},{"name":"source","tags":["code","composer","content","creation","data","doc","document","file","folder","mode","source","storage","view"]},{"name":"settings_applications","tags":["application","change","details","gear","info","information","options","personal","service","settings"]},{"name":"dashboard_customize","tags":["cards","customize","dashboard","format","layout","rectangle","shapes","square","web","website"]},{"name":"find_in_page","tags":["data","doc","document","drive","file","find","folder","folders","glass","in","look","magnify","magnifying","page","paper","search","see","sheet","slide","writing"]},{"name":"support","tags":["assist","buoy","help","life","lifebuoy","rescue","safe","safety","support"]},{"name":"ads_click","tags":["ads","browser","click","clicks","cursor","internet","target","traffic","web"]},{"name":"new_releases","tags":["approve","award","check","checkmark","complete","done","new","notification","ok","release","releases","select","star","symbol","tick","verification","verified","warning","yes"]},{"name":"flutter_dash","tags":["bird","dash","flutter","mascot"]},{"name":"playlist_add","tags":["+","add","collection","list","music","new","playlist","plus","symbol"]},{"name":"save_alt","tags":["alt","arrow","disk","document","down","file","floppy","multimedia","save"]},{"name":"close_fullscreen","tags":["action","arrow","arrows","close","collapse","direction","full","fullscreen","minimize","screen"]},{"name":"credit_score","tags":["approve","bill","card","cash","check","coin","commerce","complete","cost","credit","currency","dollars","done","finance","loan","mark","money","ok","online","pay","payment","score","select","symbol","tick","validate","verified","yes"]},{"name":"layers","tags":["arrange","disabled","enabled","interaction","layers","maps","off","on","overlay","pages","slash"]},{"name":"redeem","tags":["bill","card","cart","cash","certificate","coin","commerce","credit","currency","dollars","gift","giftcard","money","online","pay","payment","present","redeem","shopping"]},{"name":"spa","tags":["aromatherapy","flower","healthcare","leaf","massage","meditation","nature","petals","places","relax","spa","wellbeing","wellness"]},{"name":"announcement","tags":["!","alert","announcement","attention","bubble","caution","chat","comment","communicate","danger","error","exclamation","feedback","important","mark","message","notification","speech","symbol","warning"]},{"name":"keyboard_backspace","tags":["arrow","back","backspace","keyboard","left"]},{"name":"loyalty","tags":["benefits","card","credit","heart","loyalty","membership","miles","points","program","subscription","tag","travel","trip"]},{"name":"swap_vert","tags":["arrow","arrows","direction","down","navigation","swap","up","vert","vertical"]},{"name":"sentiment_dissatisfied","tags":["angry","disappointed","dislike","dissatisfied","emotions","expressions","face","feelings","frown","mood","person","sad","sentiment","survey","unhappy","unsatisfied","upset"]},{"name":"medical_services","tags":["aid","bag","briefcase","emergency","first","kit","medical","medicine","services"]},{"name":"view_headline","tags":["design","format","grid","headline","layout","paragraph","text","view","website"]},{"name":"arrow_circle_right","tags":["arrow","circle","direction","navigation","right"]},{"name":"format_list_numbered","tags":["align","alignment","digit","doc","edit","editing","editor","format","list","notes","number","numbered","sheet","spreadsheet","symbol","text","type","writing"]},{"name":"phone_android","tags":["OS","android","cell","device","hardware","iOS","mobile","phone","tablet"]},{"name":"sms","tags":["3","bubble","chat","communication","conversation","dots","message","more","service","sms","speech","three"]},{"name":"restore","tags":["arrow","back","backwards","clock","date","history","refresh","renew","restore","reverse","rotate","schedule","time","turn"]},{"name":"policy","tags":["certified","find","glass","legal","look","magnify","magnifying","policy","privacy","private","protect","protection","search","security","see","shield","verified"]},{"name":"dangerous","tags":["broken","danger","dangerous","fix","no","sign","stop","update","warning","wrong","x"]},{"name":"battery_full","tags":["battery","cell","charge","full","mobile","power"]},{"name":"euro_symbol","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","euro","finance","money","online","pay","payment","symbol"]},{"name":"query_stats","tags":["analytics","chart","data","diagram","find","glass","graph","infographic","line","look","magnify","magnifying","measure","metrics","query","search","see","statistics","stats","tracking"]},{"name":"group_work","tags":["alliance","collaboration","group","partnership","team","teamwork","together","work"]},{"name":"expand_circle_down","tags":["arrow","arrows","chevron","circle","collapse","direction","down","expand","expandable","list","more"]},{"name":"sensors","tags":["connection","network","scan","sensors","signal","wireless"]},{"name":"keyboard_arrow_up","tags":["arrow","arrows","keyboard","up"]},{"name":"brush","tags":["art","brush","design","draw","edit","editing","paint","painting","tool"]},{"name":"meeting_room","tags":["building","door","doorway","entrance","home","house","interior","meeting","office","open","places","room"]},{"name":"key","tags":["key","lock","password","unlock"]},{"name":"house","tags":["architecture","building","estate","family","home","homepage","house","place","places","real","residence","residential","shelter"]},{"name":"lunch_dining","tags":["breakfast","dining","dinner","drink","fastfood","food","hamburger","lunch","meal"]},{"name":"table_chart","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic grid","measure","metrics","statistics","table","tracking"]},{"name":"border_color","tags":["all","border","doc","edit","editing","editor","pen","pencil","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"compare_arrows","tags":["arrow","arrows","collide","compare","direction","left","pressure","push","right","together"]},{"name":"south","tags":["arrow","directional","down","maps","navigation","south"]},{"name":"directions_walk","tags":["body","direction","directions","human","jogging","maps","people","person","route","run","walk"]},{"name":"arrow_left","tags":["app","application","arrow","components","direction","interface","left","navigation","screen","site","ui","ux","web","website"]},{"name":"tag","tags":["hash","hashtag","key","media","number","pound","social","tag","trend"]},{"name":"change_circle","tags":["around","arrows","change","circle","direction","navigation","rotate"]},{"name":"subject","tags":["alignment","doc","document","email","full","justify","list","note","subject","text","writing"]},{"name":"sentiment_very_dissatisfied","tags":["angry","disappointed","dislike","dissatisfied","emotions","expressions","face","feelings","mood","person","sad","sentiment","sorrow","survey","unhappy","unsatisfied","upset","very"]},{"name":"local_hospital","tags":["911","aid","cross","emergency","first","hospital","local","medicine"]},{"name":"table_view","tags":["format","grid","group","layout","multiple","table","view"]},{"name":"disabled_by_default","tags":["box","by","cancel","close","default","disabled","exit","no","quit","remove","square","stop","x"]},{"name":"notification_important","tags":["!","active","alarm","alert","attention","bell","caution","chime","danger","error","exclamation","important","mark","notification","notifications","notify","reminder","ring","sound","symbol","warning"]},{"name":"celebration","tags":["activity","birthday","celebration","event","fun","party"]},{"name":"laptop","tags":["Android","OS","chrome","computer","desktop","device","hardware","iOS","laptop","mac","monitor","web","windows"]},{"name":"loop","tags":["around","arrow","arrows","direction","inprogress","load","loading refresh","loop","music","navigation","renew","rotate","turn"]},{"name":"nightlight_round","tags":["dark","half","light","mode","moon","night","nightlight","round"]},{"name":"privacy_tip","tags":["alert","announcement","assistance","certified","details","help","i","info","information","privacy","private","protect","protection","security","service","shield","support","tip","verified"]},{"name":"import_contacts","tags":["address","book","contacts","import","info","information","open"]},{"name":"equalizer","tags":["adjustment","analytics","chart","data","equalizer","graph","measure","metrics","music","noise","sound","static","statistics","tracking","volume"]},{"name":"app_registration","tags":["app","apps","edit","pencil","register","registration"]},{"name":"keyboard_double_arrow_right","tags":["arrow","arrows","direction","double","multiple","navigation","right"]},{"name":"handshake","tags":["agreement","hand","hands","partnership","shake"]},{"name":"corporate_fare","tags":["architecture","building","business","corporate","estate","fare","organization","place","real","residence","residential","shelter"]},{"name":"local_library","tags":["book","community learning","library","local","read"]},{"name":"https","tags":["https","lock","locked","password","privacy","private","protection","safety","secure","security"]},{"name":"euro","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","euro","euros","finance","money","online","pay","payment","price","shopping","symbol"]},{"name":"coronavirus","tags":["19","bacteria","coronavirus","covid","disease","germs","illness","sick","social"]},{"name":"price_check","tags":["approve","bill","card","cash","check","coin","commerce","complete","cost","credit","currency","dollars","done","finance","mark","money","ok","online","pay","payment","price","select","shopping","symbol","tick","validate","verified","yes"]},{"name":"live_tv","tags":["Android","OS","antennas hardware","chrome","desktop","device","iOS","live","mac","monitor","movie","play","stream","television","tv","web","window"]},{"name":"park","tags":["attraction","fresh","local","nature","outside","park","plant","tree"]},{"name":"toc","tags":["content","format","lines","list","order","reorder","stacked","table","title","titles","toc"]},{"name":"track_changes","tags":["bullseye","changes","circle","evolve","lines","movement","rotate","shift","target","track"]},{"name":"arrow_circle_up","tags":["arrow","circle","direction","navigation","up"]},{"name":"emoji_people","tags":["arm","body","emoji","greeting","human","people","person","social","waving"]},{"name":"flash_on","tags":["bolt","disabled","electric","enabled","fast","flash","lightning","off","on","slash","thunderbolt"]},{"name":"copyright","tags":["alphabet","c","character","copyright","emblem","font","legal","letter","owner","symbol","text"]},{"name":"bookmarks","tags":["bookmark","bookmarks","favorite","label","layers","library","multiple","read","reading","remember","ribbon","save","stack","tag"]},{"name":"ac_unit","tags":["ac","air","cold","conditioner","flake","snow","temperature","unit","weather","winter"]},{"name":"contact_phone","tags":["account","avatar","call","communicate","contact","face","human","info","information","message","mobile","people","person","phone","profile","user"]},{"name":"keyboard_arrow_left","tags":["arrow","arrows","keyboard","left"]},{"name":"medication","tags":["doctor","drug","emergency","hospital","medication","medicine","pharmacy","pills","prescription"]},{"name":"grading","tags":["'favorite'_new'. ' Remove this icon & keep 'star'.","'star_boarder'","'star_border_purple500'","'star_outline'","'star_purple500'","'star_rate'","Same as 'star'"]},{"name":"keyboard_return","tags":["arrow","back","keyboard","left","return"]},{"name":"api","tags":["api","developer","development","enterprise","software"]},{"name":"smart_toy","tags":["bot","droid","games","robot","smart","toy"]},{"name":"input","tags":["arrow","box","download","input","login","move","right"]},{"name":"self_improvement","tags":["body","calm","care","chi","human","improvement","meditate","meditation","people","person","relax","self","sitting","wellbeing","yoga","zen"]},{"name":"live_help","tags":["?","assistance","bubble","chat","comment","communicate","help","info","information","live","message","punctuation","question mark","recent","restore","speech","support","symbol"]},{"name":"query_builder","tags":["builder","clock","date","query","schedule","time"]},{"name":"perm_media","tags":["collection","data","doc","document","file","folder","folders","image","landscape","media","mountain","mountains","perm","photo","photography","picture","storage"]},{"name":"download_for_offline","tags":["arrow","circle","down","download","for offline","install","upload"]},{"name":"view_module","tags":["design","format","grid","layout","module","square","squares","stacked","view","website"]},{"name":"pin","tags":["1","2","3","digit","key","login","logout","number","password","pattern","pin","security","star","symbol","unlock"]},{"name":"fast_forward","tags":["control","fast","forward","media","music","play","speed","time","tv","video"]},{"name":"forward_to_inbox","tags":["arrow","arrows","directions","email","envelop","forward","inbox","letter","mail","message","navigation","outgoing","right","send","to"]},{"name":"person_remove","tags":["account","avatar","delete","face","human","minus","people","person","profile","remove","unfriend","user"]},{"name":"local_atm","tags":["atm","bill","card","cart","cash","coin","commerce","credit","currency","dollars","local","money","online","pay","payment","shopping","symbol"]},{"name":"star_half","tags":["achievement","bookmark","favorite","half","highlight","important","marked","ranking","rate","rating rank","reward","save","saved","shape","special","star","toggle"]},{"name":"build_circle","tags":["adjust","build","circle","fix","repair","tool","wrench"]},{"name":"redo","tags":["arrow","backward","forward","next","redo","repeat","rotate","undo"]},{"name":"web","tags":["browser","internet","page","screen","site","web","website","www"]},{"name":"north_east","tags":["arrow","east","maps","navigation","noth","right","up"]},{"name":"north","tags":["arrow","directional","maps","navigation","north","up"]},{"name":"cottage","tags":["architecture","beach","cottage","estate","home","house","lake","lodge","maps","place","real","residence","residential","stay","traveling"]},{"name":"local_activity","tags":["activity","event","event ticket","local","star","things","ticket"]},{"name":"currency_exchange","tags":["360","around","arrow","arrows","cash","coin","commerce","currency","direction","dollars","exchange","inprogress","money","pay","renew","rotate","sync","turn","universal"]},{"name":"video_library","tags":["arrow","collection","library","play","video"]},{"name":"hourglass_bottom","tags":["bottom","countdown","half","hourglass","loading","minute","minutes","time","wait","waiting"]},{"name":"headphones","tags":["accessory","audio","device","ear","earphone","headphones","headset","listen","music","sound"]},{"name":"zoom_out","tags":["find","glass","look","magnify","magnifying","minus","negative","out","scale","search","see","size","small","smaller","zoom"]},{"name":"poll","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","poll","statistics","survey","tracking","vote"]},{"name":"perm_contact_calendar","tags":["account","calendar","contact","date","face","human","information","people","perm","person","profile","schedule","time","user"]},{"name":"forward","tags":["arrow","forward","mail","message","playback","right","sent"]},{"name":"person_pin","tags":["account","avatar","destination","direction","face","human","location","maps","people","person","pin","place","profile","stop","user"]},{"name":"home_work","tags":["architecture","building","estate","home","place","real","residence","residential","shelter","work"]},{"name":"playlist_add_check","tags":["add","approve","check","collection","complete","done","list","mark","music","ok","playlist","select","tick","validate","verified","yes"]},{"name":"local_cafe","tags":["bottle","cafe","coffee","cup","drink","food","restaurant","tea"]},{"name":"ondemand_video","tags":["Android","OS","chrome","demand","desktop","device","hardware","iOS","mac","monitor","ondemand","play","television","tv","video","web","window"]},{"name":"design_services","tags":["compose","create","design","draft","edit","editing","input","pen","pencil","ruler","service","write","writing"]},{"name":"looks_one","tags":["1","digit","looks","numbers","square","symbol"]},{"name":"backup","tags":["arrow","backup","cloud","data","drive","files folders","storage","up","upload"]},{"name":"newspaper","tags":["article","data","doc","document","drive","file","folder","folders","magazine","media","news","newspaper","notes","page","paper","sheet","slide","text","writing"]},{"name":"memory","tags":["card","chip","digital","memory","micro","processor","sd","storage"]},{"name":"open_with","tags":["arrow","arrows","direction","expand","move","open","pan","with"]},{"name":"content_cut","tags":["content","copy","cut","doc","document","file","past","scissors","trim"]},{"name":"keyboard","tags":["computer","device","hardware","input","keyboard","keypad","letter","office","text","type"]},{"name":"hourglass_top","tags":["countdown","half","hourglass","loading","minute","minutes","time","top","wait","waiting"]},{"name":"settings_phone","tags":["call","cell","contact","device","hardware","mobile","phone","settings","telephone"]},{"name":"rss_feed","tags":["application","blog","connection","data","feed","internet","network","rss","service","signal","website","wifi","wireless"]},{"name":"first_page","tags":["arrow","back","chevron","first","left","page","rewind"]},{"name":"delivery_dining","tags":["delivery","dining","food","meal","restaurant","scooter","takeout","transportation","vehicle","vespa"]},{"name":"rate_review","tags":["comment","feedback","pen","pencil","rate","review","stars","write"]},{"name":"control_point","tags":["+","add","circle","control","plus","point"]},{"name":"gpp_good","tags":["certified","check","good","gpp","ok","pass","security","shield","sim","tick"]},{"name":"circle_notifications","tags":["active","alarm","alert","bell","chime","circle","notifications","notify","reminder","ring","sound"]},{"name":"auto_fix_high","tags":["adjust","ai","artificial","auto","automatic","automation","custom","edit","editing","enhance","erase","fix","genai","high","intelligence","magic","modify","pen","smart","spark","sparkle","star","tool","wand"]},{"name":"book_online","tags":["Android","OS","admission","appointment","book","cell","device","event","hardware","iOS","mobile","online","pass","phone","reservation","tablet","ticket"]},{"name":"notes","tags":["comment","doc","document","note","notes","text","write","writing"]},{"name":"point_of_sale","tags":["checkout","cost","machine","merchant","money","of","pay","payment","point","pos","retail","sale","system","transaction"]},{"name":"perm_phone_msg","tags":["bubble","call","cell","chat","comment","communicate","contact","device","message","msg","perm","phone","recording","speech","telephone","voice"]},{"name":"speaker_notes","tags":["bubble","chat","comment","communicate","format","list","message","notes","speaker","speech","text"]},{"name":"fullscreen_exit","tags":["adjust","app","application","components","exit","full","fullscreen","interface","screen","site","size","ui","ux","view","web","website"]},{"name":"headset_mic","tags":["accessory","audio","chat","device","ear","earphone","headphones","headset","listen","mic","music","sound","talk"]},{"name":"create_new_folder","tags":["+","add","create","data","doc","document","drive","file","folder","new","plus","sheet","slide","storage","symbol"]},{"name":"wysiwyg","tags":["composer","mode","screen","site","software","system","text","view","visibility","web","website","window","wysiwyg"]},{"name":"label_important","tags":["favorite","important","indent","label","library","mail","remember","save","stamp","sticker","tag","wing"]},{"name":"card_membership","tags":["bill","bookmark","card","cash","certificate","coin","commerce","cost","credit","currency","dollars","finance","loyalty","membership","money","online","pay","payment","shopping","subscription"]},{"name":"style","tags":["booklet","cards","filters","options","style","tags"]},{"name":"arrow_circle_down","tags":["arrow","circle","direction","down","navigation"]},{"name":"file_present","tags":["clip","data","doc","document","drive","file","folder","folders","note","paper","present","reminder","sheet","slide","storage","writing"]},{"name":"directions_bus","tags":["automobile","bus","car","cars","directions","maps","public","transportation","vehicle"]},{"name":"whatshot","tags":["arrow","circle","direction","fire","frames","hot","round","whatshot"]},{"name":"sports_soccer","tags":["athlete","athletic","ball","entertainment","exercise","football","game","hobby","soccer","social","sports"]},{"name":"indeterminate_check_box","tags":["app","application","box","button","check","components","control","design","form","indeterminate","interface","screen","select","selected","selection","site","square","toggle","ui","undetermined","ux","web","website"]},{"name":"outlined_flag","tags":["country","flag","goal","mark","nation","outlined","report","start"]},{"name":"price_change","tags":["arrows","bill","card","cash","change","coin","commerce","cost","credit","currency","dollars","down","finance","money","online","pay","payment","price","shopping","symbol","up"]},{"name":"mark_email_read","tags":["approve","check","complete","done","email","envelop","letter","mail","mark","message","note","ok","read","select","send","sent","tick","yes"]},{"name":"library_add","tags":["+","add","collection","layers","library","multiple","music","new","plus","stacked","symbol","video"]},{"name":"pageview","tags":["doc","document","find","glass","magnifying","page","paper","search","view"]},{"name":"tv","tags":["device","display","monitor","screen","screencast","stream","television","tv","video","wireless"]},{"name":"inbox","tags":["archive","email","inbox","incoming","mail","message"]},{"name":"adjust","tags":["adjust","alter","center","circle","circles","dot","fix","image","move","target"]},{"name":"3d_rotation","tags":["3","3d","D","alphabet","arrow","arrows","av","camera","character","digit","font","letter","number","rotation","symbol","text","type","vr"]},{"name":"battery_charging_full","tags":["battery","bolt","cell","charge","charging","full","lightening","mobile","power","thunderbolt"]},{"name":"chair","tags":["chair","comfort","couch","decoration","furniture","home","house","living","lounging","loveseat","room","seat","seating","sofa"]},{"name":"directions_bike","tags":["bicycle","bike","direction","directions","human","maps","person","public","route","transportation"]},{"name":"mic_off","tags":["audio","disabled","enabled","hear","hearing","mic","microphone","noise","off","on","record","recording","slash","sound","voice"]},{"name":"local_police","tags":["911","badge","law","local","officer","police","protect","protection","security","shield"]},{"name":"fastfood","tags":["drink","fastfood","food","hamburger","maps","meal","places"]},{"name":"tungsten","tags":["electricity","indoor","lamp","light","lightbulb","setting","tungsten"]},{"name":"mood","tags":["emoji","emotions","expressions","face","feelings","glad","happiness","happy","like","mood","person","pleased","smile","smiling","social","survey"]},{"name":"pause_circle","tags":["circle","control","controls","media","music","pause","video"]},{"name":"upgrade","tags":["arrow","export","instal","line","replace","up","update","upgrade"]},{"name":"recommend","tags":["approved","circle","confirm","favorite","gesture","hand","like","reaction","recommend","social","support","thumbs","up","well"]},{"name":"directions_car_filled","tags":["automobile","car","cars","direction","directions","filled","maps","public","transportation","vehicle"]},{"name":"fmd_good","tags":["destination","direction","fmd","good","location","maps","pin","place","stop"]},{"name":"integration_instructions","tags":["brackets","clipboard","code","css","develop","developer","doc","document","engineer","engineering clipboard","html","instructions","integration","platform"]},{"name":"format_bold","tags":["B","alphabet","bold","character","doc","edit","editing","editor","font","format","letter","sheet","spreadsheet","styles","symbol","text","type","writing"]},{"name":"people_outline","tags":["accounts","committee","face","family","friends","humans","network","outline","people","persons","profiles","social","team","users"]},{"name":"trending_down","tags":["analytics","arrow","data","diagram","down","graph","infographic","measure","metrics","movement","rate","rating","statistics","tracking","trending"]},{"name":"change_history","tags":["change","history","shape","triangle"]},{"name":"female","tags":["female","gender","girl","lady","social","symbol","woman","women"]},{"name":"link_off","tags":["attached","chain","clip","connection","disabled","enabled","link","linked","links","multimedia","off","on","slash","url"]},{"name":"text_fields","tags":["T","add","alphabet","character","field","fields","font","input","letter","symbol","text","type"]},{"name":"swipe","tags":["arrow","arrows","fingers","gesture","hand","hands","swipe","touch"]},{"name":"reviews","tags":["bubble","chat","comment","communicate","feedback","message","rate","rating","recommendation","reviews","speech"]},{"name":"home_repair_service","tags":["box","equipment","fix","home","kit","mechanic","repair","repairing","service","tool","toolbox","tools","workshop"]},{"name":"subscriptions","tags":["enroll","list","media","order","play","signup","subscribe","subscriptions"]},{"name":"video_call","tags":["+","add","call","camera","chat","conference","film","filming","hardware","image","motion","new","picture","plus","symbol","video","videography"]},{"name":"zoom_out_map","tags":["arrow","arrows","destination","location","maps","move","out","place","stop","zoom"]},{"name":"straighten","tags":["length","measure","measurement","ruler","size","straighten"]},{"name":"arrow_drop_down_circle","tags":["app","application","arrow","circle","components","direction","down","drop","interface","navigation","screen","site","ui","ux","web","website"]},{"name":"bed","tags":["bed","bedroom","double","full","furniture","home","hotel","house","king","night","pillows","queen","rest","room","size","sleep"]},{"name":"drive_eta","tags":["automobile","car","cars","destination","direction","drive","estimate","eta","maps","public","transportation","travel","trip","vehicle"]},{"name":"class","tags":["archive","book","bookmark","class","favorite","label","library","read","reading","remember","ribbon","save","tag"]},{"name":"drafts","tags":["document","draft","drafts","email","file","letter","mail","message","read"]},{"name":"ballot","tags":["ballot","bullet","election","list","point","poll","vote"]},{"name":"volume_mute","tags":["audio","control","music","mute","sound","speaker","tv","volume"]},{"name":"table_rows","tags":["grid","layout","lines","rows","stacked","table"]},{"name":"accessible","tags":["accessibility","accessible","body","handicap","help","human","people","person","wheelchair"]},{"name":"stop_circle","tags":["circle","control","controls","music","pause","play","square","stop","video"]},{"name":"family_restroom","tags":["bathroom","child","children","family","father","kids","mother","parents","restroom","wc"]},{"name":"title","tags":["T","alphabet","character","font","header","letter","subject","symbol","text","title","type"]},{"name":"biotech","tags":["biotech","chemistry","laboratory","microscope","research","science","technology"]},{"name":"insert_emoticon","tags":["account","emoji","emoticon","face","happy","human","insert","people","person","profile","sentiment","smile","user"]},{"name":"g_translate","tags":["emblem","g","google","language","logo","mark","speaking","speech","translate","translator","words"]},{"name":"last_page","tags":["app","application","arrow","chevron","components","end","forward","interface","last","page","right","screen","site","ui","ux","web","website"]},{"name":"publish","tags":["arrow","cloud","file","import","publish","up","upload"]},{"name":"repeat","tags":["arrow","arrows","control","controls","media","music","repeat","video"]},{"name":"checklist_rtl","tags":["align","alignment","approve","check","checklist","complete","doc","done","edit","editing","editor","format","list","mark","notes","ok","rtl","select","sheet","spreadsheet","text","tick","type","validate","verified","writing","yes"]},{"name":"wifi_off","tags":["connection","data","disabled","enabled","internet","network","off","offline","on","scan","service","signal","slash","wifi","wireless"]},{"name":"settings_accessibility","tags":["accessibility","body","details","human","information","people","person","personal","preferences","profile","settings","user"]},{"name":"percent","tags":["math","number","percent","symbol"]},{"name":"insert_photo","tags":["image","insert","landscape","mountain","mountains","photo","photography","picture"]},{"name":"hotel","tags":["body","hotel","human","people","person","sleep","stay","travel","trip"]},{"name":"cleaning_services","tags":["clean","cleaning","dust","services","sweep"]},{"name":"downloading","tags":["arrow","circle","down","download","downloading","downloads","install","pending","progress","upload"]},{"name":"expand","tags":["arrow","arrows","compress","enlarge","expand","grow","move","push","together"]},{"name":"local_phone","tags":["booth","call","communication","phone","telecommunication"]},{"name":"offline_bolt","tags":["bolt","circle","electric","fast","lightning","offline","thunderbolt"]},{"name":"auto_graph","tags":["analytics","auto","chart","data","diagram","graph","infographic","line","measure","metrics","stars","statistics","tracking"]},{"name":"local_grocery_store","tags":["grocery","market","shop","store"]},{"name":"photo_library","tags":["album","image","library","mountain","mountains","photo","photography","picture"]},{"name":"miscellaneous_services","tags":[]},{"name":"note_alt","tags":["alt","clipboard","document","file","memo","note","page","paper","writing"]},{"name":"settings_backup_restore","tags":["arrow","back","backup","backwards","refresh","restore","reverse","rotate","settings"]},{"name":"production_quantity_limits","tags":["!","alert","attention","bill","card","cart","cash","caution","coin","commerce","credit","currency","danger","dollars","error","exclamation","important","limits","mark","money","notification","online","pay","payment","production","quantity","shopping","symbol","warning"]},{"name":"person_off","tags":["account","avatar","disabled","enabled","face","human","off","on","people","person","profile","slash","user"]},{"name":"report_gmailerrorred","tags":["!","alert","attention","caution","danger","error","exclamation","gmail","gmailerrorred","important","mark","notification","octagon","report","symbol","warning"]},{"name":"camera","tags":["aperture","camera","lens","photo","photography","picture","shutter"]},{"name":"recycling","tags":["bio","eco","green","loop","recyclable","recycle","recycling","rotate","sustainability","sustainable","trash"]},{"name":"male","tags":["boy","gender","male","man","social","symbol"]},{"name":"not_interested","tags":["cancel","close","dislike","exit","interested","no","not","off","quit","remove","stop","x"]},{"name":"event_busy","tags":["busy","calendar","cancel","close","date","event","exit","no","remove","schedule","stop","time","unavailable","x"]},{"name":"arrow_circle_left","tags":["arrow","circle","direction","left","navigation"]},{"name":"shuffle","tags":["arrow","arrows","control","controls","music","random","shuffle","video"]},{"name":"aspect_ratio","tags":["aspect","expand","image","ratio","resize","scale","size","square"]},{"name":"other_houses","tags":["architecture","cottage","estate","home","house","houses","maps","other","place","real","residence","residential","stay","traveling"]},{"name":"model_training","tags":["arrow","bulb","idea","inprogress","light","load","loading","model","refresh","renew","restore","reverse","rotate","training"]},{"name":"unfold_less","tags":["arrow","arrows","chevron","collapse","direction","expand","expandable","inward","less","list","navigation","unfold","up"]},{"name":"insert_chart_outlined","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","insert","measure","metrics","outlined","statistics","tracking"]},{"name":"donut_large","tags":["analytics","chart","data","diagram","donut","graph","infographic","inprogress","large","measure","metrics","pie","statistics","tracking"]},{"name":"view_column","tags":["column","design","format","grid","layout","vertical","view","website"]},{"name":"segment","tags":["alignment","fonts","format","lines","list","paragraph","part","piece","rule","rules","segment","style","text"]},{"name":"checkroom","tags":["checkroom","closet","clothes","coat check","hanger"]},{"name":"mode","tags":["compose","create","draft","draw","edit","mode","pen","pencil","write"]},{"name":"portrait","tags":["account","face","human","people","person","photo","picture","portrait","profile","user"]},{"name":"camera_alt","tags":["alt","camera","image","photo","photography","picture"]},{"name":"keyboard_double_arrow_left","tags":["arrow","arrows","direction","double","left","multiple","navigation"]},{"name":"delete_sweep","tags":["bin","can","delete","garbage","remove","sweep","trash"]},{"name":"hub","tags":["center","connection","core","focal point","hub","network","nucleus","topology"]},{"name":"audiotrack","tags":["audio","audiotrack","key","music","note","sound","track"]},{"name":"calendar_view_month","tags":["calendar","date","day","event","format","grid","layout","month","schedule","today","view"]},{"name":"draw","tags":["compose","create","design","draft","draw","edit","editing","input","pen","pencil","write","writing"]},{"name":"navigation","tags":["destination","direction","location","maps","navigation","pin","place","point","stop"]},{"name":"folder_shared","tags":["account","collaboration","data","doc","document","drive","face","file","folder","human","people","person","profile","share","shared","sheet","slide","storage","team","user"]},{"name":"read_more","tags":["arrow","more","read","text"]},{"name":"stacked_bar_chart","tags":["analytics","bar","chart-chart","data","diagram","graph","infographic","measure","metrics","stacked","statistics","tracking"]},{"name":"mode_comment","tags":["bubble","chat","comment","communicate","feedback","message","mode comment","speech"]},{"name":"schedule_send","tags":["calendar","clock","date","email","letter","mail","remember","schedule","send","share","time"]},{"name":"bluetooth","tags":["bluetooth","cast","connect","connection","device","paring","streaming","symbol","wireless"]},{"name":"graphic_eq","tags":["audio","eq","equalizer","graphic","music","recording","sound","voice"]},{"name":"markunread","tags":["email","envelop","letter","mail","markunread","message","send","unread"]},{"name":"alarm_on","tags":["alarm","alert","bell","clock","disabled","duration","enabled","notification","off","on","slash","time","timer","watch"]},{"name":"local_gas_station","tags":["auto","car","gas","local","oil","station","vehicle"]},{"name":"person_add_alt_1","tags":[]},{"name":"maximize","tags":["app","application","components","design","interface","line","maximize","screen","shape","site","ui","ux","web","website"]},{"name":"bookmark_add","tags":["+","add","bookmark","favorite","plus","remember","ribbon","save","symbol"]},{"name":"dvr","tags":["Android","OS","audio","chrome","computer","desktop","device","display","dvr","electronic","hardware","iOS","list","mac","monitor","record","recorder","screen","tv","video","web","window"]},{"name":"do_not_disturb_on","tags":["cancel","close","denied","deny","disabled","disturb","do","enabled","off","on","remove","silence","slash","stop"]},{"name":"train","tags":["automobile","car","cars","direction","maps","public","rail","subway","train","transportation","vehicle"]},{"name":"person_pin_circle","tags":["account","circle","destination","direction","face","human","location","maps","people","person","pin","place","profile","stop","user"]},{"name":"square_foot","tags":["construction","feet","foot","inches","length","measurement","ruler","school","set","square","tools"]},{"name":"more_time","tags":["+","add","clock","date","more","new","plus","schedule","symbol","time"]},{"name":"document_scanner","tags":["article","data","doc","document","drive","file","folder","folders","notes","page","paper","scan","scanner","sheet","slide","text","writing"]},{"name":"thumbs_up_down","tags":["dislike","down","favorite","fingers","gesture","hands","like","rate","rating","thumbs","up"]},{"name":"settings_ethernet","tags":["arrows","computer","connect","connection","connectivity","dots","ethernet","internet","network","settings","wifi"]},{"name":"sort_by_alpha","tags":["alphabet","alphabetize","az","by alpha","character","font","letter","list","order","organize","sort","symbol","text","type"]},{"name":"theaters","tags":["film","movie","movies","show","showtimes","theater","theaters","watch"]},{"name":"cloud_done","tags":["app","application","approve","backup","check","cloud","complete","connection","done","drive","files","folders","internet","mark","network","ok","select","sky","storage","tick","upload","validate","verified","yes"]},{"name":"local_parking","tags":["alphabet","auto","car","character","font","garage","letter","local","park","parking","symbol","text","type","vehicle"]},{"name":"view_agenda","tags":["agenda","cards","design","format","grid","layout","stacked","view","website"]},{"name":"mark_email_unread","tags":["check","circle","email","envelop","letter","mail","mark","message","note","notification","send","unread"]},{"name":"local_florist","tags":["florist","flower","local","shop"]},{"name":"connect_without_contact","tags":["communicating","connect","contact","distance","people","signal","social","socialize","without"]},{"name":"thumb_down_off_alt","tags":["disabled","dislike","down","enabled","favorite","filled","fingers","gesture","hand","hands","like","off","offline","on","rank","ranking","rate","rating","slash","thumb"]},{"name":"sentiment_neutral","tags":["emotionless","emotions","expressions","face","feelings","fine","indifference","mood","neutral","okay","person","sentiment","survey"]},{"name":"call_end","tags":["call","cell","contact","device","end","hardware","mobile","phone","telephone"]},{"name":"subdirectory_arrow_right","tags":["arrow","directory","down","navigation","right","sub","subdirectory"]},{"name":"diamond","tags":["diamond","fashion","gems","jewelry","logo","retail","valuable","valuables"]},{"name":"podcasts","tags":["broadcast","casting","network","podcasts","signal","transmitting","wireless"]},{"name":"monitor_heart","tags":["baseline","device","ecc","ecg","fitness","health","heart","medical","monitor","track"]},{"name":"all_inclusive","tags":["all","endless","forever","inclusive","infinity","loop","mobius","neverending","strip","sustainability","sustainable"]},{"name":"wc","tags":["bathroom","closet","female","male","man","restroom","room","wash","water","wc","women"]},{"name":"grass","tags":["backyard","fodder","grass","ground","home","lawn","plant","turf","yard"]},{"name":"important_devices","tags":["Android","OS","desktop","devices","hardware","iOS","important","mobile","monitor","phone","star","tablet","web"]},{"name":"back_hand","tags":["back","fingers","gesture","hand","raised"]},{"name":"hiking","tags":["backpacking","bag","climbing","duffle","hiking","mountain","social","sports","stick","trail","travel","walking"]},{"name":"masks","tags":["air","cover","covid","face","hospital","masks","medical","pollution","protection","respirator","sick","social"]},{"name":"waving_hand","tags":["bye","fingers","gesture","goodbye","greetings","hand","hello","palm","wave","waving"]},{"name":"architecture","tags":["architecture","art","compass","design","draw","drawing","engineering","geometric","tool"]},{"name":"local_post_office","tags":["delivery","email","envelop","letter","local","mail","message","office","package","parcel","post","postal","send","stamp"]},{"name":"functions","tags":["average","calculate","count","custom","doc","edit","editing","editor","functions","math","sheet","spreadsheet","style","sum","text","type","writing"]},{"name":"directions","tags":["arrow","directions","maps","right","route","sign","traffic"]},{"name":"money","tags":["100","bill","card","cash","coin","commerce","cost","credit","currency","digit","dollars","finance","money","number","online","pay","payment","price","shopping","symbol"]},{"name":"unpublished","tags":["approve","check","circle","complete","disabled","done","enabled","mark","off","ok","on","select","slash","tick","unpublished","validate","verified","yes"]},{"name":"notifications_off","tags":["active","alarm","alert","bell","chime","disabled","enabled","notifications","notify","off","offline","on","reminder","ring","slash","sound"]},{"name":"airport_shuttle","tags":["airport","automobile","car","cars","commercial","delivery","direction","maps","mini","public","shuttle","transport","transportation","travel","truck","van","vehicle"]},{"name":"insert_link","tags":["add","attach","clip","file","insert","link","mail","media"]},{"name":"thumb_down_alt","tags":["bad","decline","disapprove","dislike","down","feedback","hate","negative","no","reject","social","thumb","veto","vote"]},{"name":"two_wheeler","tags":["automobile","bike","car","cars","direction","maps","motorcycle","public","scooter","sport","transportation","travel","two wheeler","vehicle"]},{"name":"nightlight","tags":["dark","disturb","mode","moon","night","nightlight","sleep"]},{"name":"mic_none","tags":["hear","hearing","mic","microphone","noise","none","record","sound","voice"]},{"name":"keyboard_double_arrow_down","tags":["arrow","arrows","direction","double","down","multiple","navigation"]},{"name":"invert_colors","tags":["colors","drop","droplet","edit","editing","hue","invert","inverted","palette","tone","water"]},{"name":"clear_all","tags":["all","clear","doc","document","format","lines","list"]},{"name":"mouse","tags":["click","computer","cursor","device","hardware","mouse","wireless"]},{"name":"mode_edit_outline","tags":["compose","create","draft","draw","edit","mode","outline","pen","pencil","write"]},{"name":"open_in_browser","tags":["arrow","browser","in","open","site","up","web","website","window"]},{"name":"insert_invitation","tags":["calendar","date","day","event","insert","invitation","mark","month","range","remember","reminder","today","week"]},{"name":"fast_rewind","tags":["back","control","fast","media","music","play","rewind","speed","time","tv","video"]},{"name":"opacity","tags":["color","drop","droplet","hue","invert","inverted","opacity","palette","tone","water"]},{"name":"video_camera_front","tags":["account","camera","face","front","human","image","people","person","photo","photography","picture","profile","user","video"]},{"name":"commute","tags":["automobile","car","commute","direction","maps","public","train","transportation","trip","vehicle"]},{"name":"addchart","tags":["+","addchart","analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","new","plus","statistics","symbol","tracking"]},{"name":"no_accounts","tags":["account","accounts","avatar","disabled","enabled","face","human","no","off","offline","on","people","person","profile","slash","thumbnail","unavailable","unidentifiable","unknown","user"]},{"name":"coffee","tags":["beverage","coffee","cup","drink","mug","plate","set","tea"]},{"name":"luggage","tags":["airport","bag","baggage","carry","flight","hotel","luggage","on","suitcase","travel","trip"]},{"name":"workspaces","tags":["circles","collaboration","dot","filled","group","outline","space","team","work","workspaces"]},{"name":"child_care","tags":["babies","baby","care","child","children","face","infant","kids","newborn","toddler","young"]},{"name":"sports_score","tags":["destination","flag","goal","score","sports"]},{"name":"library_music","tags":["add","album","collection","library","music","song","sounds"]},{"name":"history_toggle_off","tags":["clock","date","history","off","schedule","time","toggle"]},{"name":"system_update_alt","tags":["arrow","down","download","export","system","update"]},{"name":"access_time","tags":[]},{"name":"rotate_right","tags":["around","arrow","direction","inprogress","load","loading refresh","renew","right","rotate","turn"]},{"name":"color_lens","tags":["art","color","lens","paint","pallet"]},{"name":"grid_on","tags":["collage","disabled","enabled","grid","image","layout","off","on","slash","view"]},{"name":"crop_free","tags":["adjust","adjustments","crop","edit","editing","focus","frame","free","image","photo","photos","settings","size","zoom"]},{"name":"cloud_queue","tags":["cloud","connection","internet","network","queue","sky","upload"]},{"name":"keyboard_voice","tags":["keyboard","mic","microphone","noise","record","recorder","speaker","voice"]},{"name":"format_align_left","tags":["align","alignment","doc","edit","editing","editor","format","left","sheet","spreadsheet","text","type","writing"]},{"name":"view_week","tags":["bars","columns","design","format","grid","layout","view","website","week"]},{"name":"real_estate_agent","tags":["agent","architecture","broker","estate","hand","home","house","loan","mortgage","property","real","residence","residential","sales","social"]},{"name":"horizontal_rule","tags":["gmail","horizontal","line","novitas","rule"]},{"name":"topic","tags":["data","doc","document","drive","file","folder","sheet","slide","storage","topic"]},{"name":"shower","tags":["bath","bathroom","closet","home","house","place","plumbing","room","shower","sprinkler","wash","water","wc"]},{"name":"format_italic","tags":["alphabet","character","doc","edit","editing","editor","font","format","italic","letter","sheet","spreadsheet","style","symbol","text","type","writing"]},{"name":"traffic","tags":["direction","light","maps","signal","street","traffic"]},{"name":"add_business","tags":["+","add","bill","building","business","card","cash","coin","commerce","company","credit","currency","dollars","market","money","new","online","pay","payment","plus","shop","shopping","store","storefront","symbol"]},{"name":"electrical_services","tags":["charge","cord","electric","electrical","plug","power","services","wire"]},{"name":"timelapse","tags":["duration","motion","photo","time","timelapse","timer","video"]},{"name":"youtube_searched_for","tags":["arrow","back","backwards","find","glass","history","inprogress","load","loading","look","magnify","magnifying","refresh","renew","restore","reverse","rotate","search","see","youtube"]},{"name":"front_hand","tags":["fingers","front","gesture","hand","hello","palm","stop"]},{"name":"yard","tags":["backyard","flower","garden","home","house","nature","pettle","plants","yard"]},{"name":"tour","tags":["destination","flag","places","tour","travel","visit"]},{"name":"factory","tags":["factory","industry","manufacturing","warehouse"]},{"name":"developer_board","tags":["board","chip","computer","developer","development","hardware","microchip","processor"]},{"name":"more","tags":["3","archive","bookmark","dots","etc","favorite","indent","label","more","remember","save","stamp","sticker","tab","tag","three"]},{"name":"star_purple500","tags":["500","best","bookmark","favorite","highlight","purple","ranking","rate","rating","save","star","toggle"]},{"name":"format_color_fill","tags":["bucket","color","doc","edit","editing","editor","fill","format","paint","sheet","spreadsheet","style","text","type","writing"]},{"name":"beach_access","tags":["access","beach","places","summer","sunny","umbrella"]},{"name":"local_bar","tags":["alcohol","bar","bottle","club","cocktail","drink","food","liquor","local","wine"]},{"name":"add_link","tags":["add","attach","clip","link","new","plus","symbol"]},{"name":"landscape","tags":["image","landscape","mountain","mountains","nature","photo","photography","picture"]},{"name":"slideshow","tags":["movie","photos","play","slideshow","square","video","view"]},{"name":"stream","tags":["cast","connected","feed","live","network","signal","stream","wireless"]},{"name":"videocam_off","tags":["cam","camera","conference","disabled","enabled","film","filming","hardware","image","motion","off","offline","on","picture","slash","video","videography"]},{"name":"directions_boat","tags":["automobile","boat","car","cars","direction","directions","ferry","maps","public","transportation","vehicle"]},{"name":"download_done","tags":["arrow","arrows","check","done","down","download","downloads","drive","install","installed","ok","tick","upload"]},{"name":"volume_down","tags":["audio","control","down","music","sound","speaker","tv","volume"]},{"name":"alt_route","tags":["alt","alternate","alternative","arrows","direction","maps","navigation","options","other","route","routes","split","symbol"]},{"name":"mood_bad","tags":["bad","disappointment","dislike","emoji","emotions","expressions","face","feelings","mood","person","rating","social","survey","unhappiness","unhappy","unpleased","unsmile","unsmiling"]},{"name":"vaccines","tags":["aid","covid","doctor","drug","emergency","hospital","immunity","injection","medical","medication","medicine","needle","pharmacy","sick","syringe","vaccination","vaccines","vial"]},{"name":"dialpad","tags":["buttons","call","contact","device","dial","dialpad","dots","mobile","numbers","pad","phone"]},{"name":"route","tags":["directions","maps","path","route","sign","traffic"]},{"name":"hide_source","tags":["circle","disabled","enabled","hide","off","offline","on","shape","slash","source"]},{"name":"bookmark_added","tags":["added","approve","bookmark","check","complete","done","favorite","mark","ok","remember","save","select","tick","validate","verified","yes"]},{"name":"mark_as_unread","tags":["as","envelop","letter","mail","mark","post","postal","read","receive","send","unread"]},{"name":"plagiarism","tags":["doc","document","find","glass","look","magnifying","page","paper","plagiarism","search","see"]},{"name":"turned_in","tags":["archive","bookmark","favorite","in","label","library","read","reading","remember","ribbon","save","tag","turned"]},{"name":"settings_input_antenna","tags":["airplay","antenna","arrows","cast","computer","connect","connection","connectivity","dots","input","internet","network","screencast","settings","stream","wifi","wireless"]},{"name":"shop","tags":["bag","bill","buy","card","cart","cash","coin","commerce","credit","currency","dollars","google","money","online","pay","payment","play","shop","shopping","store"]},{"name":"pool","tags":["athlete","athletic","beach","body","entertainment","exercise","hobby","human","ocean","people","person","places","pool","sea","sports","swim","swimming","water"]},{"name":"search_off","tags":["cancel","close","disabled","enabled","find","glass","look","magnify","magnifying","off","on","search","see","slash","stop","x"]},{"name":"approval","tags":["apply","approval","approvals","approve","certificate","certification","disapproval","drive","file","impression","ink","mark","postage","stamp"]},{"name":"currency_rupee","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","rupee","shopping","symbol"]},{"name":"power","tags":["charge","cord","electric","electrical","outlet","plug","power"]},{"name":"collections_bookmark","tags":["album","archive","bookmark","collections","favorite","gallery","label","library","read","reading","remember","ribbon","save","stack","tag"]},{"name":"not_started","tags":["circle","media","not","pause","play","started","video"]},{"name":"pedal_bike","tags":["automobile","bicycle","bike","car","cars","direction","human","maps","pedal","public","route","scooter","transportation","vehicle","vespa"]},{"name":"water","tags":["aqua","beach","lake","ocean","river","water","waves","weather"]},{"name":"router","tags":["box","cable","connection","hardware","internet","network","router","signal","wifi"]},{"name":"flight_land","tags":["airport","arrival","arriving","flight","fly","land","landing","plane","transportation","travel"]},{"name":"shopping_cart_checkout","tags":["arrow","cart","cash","checkout","coin","commerce","currency","dollars","money","online","pay","payment","right","shopping"]},{"name":"agriculture","tags":["agriculture","automobile","car","cars","cultivation","farm","harvest","maps","tractor","transport","travel","truck","vehicle"]},{"name":"where_to_vote","tags":["approve","ballot","check","complete","destination","direction","done","location","maps","mark","ok","pin","place","poll","select","stop","tick","to","validate election","verified","vote","where","yes"]},{"name":"beenhere","tags":["approve","archive","beenhere","bookmark","check","complete","done","favorite","label","library","mark","ok","read","reading","remember","ribbon","save","select","tag","tick","validate","verified","yes"]},{"name":"add_comment","tags":["+","add","bubble","chat","comment","communicate","feedback","message","new","plus","speech","symbol"]},{"name":"copy_all","tags":["all","content","copy","cut","doc","document","file","multiple","page","paper","past"]},{"name":"dynamic_feed","tags":["'mail_outline'","'markunread'. Keep 'mail' and remove others.","Duplicate of 'email'"]},{"name":"videogame_asset","tags":["asset","console","controller","device","game","gamepad","gaming","playstation","video"]},{"name":"move_to_inbox","tags":["archive","arrow","down","email","envelop","inbox","incoming","letter","mail","message","move to","send"]},{"name":"crop_square","tags":["adjust","adjustments","app","application","area","components","crop","design","edit","editing","expand","frame","image","images","interface","open","photo","photos","rectangle","screen","settings","shape","shapes","site","size","square","ui","ux","web","website","window"]},{"name":"recent_actors","tags":["account","actors","avatar","card","cards","carousel","face","human","layers","list","people","person","profile","recent","thumbnail","user"]},{"name":"emoji_nature","tags":["animal","bee","bug","daisy","emoji","flower","insect","ladybug","nature","petals","spring","summer"]},{"name":"cloud_off","tags":["app","application","backup","cloud","connection","disabled","drive","enabled","files","folders","internet","network","off","offline","on","sky","slash","storage","upload"]},{"name":"panorama_fish_eye","tags":["angle","circle","eye","fish","image","panorama","photo","photography","picture","wide"]},{"name":"lens","tags":["circle","full","geometry","lens","moon"]},{"name":"360","tags":["360","arrow","av","camera","direction","rotate","rotation","vr"]},{"name":"share_location","tags":["destination","direction","gps","location","maps","pin","place","share","stop","tracking"]},{"name":"assignment_late","tags":["!","alert","assignment","attention","caution","clipboard","danger","doc","document","error","exclamation","important","late","mark","notification","symbol","warning"]},{"name":"switch_account","tags":["account","choices","face","human","multiple","options","people","person","profile","social","switch","user"]},{"name":"looks_two","tags":["2","digit","looks","numbers","square","symbol"]},{"name":"do_not_disturb","tags":["cancel","close","denied","deny","disturb","do","remove","silence","stop"]},{"name":"donut_small","tags":["analytics","chart","data","diagram","donut","graph","infographic","inprogress","measure","metrics","pie","small","statistics","tracking"]},{"name":"saved_search","tags":["find","glass","important","look","magnify","magnifying","marked","saved","search","see","star"]},{"name":"contactless","tags":["bluetooth","cash","connect","connection","connectivity","contact","contactless","credit","device","finance","pay","payment","signal","transaction","wifi","wireless"]},{"name":"highlight_alt","tags":["alt","arrow","box","click","cursor","draw","focus","highlight","pointer","select","selection","target"]},{"name":"assignment_return","tags":["arrow","assignment","back","clipboard","doc","document","left","retun"]},{"name":"kitchen","tags":["appliance","cold","food","fridge","home","house","ice","kitchen","places","refrigerator","storage"]},{"name":"warehouse","tags":["garage","industry","manufacturing","storage","warehouse"]},{"name":"liquor","tags":["alcohol","bar","bottle","club","cocktail","drink","food","liquor","party","store","wine"]},{"name":"gpp_maybe","tags":["!","alert","attention","caution","certified","danger","error","exclamation","gpp","important","mark","maybe","notification","privacy","private","protect","protection","security","shield","sim","symbol","verified","warning"]},{"name":"settings_input_component","tags":["audio","av","cable","cables","component","connect","connection","connectivity","input","internet","plug","points","settings","video","wifi"]},{"name":"waves","tags":["beach","lake","ocean","pool","river","sea","swim","water","wave","waves"]},{"name":"hotel_class","tags":["achievement","bookmark","class","favorite","highlight","hotel","important","marked","rank","ranking","rate","rating","reward","save","saved","shape","special","star"]},{"name":"web_asset","tags":["-website","app","application desktop","asset","browser","design","download","image","interface","internet","layout","screen","site","ui","ux","video","web","website","window","www"]},{"name":"view_carousel","tags":["cards","carousel","design","format","grid","layout","view","website"]},{"name":"anchor","tags":["anchor","google","logo"]},{"name":"filter_alt_off","tags":["alt","disabled","edit","filter","funnel","off","offline","options","refine","sift","slash"]},{"name":"balance","tags":["balance","equal","equity","impartiality","justice","parity","stability. equilibrium","steadiness","symmetry"]},{"name":"view_quilt","tags":["design","format","grid","layout","quilt","square","squares","stacked","view","website"]},{"name":"library_add_check","tags":["add","approve","check","collection","complete","done","layers","library","mark","multiple","music","ok","select","stacked","tick","validate","verified","video","yes"]},{"name":"queue_music","tags":["collection","list","music","playlist","queue"]},{"name":"casino","tags":["casino","dice","dots","entertainment","gamble","gambling","game","games","luck","places"]},{"name":"hearing","tags":["accessibility","accessible","aid","ear","handicap","hearing","help","impaired","listen","sound","volume"]},{"name":"phone_enabled","tags":["call","cell","contact","device","enabled","hardware","mobile","phone","telephone"]},{"name":"linear_scale","tags":["app","application","components","design","interface","layout","linear","measure","menu","scale","screen","site","slider","ui","ux","web","website","window"]},{"name":"holiday_village","tags":["architecture","beach","camping","cottage","estate","holiday","home","house","lake","lodge","maps","place","real","residence","residential","stay","traveling","vacation","village"]},{"name":"turned_in_not","tags":["archive","bookmark","favorite","in","label","library","not","read","reading","remember","ribbon","save","tag","turned"]},{"name":"sync_problem","tags":["!","360","alert","around","arrow","arrows","attention","caution","danger","direction","error","exclamation","important","inprogress","load","loading refresh","mark","notification","problem","renew","rotate","symbol","sync","turn","warning"]},{"name":"start","tags":["arrow","keyboard","next","right","start"]},{"name":"all_inbox","tags":["Inbox","all","delivered","delivery","email","mail","message","send"]},{"name":"mediation","tags":["arrow","arrows","direction","dots","mediation","right"]},{"name":"edit_off","tags":["compose","create","disabled","draft","edit","editing","enabled","input","new","off","offline","on","pen","pencil","slash","write","writing"]},{"name":"emergency","tags":["asterisk","clinic","emergency","health","hospital","maps","medical","symbol"]},{"name":"settings_remote","tags":["bluetooth","connection","connectivity","device","remote","settings","signal","wifi","wireless"]},{"name":"drive_file_move","tags":["arrow","data","doc","document","drive","file","folder","move","right","sheet","slide","storage"]},{"name":"fit_screen","tags":["enlarge","fit","format","layout","reduce","scale","screen","size"]},{"name":"hourglass_full","tags":["countdown","full","hourglass","loading","minutes","time","wait","waiting"]},{"name":"nights_stay","tags":["climate","cloud","crescent","dark","lunar","mode","moon","nights","phases","silence","silent","sky","stay","time","weather"]},{"name":"pause_circle_filled","tags":["circle","control","controls","filled","media","music","pause","video"]},{"name":"catching_pokemon","tags":["catching","go","pokemon","pokestop","travel"]},{"name":"king_bed","tags":["bed","bedroom","double","furniture","home","hotel","house","king","night","pillows","queen","rest","room","sleep"]},{"name":"flaky","tags":["approve","check","close","complete","contrast","done","exit","flaky","mark","no","ok","options","select","stop","tick","verified","x","yes"]},{"name":"format_size","tags":["alphabet","character","color","doc","edit","editing","editor","fill","font","format","letter","paint","sheet","size","spreadsheet","style","symbol","text","type","writing"]},{"name":"interests","tags":["circle","heart","interests","shapes","social","square","triangle"]},{"name":"stacked_line_chart","tags":["analytics","chart","data","diagram","graph","infographic","line","measure","metrics","stacked","statistics","tracking"]},{"name":"unarchive","tags":["archive","arrow","inbox","mail","store","unarchive","undo","up"]},{"name":"subtitles","tags":["accessible","caption","cc","character","closed","decoder","language","media","movies","subtitle","subtitles","tv"]},{"name":"toll","tags":["bill","booth","car","card","cash","coin","commerce","credit","currency","dollars","highway","money","online","pay","payment","ticket","toll"]},{"name":"keyboard_double_arrow_up","tags":["arrow","arrows","direction","double","multiple","navigation","up"]},{"name":"time_to_leave","tags":["automobile","car","cars","destination","direction","drive","estimate","eta","maps","public","transportation","travel","trip","vehicle"]},{"name":"location_searching","tags":["destination","direction","location","maps","pin","place","pointer","searching","stop","tracking"]},{"name":"cable","tags":["cable","connect","connection","device","electronics","usb","wire"]},{"name":"moving","tags":["arrow","direction","moving","navigation","travel","up"]},{"name":"remove_shopping_cart","tags":["card","cart","cash","checkout","coin","commerce","credit","currency","disabled","dollars","enabled","off","on","online","pay","payment","remove","shopping","slash","tick"]},{"name":"cast_for_education","tags":["Android","OS","airplay","cast","chrome","connect","desktop","device","display","education","for","hardware","iOS","learning","lessons teaching","mac","monitor","screen","screencast","streaming","television","tv","web","window","wireless"]},{"name":"fiber_new","tags":["alphabet","character","fiber","font","letter","network","new","symbol","text","type"]},{"name":"format_underlined","tags":["alphabet","character","doc","edit","editing","editor","font","format","letter","line","sheet","spreadsheet","style","symbol","text","type","under","underlined","writing"]},{"name":"pause_circle_outline","tags":["circle","control","controls","media","music","outline","pause","video"]},{"name":"mark_chat_unread","tags":["bubble","chat","circle","comment","communicate","mark","message","notification","speech","unread"]},{"name":"insert_comment","tags":["add","bubble","chat","comment","feedback","insert","message"]},{"name":"cameraswitch","tags":["arrows","camera","cameraswitch","flip","rotate","swap","switch","view"]},{"name":"rocket","tags":["rocket","space","spaceship"]},{"name":"local_airport","tags":["air","airplane","airport","flight","plane","transportation","travel","trip"]},{"name":"lock_clock","tags":["clock","date","lock","locked","password","privacy","private","protection","safety","schedule","secure","security","time"]},{"name":"device_hub","tags":["Android","OS","circle","computer","desktop","device","hardware","hub","iOS","laptop","mobile","monitor","phone","square","tablet","triangle","watch","wearable","web"]},{"name":"filter_vintage","tags":["edit","editing","effect","filter","flower","image","images","photography","picture","pictures","vintage"]},{"name":"sailing","tags":["boat","entertainment","fishing","hobby","ocean","sailboat","sailing","sea","social sports","travel","water"]},{"name":"roofing","tags":["architecture","building","chimney","construction","estate","home","house","real","residence","residential","roof","roofing","service","shelter"]},{"name":"settings_voice","tags":["mic","microphone","record","recorder","settings","speaker","voice"]},{"name":"swap_horizontal_circle","tags":["arrow","arrows","back","circle","forward","horizontal","swap"]},{"name":"add_location_alt","tags":["+","add","alt","destination","direction","location","maps","new","pin","place","plus","stop","symbol"]},{"name":"room_service","tags":["alert","bell","delivery","hotel","notify","room","service"]},{"name":"content_paste_search","tags":["clipboard","content","doc","document","file","find","paste","search","trace","track"]},{"name":"reply_all","tags":["all","arrow","backward","group","left","mail","message","multiple","reply","send","share"]},{"name":"compost","tags":["bio","compost","compostable","decomposable","decompose","eco","green","leaf","leafs","nature","organic","plant","recycle","sustainability","sustainable"]},{"name":"bubble_chart","tags":["analytics","bar","bars","bubble","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"compare","tags":["adjust","adjustment","compare","edit","editing","edits","enhance","fix","image","images","photo","photography","photos","scan","settings"]},{"name":"money_off","tags":["bill","card","cart","cash","coin","commerce","credit","currency","disabled","dollars","enabled","money","off","on","online","pay","payment","shopping","slash","symbol"]},{"name":"file_open","tags":["arrow","doc","document","drive","file","left","open","page","paper"]},{"name":"filter_drama","tags":["cloud","drama","edit","editing","effect","filter","image","photo","photography","picture","sky camera"]},{"name":"shortcut","tags":["arrow","direction","forward","right","shortcut"]},{"name":"view_sidebar","tags":["design","format","grid","layout","sidebar","view","web"]},{"name":"looks_3","tags":["3","digit","looks","numbers","square","symbol"]},{"name":"note","tags":["bookmark","message","note","paper"]},{"name":"vertical_align_bottom","tags":["align","alignment","arrow","bottom","doc","down","edit","editing","editor","sheet","spreadsheet","text","type","vertical","writing"]},{"name":"3p","tags":["3","3p","account","avatar","bubble","chat","comment","communicate","face","human","message","party","people","person","profile","speech","user"]},{"name":"online_prediction","tags":["bulb","connection","idea","light","network","online","prediction","signal","wireless"]},{"name":"cancel_presentation","tags":["cancel","close","device","exit","no","present","presentation","quit","remove","screen","slide","stop","website","window","x"]},{"name":"select_all","tags":["all","select","selection","square","tool"]},{"name":"event_seat","tags":["assign","assigned","chair","event","furniture","reservation","row","seat","section","sit"]},{"name":"window","tags":["close","glass","grid","home","house","interior","layout","outside","window"]},{"name":"av_timer","tags":["av","clock","countdown","duration","minutes","seconds","time","timer","watch"]},{"name":"album","tags":["album","artist","audio","bvb","cd","computer","data","disk","file","music","record","sound","storage","track"]},{"name":"local_dining","tags":["dining","eat","food","fork","knife","local","meal","restaurant","spoon"]},{"name":"headset","tags":["accessory","audio","device","ear","earphone","headphones","headset","listen","music","sound"]},{"name":"maps_ugc","tags":["+","add","bubble","comment","communicate","feedback","maps","message","new","plus","speech","symbol","ugc"]},{"name":"airplane_ticket","tags":["airplane","airport","boarding","flight","fly","maps","pass","ticket","transportation","travel"]},{"name":"vertical_split","tags":["design","format","grid","layout","paragraph","split","text","vertical","website","writing"]},{"name":"sports_basketball","tags":["athlete","athletic","ball","basketball","entertainment","exercise","game","hobby","social","sports"]},{"name":"next_plan","tags":["arrow","circle","next","plan","right"]},{"name":"drive_folder_upload","tags":["arrow","data","doc","document","drive","file","folder","sheet","slide","storage","up","upload"]},{"name":"pregnant_woman","tags":["baby","birth","body","female","human","lady","maternity","mom","mother","people","person","pregnant","women"]},{"name":"wallpaper","tags":["background","image","landscape","photo","photography","picture","wallpaper"]},{"name":"image_search","tags":["find","glass","image","landscape","look","magnify","magnifying","mountain","mountains","photo","photography","picture","search","see"]},{"name":"data_exploration","tags":["analytics","arrow","chart","data","diagram","exploration","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"device_thermostat","tags":["celsius","device","fahrenheit","meter","temp","temperature","thermometer","thermostat"]},{"name":"healing","tags":["bandage","edit","editing","emergency","fix","healing","hospital","image","medicine"]},{"name":"laptop_mac","tags":["Android","OS","chrome","device","display","hardware","iOS","laptop","mac","monitor","screen","web","window"]},{"name":"height","tags":["arrow","color","doc","down","edit","editing","editor","fill","format","height","paint","sheet","spreadsheet","style","text","type","up","writing"]},{"name":"restore_from_trash","tags":["arrow","back","backwards","clock","date","history","refresh","renew","restore","reverse","rotate","schedule","time","turn"]},{"name":"radar","tags":["detect","military","near","network","position","radar","scan"]},{"name":"auto_awesome_motion","tags":["adjust","auto","awesome","collage","edit","editing","enhance","image","motion","photo","video"]},{"name":"file_download_done","tags":["arrow","arrows","check","done","down","download","downloads","drive","file","install","installed","tick","upload"]},{"name":"notification_add","tags":["+","active","add","alarm","alert","bell","chime","notification","notifications","notify","plus","reminder","ring","sound","symbol"]},{"name":"call_made","tags":["arrow","call","device","made","mobile"]},{"name":"camera_enhance","tags":["ai","artificial","automatic","automation","camera","custom","enhance","genai","important","intelligence","lens","magic","photo","photography","picture","quality","smart","spark","sparkle","special","star"]},{"name":"rotate_left","tags":["around","arrow","direction","inprogress","left","load","loading refresh","renew","rotate","turn"]},{"name":"local_taxi","tags":["automobile","cab","call","car","cars","direction","local","lyft","maps","public","taxi","transportation","uber","vehicle","yellow"]},{"name":"star_border_purple500","tags":["500","best","bookmark","border","favorite","highlight","outline","purple","ranking","rate","rating","save","star","toggle"]},{"name":"gpp_bad","tags":["bad","cancel","certified","close","error","exit","gpp","no","privacy","private","protect","protection","remove","security","shield","sim","stop","verified","x"]},{"name":"playlist_play","tags":["arrow","collection","list","music","play","playlist"]},{"name":"cast","tags":["Android","OS","airplay","cast","chrome","connect","desktop","device","display","hardware","iOS","mac","monitor","screen","screencast","streaming","television","tv","web","window","wireless"]},{"name":"vertical_align_top","tags":["align","alignment","arrow","doc","edit","editing","editor","sheet","spreadsheet","text","top","type","up","vertical","writing"]},{"name":"ramen_dining","tags":["breakfast","dining","dinner","drink","fastfood","food","lunch","meal","noodles","ramen","restaurant"]},{"name":"data_usage","tags":["analytics","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking","usage"]},{"name":"markunread_mailbox","tags":["deliver","envelop","letter","mail","mailbox","markunread","post","postal","postbox","receive","send","unread"]},{"name":"terminal","tags":["application","code","emulator","program","software","terminal"]},{"name":"screen_share","tags":["Android","OS","arrow","cast","chrome","device","display","hardware","iOS","laptop","mac","mirror","monitor","screen","share","steam","streaming","web","window"]},{"name":"center_focus_strong","tags":["camera","center","focus","image","lens","photo","photography","strong","zoom"]},{"name":"queue","tags":["add","collection","layers","list","multiple","music","playlist","queue","stack","stream","video"]},{"name":"games","tags":["adjust","arrow","arrows","control","controller","direction","games","gaming","left","move","right"]},{"name":"low_priority","tags":["arrange","arrow","backward","bottom","list","low","move","order","priority"]},{"name":"dynamic_form","tags":["bolt","code","dynamic","electric","fast","form","lightning","lists","questionnaire","thunderbolt"]},{"name":"tab","tags":["browser","computer","document","documents","folder","internet","tab","tabs","web","website","window","windows"]},{"name":"lock_reset","tags":["around","inprogress","load","loading refresh","lock","locked","password","privacy","private","protection","renew","rotate","safety","secure","security","turn"]},{"name":"room_preferences","tags":["building","door","doorway","entrance","gear","home","house","interior","office","open","preferences","room","settings"]},{"name":"crop","tags":["adjust","adjustments","area","crop","edit","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"monitor_weight","tags":["body","device","diet","health","monitor","scale","smart","weight"]},{"name":"trip_origin","tags":["circle","departure","origin","trip"]},{"name":"calendar_view_week","tags":["calendar","date","day","event","format","grid","layout","month","schedule","today","view","week"]},{"name":"signal_wifi_4_bar","tags":["4","bar","cell","cellular","data","internet","mobile","network","phone","signal","wifi","wireless"]},{"name":"blur_on","tags":["blur","disabled","dots","edit","editing","effect","enabled","enhance","filter","off","on","slash"]},{"name":"view_stream","tags":["design","format","grid","layout","lines","list","stacked","stream","view","website"]},{"name":"radio","tags":["antenna","audio","device","frequency","hardware","listen","media","music","player","radio","signal","tune"]},{"name":"hail","tags":["body","hail","human","people","person","pick","public","stop","taxi","transportation"]},{"name":"do_disturb_on","tags":["cancel","close","denied","deny","disabled","disturb","do","enabled","off","on","remove","silence","slash","stop"]},{"name":"sensor_door","tags":["alarm","security","security system"]},{"name":"wb_incandescent","tags":["balance","bright","edit","editing","incandescent","light","lighting","setting","settings","white","wp"]},{"name":"local_drink","tags":["cup","drink","drop","droplet","liquid","local","park","water"]},{"name":"accessible_forward","tags":["accessibility","accessible","body","forward","handicap","help","human","people","person","wheelchair"]},{"name":"replay_circle_filled","tags":["arrow","arrows","circle","control","controls","filled","music","refresh","renew","repeat","replay","video"]},{"name":"local_printshop","tags":["draft","fax","ink","local","machine","office","paper","print","printer","printshop","send"]},{"name":"local_laundry_service","tags":["cleaning","clothing","dry","dryer","hotel","laundry","local","service","washer"]},{"name":"vpn_lock","tags":["earth","globe","lock","locked","network","password","privacy","private","protection","safety","secure","security","virtual","vpn","world"]},{"name":"schema","tags":["analytics","chart","data","diagram","flow","graph","infographic","measure","metrics","schema","statistics","tracking"]},{"name":"request_page","tags":["data","doc","document","drive","file","folder","folders","page","paper","request","sheet","slide","writing"]},{"name":"token","tags":["badge","hexagon","mark","shield","sign","symbol"]},{"name":"branding_watermark","tags":["branding","components","copyright","design","emblem","format","identity","interface","layout","logo","screen","site","stamp","ui","ux","watermark","web","website","window"]},{"name":"theater_comedy","tags":["broadway","comedy","event","movie","musical","places","show","standup","theater","tour","watch"]},{"name":"text_format","tags":["alphabet","character","font","format","letter","square A","style","symbol","text","type"]},{"name":"directions_bus_filled","tags":["automobile","bus","car","cars","direction","directions","filled","maps","public","transportation","vehicle"]},{"name":"remove_done","tags":["approve","check","complete","disabled","done","enabled","finished","mark","multiple","off","ok","on","remove","select","slash","tick","yes"]},{"name":"sports_bar","tags":["alcohol","bar","beer","drink","liquor","pint","places","pub","sports"]},{"name":"watch","tags":["Android","OS","ar","clock","gadget","iOS","time","vr","watch","wearables","web","wristwatch"]},{"name":"add_to_drive","tags":["add","app","application","backup","cloud","drive","files","folders","gdrive","google","recovery","shortcut","storage"]},{"name":"format_align_center","tags":["align","alignment","center","doc","edit","editing","editor","format","sheet","spreadsheet","text","type","writing"]},{"name":"settings_power","tags":["info","information","off","on","power","save","settings","shutdown"]},{"name":"local_pizza","tags":["drink","fastfood","food","local","meal","pizza"]},{"name":"add_alert","tags":["+","active","add","alarm","alert","bell","chime","new","notifications","notify","plus","reminder","ring","sound","symbol"]},{"name":"smart_button","tags":["action","ai","artificial","automatic","automation","button","components","composer","custom","function","genai","intelligence","interface","magic","site","smart","spark","sparkle","special","star","stars","ui","ux","web","website"]},{"name":"flare","tags":["bright","edit","editing","effect","flare","image","images","light","photography","picture","pictures","sun"]},{"name":"developer_mode","tags":["Android","OS","bracket","cell","code","developer","development","device","engineer","hardware","iOS","mobile","mode","phone","tablet"]},{"name":"call_split","tags":["arrow","call","device","mobile","split"]},{"name":"free_breakfast","tags":["beverage","breakfast","cafe","coffee","cup","drink","free","mug","tea"]},{"name":"auto_delete","tags":["auto","bin","can","clock","date","delete","garbage","remove","schedule","time","trash"]},{"name":"sports_kabaddi","tags":["athlete","athletic","body","combat","entertainment","exercise","fighting","game","hobby","human","kabaddi","people","person","social","sports","wrestle","wrestling"]},{"name":"face_retouching_natural","tags":["ai","artificial","automatic","automation","custom","edit","editing","effect","emoji","emotion","face","faces","genai","image","intelligence","magic","natural","photo","photography","retouch","retouching","settings","smart","spark","sparkle","star","tag"]},{"name":"not_listed_location","tags":["?","assistance","destination","direction","help","info","information","listed","location","maps","not","pin","place","punctuation","question mark","stop","support","symbol"]},{"name":"wb_cloudy","tags":["balance","cloud","cloudy","edit","editing","white","wp"]},{"name":"sports","tags":["athlete","athletic","blowing","coach","entertainment","exercise","game","hobby","instrument","referee","social","sound","sports","warning","whistle"]},{"name":"emoji_symbols","tags":["ampersand","character","emoji","hieroglyph","music","note","percent","sign","symbols"]},{"name":"bathtub","tags":["bath","bathing","bathroom","bathtub","home","hotel","human","person","shower","travel","tub"]},{"name":"forward_10","tags":["10","arrow","control","controls","digit","fast","forward","music","number","play","seconds","symbol","video"]},{"name":"tablet_mac","tags":["Android","OS","device","hardware","iOS","ipad","mobile","tablet mac","web"]},{"name":"mode_night","tags":["dark","disturb","lunar","mode","moon","night","sleep"]},{"name":"broken_image","tags":["broken","corrupt","error","image","landscape","mountain","mountains","photo","photography","picture","torn"]},{"name":"escalator_warning","tags":["body","child","escalator","human","kid","parent","people","person","warning"]},{"name":"assistant","tags":["ai","artificial","assistant","automatic","automation","bubble","chat","comment","communicate","custom","feedback","genai","intelligence","magic","message","recommendation","smart","spark","sparkle","speech","star","suggestion","twinkle"]},{"name":"cases","tags":["bag","baggage","briefcase","business","case","cases","purse","suitcase"]},{"name":"wifi_tethering","tags":["cell","cellular","connection","data","internet","mobile","network","phone","scan","service","signal","speed","tethering","wifi","wireless"]},{"name":"reduce_capacity","tags":["arrow","body","capacity","covid","decrease","down","human","people","person","reduce","social"]},{"name":"colorize","tags":["color","colorize","dropper","extract","eye","picker","tool"]},{"name":"save_as","tags":["compose","create","data","disk","document","draft","drive","edit","editing","file","floppy","input","multimedia","pen","pencil","save","storage","write","writing"]},{"name":"card_travel","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","membership","miles","money","online","pay","payment","travel","trip"]},{"name":"emoji_food_beverage","tags":["beverage","coffee","cup","drink","emoji","mug","plate","set","tea"]},{"name":"font_download","tags":["A","alphabet","character","download","font","letter","square","symbol","text","type"]},{"name":"outbox","tags":["box","mail","outbox","send","sent"]},{"name":"battery_std","tags":["battery","cell","charge","mobile","plus","power","standard","std"]},{"name":"sick","tags":["covid","discomfort","emotions","expressions","face","feelings","fever","flu","ill","mood","pain","person","sick","survey","upset"]},{"name":"add_location","tags":["+","add","destination","direction","location","maps","new","pin","place","plus","stop","symbol"]},{"name":"try","tags":["bookmark","bubble","chat","comment","communicate","favorite","feedback","highlight","important","marked","message","save","saved","shape","special","speech","star","try"]},{"name":"discount","tags":[]},{"name":"man","tags":["boy","gender","male","man","social","symbol"]},{"name":"running_with_errors","tags":["!","alert","attention","caution","danger","duration","error","errors","exclamation","important","mark","notification","process","processing","running","symbol","time","warning","with"]},{"name":"diversity_3","tags":["committee","diverse","diversity","family","friends","group","groups","humans","network","people","persons","social","team"]},{"name":"filter_none","tags":["filter","multiple","none","square","stack"]},{"name":"cloud_sync","tags":["app","application","around","backup","cloud","connection","drive","files","folders","inprogress","internet","load","loading refresh","network","renew","rotate","sky","storage","turn","upload"]},{"name":"bloodtype","tags":["blood","bloodtype","donate","droplet","emergency","hospital","medicine","negative","positive","type","water"]},{"name":"dinner_dining","tags":["breakfast","dining","dinner","food","fork","lunch","meal","restaurant","spaghetti","utensils"]},{"name":"transfer_within_a_station","tags":["a","arrow","arrows","body","direction","human","left","maps","people","person","public","right","route","station","stop","transfer","transportation","vehicle","walk","within"]},{"name":"weekend","tags":["chair","couch","furniture","home","living","lounge","relax","room","weekend"]},{"name":"child_friendly","tags":["baby","care","carriage","child","children","friendly","infant","kid","newborn","stroller","toddler","young"]},{"name":"offline_pin","tags":["approve","check","checkmark","circle","complete","done","mark","offline","ok","pin","select","tick","validate","verified","yes"]},{"name":"replay_10","tags":["10","arrow","arrows","control","controls","digit","music","number","refresh","renew","repeat","replay","symbol","ten","video"]},{"name":"brightness_4","tags":["4","brightness","circle","control","crescent","level","moon","screen","sun"]},{"name":"cruelty_free","tags":["animal","bunny","cruelty","eco","free","nature","rabbit","social","sustainability","sustainable","testing"]},{"name":"format_paint","tags":["brush","color","doc","edit","editing","editor","fill","format","paint","roller","sheet","spreadsheet","style","text","type","writing"]},{"name":"filter_center_focus","tags":["camera","center","dot","edit","filter","focus","image","photo","photography","picture"]},{"name":"area_chart","tags":["analytics","area","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"bakery_dining","tags":["bakery","bread","breakfast","brunch","croissant","dining","food"]},{"name":"emoji_transportation","tags":["architecture","automobile","building","car","cars","direction","emoji","estate","maps","place","public","real","residence","residential","shelter","transportation","travel","vehicle"]},{"name":"folder_special","tags":["bookmark","data","doc","document","drive","favorite","file","folder","highlight","important","marked","save","saved","shape","sheet","slide","special","star","storage"]},{"name":"door_front","tags":["closed","door","doorway","entrance","exit","front","home","house","way"]},{"name":"calendar_view_day","tags":["calendar","date","day","event","format","grid","layout","month","schedule","today","view","week"]},{"name":"legend_toggle","tags":["analytics","chart","data","diagram","graph","infographic","legend","measure","metrics","monitoring","stackdriver","statistics","toggle","tracking"]},{"name":"light","tags":["bulb","ceiling","hanging","inside","interior","lamp","light","lighting","pendent","room"]},{"name":"find_replace","tags":["around","arrows","find","glass","inprogress","load","loading refresh","look","magnify","magnifying","renew","replace","rotate","search","see"]},{"name":"crop_original","tags":["adjust","adjustments","area","crop","edit","editing","frame","image","images","original","photo","photos","picture","settings","size"]},{"name":"rowing","tags":["activity","boat","body","canoe","human","people","person","row","rowing","sport","water"]},{"name":"enhanced_encryption","tags":["+","add","encryption","enhanced","lock","locked","new","password","plus","privacy","private","protection","safety","secure","security","symbol"]},{"name":"how_to_vote","tags":["ballot","election","how","poll","to","vote"]},{"name":"chrome_reader_mode","tags":["chrome","mode","read","reader","text"]},{"name":"auto_fix_normal","tags":["ai","artificial","auto","automatic","automation","custom","edit","erase","fix","genai","intelligence","magic","modify","smart","spark","sparkle","star","wand"]},{"name":"compress","tags":["arrow","arrows","collide","compress","pressure","push","together"]},{"name":"dehaze","tags":["adjust","dehaze","edit","editing","enhance","haze","image","lines","photo","photography","remove"]},{"name":"outlet","tags":["connect","connecter","electricity","outlet","plug","power"]},{"name":"desktop_mac","tags":["Android","OS","chrome","desktop","device","display","hardware","iOS","mac","monitor","screen","web","window"]},{"name":"nature_people","tags":["activity","body","forest","human","nature","outdoor","outside","park","people","person","tree","wilderness"]},{"name":"sports_tennis","tags":["athlete","athletic","ball","bat","entertainment","exercise","game","hobby","racket","social","sports","tennis"]},{"name":"forest","tags":["forest","jungle","nature","plantation","plants","trees","woodland"]},{"name":"upcoming","tags":["alarm","calendar","mail","message","notification","upcoming"]},{"name":"assignment_returned","tags":["arrow","assignment","clipboard","doc","document","down","returned"]},{"name":"cookie","tags":["biscuit","cookies","data","dessert","wafer"]},{"name":"fax","tags":["fax","machine","office","phone","send"]},{"name":"square","tags":["draw","four","shape quadrangle","sides","square"]},{"name":"density_medium","tags":["density","horizontal","lines","medium","rule","rules"]},{"name":"terrain","tags":["geography","landscape","mountain","terrain"]},{"name":"settings_brightness","tags":["brightness","dark","filter","light","mode","setting","settings"]},{"name":"attach_email","tags":["attach","attachment","clip","compose","email","envelop","letter","link","mail","message","send"]},{"name":"photo","tags":["image","mountain","mountains","photo","photography","picture"]},{"name":"http","tags":["alphabet","character","font","http","letter","symbol","text","transfer","type","url","website"]},{"name":"garage","tags":["automobile","automotive","car","cars","direction","garage","maps","transportation","travel","vehicle"]},{"name":"wine_bar","tags":["alcohol","bar","cocktail","cup","drink","glass","liquor","wine"]},{"name":"multiple_stop","tags":["arrows","directions","dots","left","maps","multiple","navigation","right","stop"]},{"name":"format_color_text","tags":["color","doc","edit","editing","editor","fill","format","paint","sheet","spreadsheet","style","text","type","writing"]},{"name":"gesture","tags":["drawing","finger","gesture","gestures","hand","motion"]},{"name":"heart_broken","tags":["break","broken","core","crush","health","heart","nucleus","split"]},{"name":"format_align_right","tags":["align","alignment","doc","edit","editing","editor","format","right","sheet","spreadsheet","text","type","writing"]},{"name":"transgender","tags":["female","gender","lgbt","male","neutral","social","symbol","transgender"]},{"name":"alarm_add","tags":["+","add","alarm","alert","bell","clock","countdown","date","new","notification","plus","schedule","symbol","time"]},{"name":"new_label","tags":["+","add","archive","bookmark","favorite","label","library","new","plus","read","reading","remember","ribbon","save","symbol","tag"]},{"name":"south_east","tags":["arrow","directional","down","east","maps","navigation","right","south"]},{"name":"backup_table","tags":["backup","drive","files folders","format","layout","stack","storage","table"]},{"name":"unsubscribe","tags":["cancel","close","email","envelop","letter","mail","message","newsletter","off","remove","send","subscribe","unsubscribe"]},{"name":"flash_off","tags":["bolt","disabled","electric","enabled","fast","flash","lightning","off","on","slash","thunderbolt"]},{"name":"elderly","tags":["body","cane","elderly","human","old","people","person","senior"]},{"name":"generating_tokens","tags":["access","ai","api","artificial","automatic","automation","coin","custom","genai","generating","intelligence","magic","smart","spark","sparkle","star","tokens"]},{"name":"spellcheck","tags":["a","alphabet","approve","character","check","font","letter","mark","ok","processor","select","spell","spellcheck","symbol","text","tick","type","word","write","yes"]},{"name":"auto_awesome_mosaic","tags":["adjust","auto","awesome","collage","edit","editing","enhance","image","mosaic","photo"]},{"name":"outdoor_grill","tags":["barbecue","bbq","charcoal","cooking","grill","home","house","outdoor","outside"]},{"name":"restore_page","tags":["arrow","data","doc","file","page","paper","refresh","restore","rotate","sheet","storage"]},{"name":"foundation","tags":["architecture","base","basis","building","construction","estate","foundation","home","house","real","residential"]},{"name":"credit_card_off","tags":["card","charge","commerce","cost","credit","disabled","enabled","finance","money","off","online","pay","payment","slash"]},{"name":"scatter_plot","tags":["analytics","bar","bars","chart","circles","data","diagram","dot","graph","infographic","measure","metrics","plot","scatter","statistics","tracking"]},{"name":"signal_cellular_4_bar","tags":["4","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","wifi","wireless"]},{"name":"add_moderator","tags":["+","add","certified","moderator","new","plus","privacy","private","protect","protection","security","shield","symbol","verified"]},{"name":"play_for_work","tags":["arrow","circle","down","google","half","play","work"]},{"name":"add_card","tags":["+","add","bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","new","online","pay","payment","plus","price","shopping","symbol"]},{"name":"app_settings_alt","tags":["Android","OS","app","applications","cell","device","gear","hardware","iOS","mobile","phone","setting","settings","tablet"]},{"name":"keyboard_tab","tags":["arrow","keyboard","left","next","right","tab"]},{"name":"wifi_protected_setup","tags":["around","arrow","arrows","protected","rotate","setup","wifi"]},{"name":"deck","tags":["chairs","deck","home","house","outdoors","outside","patio","social","terrace","umbrella","yard"]},{"name":"takeout_dining","tags":["box","container","delivery","dining","food","meal","restaurant","takeout"]},{"name":"tag_faces","tags":["emoji","emotion","faces","happy","satisfied","smile","tag"]},{"name":"brightness_6","tags":["6","brightness","circle","control","crescent","level","moon","screen","sun"]},{"name":"woman","tags":["female","gender","girl","lady","social","symbol","woman","women"]},{"name":"assistant_direction","tags":["assistant","destination","direction","location","maps","navigate","navigation","pin","place","right","stop"]},{"name":"brightness_5","tags":["5","brightness","circle","control","crescent","level","moon","screen","sun"]},{"name":"social_distance","tags":["6","apart","body","distance","ft","human","people","person","social","space"]},{"name":"free_cancellation","tags":["approve","calendar","cancel","cancellation","check","complete","date","day","done","event","exit","free","mark","month","no","ok","remove","schedule","select","stop","tick","validate","verified","x","yes"]},{"name":"subdirectory_arrow_left","tags":["arrow","directory","down","left","navigation","sub","subdirectory"]},{"name":"laptop_chromebook","tags":["Android","OS","chrome","chromebook","device","display","hardware","iOS","laptop","mac chromebook","monitor","screen","web","window"]},{"name":"format_list_numbered_rtl","tags":["align","alignment","digit","doc","edit","editing","editor","format","list","notes","number","numbered","rtl","sheet","spreadsheet","symbol","text","type","writing"]},{"name":"store_mall_directory","tags":["directory","mall","store"]},{"name":"settings_overscan","tags":["arrows","expand","image","photo","picture","scan","settings"]},{"name":"icecream","tags":["cream","dessert","food","ice","icecream","snack"]},{"name":"details","tags":["details","edit","editing","enhance","image","photo","photography","sharpen","triangle"]},{"name":"add_reaction","tags":["+","add","emoji","emotions","expressions","face","feelings","glad","happiness","happy","icon","icons","insert","like","mood","new","person","pleased","plus","smile","smiling","social","survey","symbol"]},{"name":"follow_the_signs","tags":["arrow","body","directional","follow","human","people","person","right","signs","social","the"]},{"name":"attribution","tags":["attribute","attribution","body","copyright","copywriter","human","people","person"]},{"name":"food_bank","tags":["architecture","bank","building","charity","eat","estate","food","fork","house","knife","meal","place","real","residence","residential","shelter","utensils"]},{"name":"closed_caption","tags":["accessible","alphabet","caption","cc","character","closed","decoder","font","language","letter","media","movies","subtitle","subtitles","symbol","text","tv","type"]},{"name":"gif","tags":["alphabet","animated","animation","bitmap","character","font","format","gif","graphics","interchange","letter","symbol","text","type"]},{"name":"phonelink","tags":["Android","OS","chrome","computer","connect","desktop","device","hardware","iOS","link","mac","mobile","phone","phonelink","sync","tablet","web","windows"]},{"name":"grain","tags":["dots","edit","editing","effect","filter","grain","image","images","photography","picture","pictures"]},{"name":"personal_injury","tags":["accident","aid","arm","bandage","body","broke","cast","fracture","health","human","injury","medical","patient","people","person","personal","sling","social"]},{"name":"flip_camera_android","tags":["android","camera","center","edit","editing","flip","image","mobile","orientation","rotate","turn"]},{"name":"museum","tags":["architecture","attraction","building","estate","event","exhibition","explore","local","museum","places","real","see","shop","store","tour"]},{"name":"north_west","tags":["arrow","directional","left","maps","navigation","north","up","west"]},{"name":"gite","tags":["architecture","estate","gite","home","hostel","house","maps","place","real","residence","residential","stay","traveling"]},{"name":"highlight","tags":["color","doc","edit","editing","editor","emphasize","fill","flash","format","highlight","light","paint","sheet","spreadsheet","style","text","type","writing"]},{"name":"brightness_1","tags":["1","brightness","circle","control","crescent","level","moon","screen"]},{"name":"plus_one","tags":["1","add","digit","increase","number","one","plus","symbol"]},{"name":"villa","tags":["architecture","beach","estate","home","house","maps","place","real","residence","residential","traveling","vacation stay","villa"]},{"name":"fmd_bad","tags":["!","alert","attention","bad","caution","danger","destination","direction","error","exclamation","fmd","important","location","maps","mark","notification","pin","place","symbol","warning"]},{"name":"flashlight_on","tags":["disabled","enabled","flash","flashlight","light","off","on","slash"]},{"name":"flip","tags":["edit","editing","flip","image","orientation","scan scanning"]},{"name":"nightlife","tags":["alcohol","bar","bottle","club","cocktail","dance","drink","food","glass","liquor","music","nightlife","note","wine"]},{"name":"present_to_all","tags":["all","arrow","present","presentation","screen","share","site","slides","to","web","website"]},{"name":"do_disturb","tags":["cancel","close","denied","deny","disturb","do","remove","silence","stop"]},{"name":"outbound","tags":["arrow","circle","directional","outbound","right","up"]},{"name":"local_pharmacy","tags":["911","aid","cross","emergency","first","hospital","local","medicine","pharmacy","places"]},{"name":"splitscreen","tags":["column","grid","layout","multitasking","row","screen","split","splitscreen","two"]},{"name":"waterfall_chart","tags":["analytics","bar","chart","data","diagram","graph","infographic","measure","metrics","statistics","tracking","waterfall"]},{"name":"switch_left","tags":["arrows","directional","left","navigation","switch","toggle"]},{"name":"domain_verification","tags":["app","application desktop","approve","check","complete","design","domain","done","interface","internet","layout","mark","ok","screen","select","site","tick","ui","ux","validate","verification","verified","web","website","window","www","yes"]},{"name":"fireplace","tags":["chimney","fire","fireplace","flame","home","house","living","pit","place","room","warm","winter"]},{"name":"video_settings","tags":["change","details","gear","info","information","options","play","screen","service","setting","settings","video","window"]},{"name":"disabled_visible","tags":["cancel","close","disabled","exit","eye","no","on","quit","remove","reveal","see","show","stop","view","visibility","visible"]},{"name":"network_wifi","tags":["cell","cellular","data","internet","mobile","network","phone","speed","wifi","wireless"]},{"name":"quickreply","tags":["bolt","bubble","chat","comment","communicate","fast","lightning","message","quick","quickreply","reply","speech","thunderbolt"]},{"name":"swap_vertical_circle","tags":["arrow","arrows","circle","down","swap","up","vertical"]},{"name":"format_align_justify","tags":["align","alignment","density","doc","edit","editing","editor","extra","format","justify","sheet","small","spreadsheet","text","type","writing"]},{"name":"settings_input_composite","tags":["component","composite","connection","connectivity","input","plug","points","settings"]},{"name":"loupe","tags":["+","add","details","focus","glass","loupe","magnifying","new","plus","symbol"]},{"name":"123","tags":["1","2","3","digit","number","symbol"]},{"name":"network_check","tags":["check","connect","connection","internet","meter","network","signal","speed","tick","wifi","wireless"]},{"name":"sms_failed","tags":["!","alert","attention","bubbles","caution","chat","communication","conversation","danger","error","exclamation","failed","feedback","important","mark","message","notification","service","sms","speech","symbol","warning"]},{"name":"cancel_schedule_send","tags":["cancel","email","mail","no","quit","remove","schedule","send","share","stop","x"]},{"name":"work_history","tags":["back","backwards","bag","baggage","briefcase","business","case","clock","date","history","job","pending","recent","schedule","suitcase","time","updates","work"]},{"name":"electric_bolt","tags":["bolt","electric","energy","fast","lightning","nest","thunderbolt"]},{"name":"view_day","tags":["cards","carousel","day","design","format","grid","layout","view","website"]},{"name":"night_shelter","tags":["architecture","bed","building","estate","homeless","house","night","place","real","shelter","sleep"]},{"name":"monitor","tags":["Android","OS","chrome","device","display","hardware","iOS","mac","monitor","screen","web","window"]},{"name":"clean_hands","tags":["bacteria","clean","disinfect","germs","gesture","hand","hands","sanitize","sanitizer"]},{"name":"mark_chat_read","tags":["approve","bubble","chat","check","comment","communicate","complete","done","mark","message","ok","read","select","sent","speech","tick","verified","yes"]},{"name":"comment_bank","tags":["archive","bank","bookmark","bubble","cchat","comment","communicate","favorite","label","library","message","remember","ribbon","save","speech","tag"]},{"name":"sim_card_download","tags":["arrow","camera","card","chip","device","down","download","memory","phone","sim","storage"]},{"name":"lan","tags":["computer","connection","data","internet","lan","network","service"]},{"name":"piano","tags":["instrument","keyboard","keys","music","musical","piano","social"]},{"name":"add_road","tags":["+","add","destination","direction","highway","maps","new","plus","road","stop","street","symbol","traffic"]},{"name":"add_ic_call","tags":["+","add","call","cell","contact","device","hardware","mobile","new","phone","plus","symbol","telephone"]},{"name":"rule_folder","tags":["approve","cancel","check","close","complete","data","doc","document","done","drive","exit","file","folder","mark","no","ok","remove","rule","select","sheet","slide","storage","tick","validate","verified","x","yes"]},{"name":"switch_access_shortcut","tags":["access","arrow","arrows","direction","navigation","new","north","shortcut","switch","symbol","up"]},{"name":"hardware","tags":["break","construction","hammer","hardware","nail","repair","tool"]},{"name":"line_weight","tags":["height","line","size","spacing","style","thickness","weight"]},{"name":"image_not_supported","tags":["disabled","enabled","image","landscape","mountain","mountains","not","off","on","photo","photography","picture","slash","supported"]},{"name":"flip_camera_ios","tags":["DISABLE_IOS","android","camera","disable_ios","edit","editing","flip","image","ios","mobile","orientation","rotate","turn"]},{"name":"phone_callback","tags":["arrow","call","callback","cell","contact","device","down","hardware","mobile","phone","telephone"]},{"name":"access_time_filled","tags":[]},{"name":"dining","tags":["cafe","cafeteria","cutlery","diner","dining","eat","eating","fork","room","spoon"]},{"name":"scale","tags":["measure","monitor","scale","weight"]},{"name":"airplanemode_active","tags":["active","airplane","airplanemode","flight","mode","on","signal"]},{"name":"set_meal","tags":["chopsticks","dinner","fish","food","lunch","meal","restaurant","set","teishoku"]},{"name":"mobile_friendly","tags":["Android","OS","approve","cell","check","complete","device","done","friendly","hardware","iOS","mark","mobile","ok","phone","select","tablet","tick","validate","verified","yes"]},{"name":"assured_workload","tags":["assured","compliance","confidential","federal","government","secure","sensitive regulatory","workload"]},{"name":"wallet","tags":[]},{"name":"merge_type","tags":["arrow","combine","direction","format","merge","text","type"]},{"name":"view_timeline","tags":["grid","layout","pattern","squares","timeline","view"]},{"name":"departure_board","tags":["automobile","board","bus","car","cars","clock","departure","maps","public","schedule","time","transportation","travel","vehicle"]},{"name":"event_repeat","tags":["around","calendar","date","day","event","inprogress","load","loading refresh","month","renew","rotate","schedule","turn"]},{"name":"sanitizer","tags":["bacteria","bottle","clean","covid","disinfect","germs","pump","sanitizer"]},{"name":"surfing","tags":["athlete","athletic","beach","body","entertainment","exercise","hobby","human","people","person","sea","social sports","sports","summer","surfing","water"]},{"name":"pix","tags":["bill","brazil","card","cash","commerce","credit","currency","finance","money","payment"]},{"name":"phonelink_ring","tags":["Android","OS","cell","connection","data","device","hardware","iOS","mobile","network","phone","phonelink","ring","service","signal","tablet","wireless"]},{"name":"display_settings","tags":["Android","OS","application","change","chrome","desktop","details","device","display","gear","hardware","iOS","info","information","mac","monitor","options","personal","screen","service","settings","web","window"]},{"name":"sports_motorsports","tags":["athlete","athletic","automobile","bike","drive","driving","entertainment","helmet","hobby","motorcycle","motorsports","protect","social","sports","vehicle"]},{"name":"horizontal_split","tags":["bars","format","horizontal","layout","lines","split","stacked"]},{"name":"view_comfy","tags":["comfy","grid","layout","pattern","squares","view"]},{"name":"polymer","tags":["emblem","logo","mark","polymer"]},{"name":"golf_course","tags":["athlete","athletic","ball","club","course","entertainment","flag","golf","golfer","golfing","hobby","hole","places","putt","sports"]},{"name":"batch_prediction","tags":["batch","bulb","idea","light","prediction"]},{"name":"filter_1","tags":["1","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"stay_current_portrait","tags":["Android","OS","current","device","hardware","iOS","mobile","phone","portrait","stay","tablet"]},{"name":"usb","tags":["cable","connection","device","usb","wire"]},{"name":"featured_play_list","tags":["collection","featured","highlighted","list","music","play","playlist","recommended"]},{"name":"data_object","tags":["brackets","code","coder","data","object","parentheses"]},{"name":"co_present","tags":["arrow","co-present","presentation","screen","share","site","slides","togather","web","website"]},{"name":"ev_station","tags":["automobile","car","cars","charging","electric","electricity","ev","maps","places","station","transportation","vehicle"]},{"name":"send_and_archive","tags":["archive","arrow","down","download","email","letter","mail","save","send","share"]},{"name":"send_to_mobile","tags":["Android","OS","arrow","device","export","forward","hardware","iOS","mobile","phone","right","send","share","tablet","to"]},{"name":"local_see","tags":["camera","lens","local","photo","photography","picture","see"]},{"name":"satellite_alt","tags":["alternative","artificial","communication","satellite","space","space station","television"]},{"name":"flatware","tags":["cafe","cafeteria","cutlery","diner","dining","eat","eating","fork","room","spoon"]},{"name":"speaker","tags":["box","electronic","loud","music","sound","speaker","stereo","system","video"]},{"name":"adb","tags":["adb","android","bridge","debug"]},{"name":"movie_creation","tags":["cinema","clapperboard","creation","film","movie","movies","slate","video"]},{"name":"picture_in_picture","tags":["crop","cropped","overlap","photo","picture","position","shape"]},{"name":"call_received","tags":["arrow","call","device","mobile","received"]},{"name":"battery_alert","tags":["!","alert","attention","battery","caution","cell","charge","danger","error","exclamation","important","mark","mobile","notification","power","symbol","warning"]},{"name":"system_update","tags":["Android","OS","arrow","arrows","cell","device","direction","down","download","hardware","iOS","install","mobile","phone","system","tablet","update"]},{"name":"webhook","tags":["api","developer","development","enterprise","software","webhook"]},{"name":"add_chart","tags":["+","add","analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","new","plus","statistics","symbol","tracking"]},{"name":"pan_tool_alt","tags":["fingers","gesture","hand","hands","human","move","pan","scan","stop","tool"]},{"name":"sports_handball","tags":["athlete","athletic","ball","body","entertainment","exercise","game","handball","hobby","human","people","person","social","sports"]},{"name":"electric_car","tags":["automobile","car","cars","electric","electricity","maps","transportation","travel","vehicle"]},{"name":"phone_forwarded","tags":["arrow","call","cell","contact","device","direction","forwarded","hardware","mobile","phone","right","telephone"]},{"name":"add_to_photos","tags":["add","collection","image","landscape","mountain","mountains","photo","photography","photos","picture","plus","to"]},{"name":"power_off","tags":["charge","cord","disabled","electric","electrical","enabled","off","on","outlet","plug","power","slash"]},{"name":"noise_control_off","tags":["audio","aware","cancel","cancellation","control","disabled","enabled","music","noise","note","off","offline","on","slash","sound"]},{"name":"code_off","tags":["brackets","code","css","develop","developer","disabled","enabled","engineer","engineering","html","off","on","platform","slash"]},{"name":"bookmark_remove","tags":["bookmark","delete","favorite","minus","remember","remove","ribbon","save","subtract"]},{"name":"screen_search_desktop","tags":["Android","OS","arrow","desktop","device","hardware","iOS","lock","monitor","rotate","screen","web"]},{"name":"panorama","tags":["angle","image","mountain","mountains","panorama","photo","photography","picture","view","wide"]},{"name":"settings_bluetooth","tags":["bluetooth","connect","connection","connectivity","device","settings","signal","symbol"]},{"name":"sports_baseball","tags":["athlete","athletic","ball","baseball","entertainment","exercise","game","hobby","social","sports"]},{"name":"festival","tags":["circus","event","festival","local","maps","places","tent","tour","travel"]},{"name":"lens_blur","tags":["blur","camera","dim","dot","effect","foggy","fuzzy","image","lens","photo","soften"]},{"name":"plumbing","tags":["build","construction","fix","handyman","plumbing","repair","tools","wrench"]},{"name":"toys","tags":["car","games","kids","toy","toys","windmill"]},{"name":"coffee_maker","tags":["appliances","beverage","coffee","cup","drink","machine","maker","mug"]},{"name":"edit_notifications","tags":["active","alarm","alert","bell","chime","compose","create","draft","edit","editing","input","new","notifications","notify","pen","pencil","reminder","ring","sound","write","writing"]},{"name":"personal_video","tags":["Android","OS","cam","chrome","desktop","device","hardware","iOS","mac","monitor","personal","television","tv","video","web","window"]},{"name":"animation","tags":["animation","circles","film","motion","movement","sequence","video"]},{"name":"bedtime","tags":["bedtime","nightime","sleep"]},{"name":"gamepad","tags":["buttons","console","controller","device","game","gamepad","gaming","playstation","video"]},{"name":"diversity_1","tags":["committee","diverse","diversity","family","friends","group","groups","heart","humans","network","people","persons","social","team"]},{"name":"center_focus_weak","tags":["camera","center","focus","image","lens","photo","photography","weak","zoom"]},{"name":"signal_wifi_statusbar_4_bar","tags":["4","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","statusbar","wifi","wireless"]},{"name":"manage_history","tags":["application","arrow","back","backwards","change","clock","date","details","gear","history","options","refresh","renew","reverse","rotate","schedule","settings","time","turn"]},{"name":"folder_zip","tags":["compress","data","doc","document","drive","file","folder","folders","open","sheet","slide","storage","zip"]},{"name":"flag_circle","tags":["circle","country","flag","goal","mark","nation","report","round","start"]},{"name":"south_west","tags":["arrow","directional","down","left","maps","navigation","south","west"]},{"name":"looks_4","tags":["4","digit","looks","numbers","square","symbol"]},{"name":"cloud_circle","tags":["app","application","backup","circle","cloud","connection","drive","files","folders","internet","network","sky","storage","upload"]},{"name":"format_shapes","tags":["alphabet","character","color","doc","edit","editing","editor","fill","font","format","letter","paint","shapes","sheet","spreadsheet","style","symbol","text","type","writing"]},{"name":"car_rental","tags":["automobile","car","cars","key","maps","rental","transportation","vehicle"]},{"name":"movie_filter","tags":["ai","artificial","automatic","automation","clapperboard","creation","custom","film","filter","genai","intelligence","magic","movie","movies","slate","smart","spark","sparkle","star","stars","video"]},{"name":"layers_clear","tags":["arrange","clear","delete","disabled","enabled","interaction","layers","maps","off","on","overlay","pages","slash"]},{"name":"phonelink_lock","tags":["Android","OS","cell","connection","device","erase","hardware","iOS","lock","locked","mobile","password","phone","phonelink","privacy","private","protection","safety","secure","security","tablet"]},{"name":"attractions","tags":["amusement","attractions","entertainment","ferris","fun","maps","park","places","wheel"]},{"name":"playlist_add_check_circle","tags":["add","album","artist","audio","cd","check","circle","collection","list","mark","music","playlist","record","sound","track"]},{"name":"hive","tags":["bee","honey","honeycomb"]},{"name":"no_photography","tags":["camera","disabled","enabled","image","no","off","on","photo","photography","picture","slash"]},{"name":"content_paste_go","tags":["clipboard","content","disabled","doc","document","enabled","file","go","on","paste","slash"]},{"name":"shop_two","tags":["add","arrow","buy","cart","google","play","purchase","shop","shopping","two"]},{"name":"edit_location","tags":["destination","direction","edit","location","maps","pen","pencil","pin","place","stop"]},{"name":"screen_rotation","tags":["Android","OS","arrow","device","hardware","iOS","mobile","phone","rotate","rotation","screen","tablet","turn"]},{"name":"numbers","tags":["digit","number","numbers","symbol"]},{"name":"sim_card","tags":["camera","card","chip","device","memory","phone","sim","storage"]},{"name":"control_camera","tags":["adjust","arrow","arrows","camera","center","control","direction","left","move","right"]},{"name":"blender","tags":["appliance","blender","cooking","electric","juicer","kitchen","machine","vitamix"]},{"name":"flip_to_front","tags":["arrange","arrangement","back","flip","format","front","layout","move","order","sort","to"]},{"name":"sports_volleyball","tags":["athlete","athletic","ball","entertainment","exercise","game","hobby","social","sports","volleyball"]},{"name":"stairs","tags":["down","staircase","stairs","up"]},{"name":"keyboard_alt","tags":["alt","computer","device","hardware","input","keyboard","keypad","letter","office","text","type"]},{"name":"crop_din","tags":["adjust","adjustments","area","crop","din","edit","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"html","tags":["alphabet","brackets","character","code","css","develop","developer","engineer","engineering","font","html","letter","platform","symbol","text","type"]},{"name":"signal_wifi_statusbar_connected_no_internet_4","tags":["!","4","alert","attention","caution","cell","cellular","connected","danger","data","error","exclamation","important","internet","mark","mobile","network","no","notification","phone","signal","speed","statusbar","symbol","warning","wifi","wireless"]},{"name":"pivot_table_chart","tags":["analytics","arrow","arrows","bar","bars","chart","data","diagram","direction","drive","edit","editing","graph","grid","infographic","measure","metrics","pivot","rotate","sheet","statistics","table","tracking"]},{"name":"microwave","tags":["appliance","cooking","electric","heat","home","house","kitchen","machine","microwave"]},{"name":"folder_copy","tags":["content","copy","cut","data","doc","document","drive","duplicate","file","folder","folders","multiple","paste","sheet","slide","storage"]},{"name":"output","tags":[]},{"name":"gif_box","tags":["alphabet","animated","animation","bitmap","character","font","format","gif","graphics","interchange","letter","symbol","text","type"]},{"name":"voice_chat","tags":["bubble","cam","camera","chat","comment","communicate","facetime","feedback","message","speech","video","voice"]},{"name":"local_convenience_store","tags":["--","24","bill","building","business","card","cash","coin","commerce","company","convenience","credit","currency","dollars","local","maps","market","money","new","online","pay","payment","plus","shop","shopping","store","storefront","symbol"]},{"name":"gps_not_fixed","tags":["destination","direction","disabled","enabled","gps","location","maps","not fixed","off","on","online","place","pointer","slash","tracking"]},{"name":"high_quality","tags":["alphabet","character","definition","display","font","high","hq","letter","movie","movies","quality","resolution","screen","symbol","text","tv","type"]},{"name":"switch_right","tags":["arrows","directional","navigation","right","switch","toggle"]},{"name":"pages","tags":["article","gplus","pages","paper","post","star"]},{"name":"table_restaurant","tags":["bar","dining","table"]},{"name":"speaker_notes_off","tags":["bubble","chat","comment","communicate","disabled","enabled","format","list","message","notes","off","on","slash","speaker","speech","text"]},{"name":"phone_disabled","tags":["call","cell","contact","device","disabled","enabled","hardware","mobile","off","offline","on","phone","slash","telephone"]},{"name":"eject","tags":["disc","drive","dvd","eject","remove","triangle","usb"]},{"name":"control_point_duplicate","tags":["+","add","circle","control","duplicate","multiple","new","plus","point","symbol"]},{"name":"filter","tags":["edit","editing","effect","filter","image","landscape","mountain","mountains","photo","photography","picture","settings"]},{"name":"pest_control","tags":["bug","control","exterminator","insects","pest"]},{"name":"backpack","tags":["back","backpack","bag","book","bookbag","knapsack","pack","storage","travel"]},{"name":"leak_add","tags":["add","connection","data","leak","link","network","service","signals","synce","wireless"]},{"name":"zoom_in_map","tags":["arrow","arrows","destination","in","location","maps","move","place","stop","zoom"]},{"name":"brightness_7","tags":["7","brightness","circle","control","crescent","level","moon","screen","sun"]},{"name":"system_security_update_good","tags":["Android","OS","approve","cell","check","complete","device","done","good","hardware","iOS","mark","mobile","ok","phone","security","select","system","tablet","tick","update","validate","verified","yes"]},{"name":"ring_volume","tags":["call","calling","cell","contact","device","hardware","incoming","mobile","phone","ring","ringer","sound","telephone","volume"]},{"name":"money_off_csred","tags":["bill","card","cart","cash","coin","commerce","credit","csred","currency","disabled","dollars","enabled","money","off","on","online","pay","payment","shopping","slash","symbol"]},{"name":"sports_football","tags":["athlete","athletic","ball","entertainment","exercise","football","game","hobby","social","sports"]},{"name":"nature","tags":["forest","nature","outdoor","outside","park","tree","wilderness"]},{"name":"vibration","tags":["Android","OS","alert","cell","device","hardware","iOS","mobile","mode","motion","notification","phone","silence","silent","tablet","vibrate","vibration"]},{"name":"snippet_folder","tags":["data","doc","document","drive","file","folder","sheet","slide","snippet","storage"]},{"name":"edit_road","tags":["destination","direction","edit","highway","maps","pen","pencil","road","street","traffic"]},{"name":"run_circle","tags":["body","circle","exercise","human","people","person","run","running"]},{"name":"dry_cleaning","tags":["cleaning","dry","hanger","hotel","laundry","places","service","towel"]},{"name":"alarm_off","tags":["alarm","alert","bell","clock","disabled","duration","enabled","notification","off","on","slash","time","timer","watch"]},{"name":"perm_data_setting","tags":["data","gear","info","information","perm","settings"]},{"name":"bedroom_parent","tags":["bed","bedroom","double","full","furniture","home","hotel","house","king","night","parent","pillows","queen","rest","room","sizem master","sleep"]},{"name":"airline_seat_recline_normal","tags":["airline","body","extra","feet","human","leg","legroom","normal","people","person","recline","seat","sitting","space","travel"]},{"name":"currency_bitcoin","tags":["bill","blockchain","card","cash","coin","commerce","cost","credit","currency","digital","dollars","finance","franc","money","online","pay","payment","price","shopping","symbol"]},{"name":"do_disturb_alt","tags":["cancel","close","denied","deny","disturb","do","remove","silence","stop"]},{"name":"sensor_window","tags":["alarm","security","security system"]},{"name":"incomplete_circle","tags":["chart","circle","incomplete"]},{"name":"settings_input_hdmi","tags":["cable","connection","connectivity","definition","hdmi","high","input","plug","plugin","points","settings","video","wire"]},{"name":"camera_indoor","tags":["architecture","building","camera","estate","film","filming","home","house","image","indoor","inside","motion","nest","picture","place","real","residence","residential","shelter","video","videography"]},{"name":"edit_location_alt","tags":["alt","edit","location","pen","pencil","pin"]},{"name":"texture","tags":["diagonal","lines","pattern","stripes","texture"]},{"name":"location_off","tags":["destination","direction","location","maps","off","pin","place","room","stop"]},{"name":"edit_attributes","tags":["approve","attribution","check","complete","done","edit","mark","ok","select","tick","validate","verified","yes"]},{"name":"duo","tags":["call","chat","conference","device","duo","video"]},{"name":"slow_motion_video","tags":["arrow","control","controls","motion","music","play","slow","speed","video"]},{"name":"perm_scan_wifi","tags":["alert","announcement","connection","info","information","internet","network","perm","scan","service","signal","wifi","wireless"]},{"name":"phonelink_setup","tags":["Android","OS","call","chat","device","hardware","iOS","info","mobile","phone","phonelink","settings","setup","tablet","text"]},{"name":"hourglass_disabled","tags":["clock","countdown","disabled","empty","enabled","hourglass","loading","minute","minutes","off","on","slash","time","wait","waiting"]},{"name":"add_to_queue","tags":["+","Android","OS","add","chrome","desktop","device","display","hardware","iOS","mac","monitor","new","plus","queue","screen","symbol","to","web","window"]},{"name":"pie_chart_outline","tags":["analytics","bar","bars","chart","data","diagram","graph","infographic","measure","metrics","outline","pie","statistics","tracking"]},{"name":"playlist_remove","tags":["-","collection","list","minus","music","playlist","remove"]},{"name":"next_week","tags":["arrow","bag","baggage","briefcase","business","case","next","suitcase","week"]},{"name":"church","tags":["christian","christianity","religion","spiritual","worship"]},{"name":"medical_information","tags":["badge","card","health","id","information","medical","services"]},{"name":"view_compact","tags":["compact","grid","layout","pattern","squares","view"]},{"name":"timer_off","tags":["alarm","alert","bell","clock","disabled","duration","enabled","notification","off","on","slash","stop","time","timer","watch"]},{"name":"bluetooth_connected","tags":["bluetooth","cast","connect","connection","device","paring","streaming","symbol","wireless"]},{"name":"photo_size_select_actual","tags":["actual","image","mountain","mountains","photo","photography","picture","select","size"]},{"name":"short_text","tags":["brief","comment","doc","document","note","short","text","write","writing"]},{"name":"bedroom_baby","tags":["babies","baby","bedroom","child","children","home","horse","house","infant","kid","newborn","rocking","room","toddler","young"]},{"name":"video_camera_back","tags":["back","camera","image","landscape","mountain","mountains","photo","photography","picture","rear","video"]},{"name":"bathroom","tags":["bath","bathroom","closet","home","house","place","plumbing","room","shower","sprinkler","wash","water","wc"]},{"name":"downhill_skiing","tags":["athlete","athletic","body","downhill","entertainment","exercise","hobby","human","people","person","ski social","skiing","snow","sports","travel","winter"]},{"name":"filter_list_off","tags":["alt","disabled","edit","filter","list","off","offline","options","refine","sift","slash"]},{"name":"connected_tv","tags":["Android","OS","airplay","chrome","connect","connected","desktop","device","display","hardware","iOS","mac","monitor","screen","screencast","streaming","television","tv","web","window","wireless"]},{"name":"format_indent_increase","tags":["align","alignment","doc","edit","editing","editor","format","increase","indent","indentation","paragraph","sheet","spreadsheet","text","type","writing"]},{"name":"settings_cell","tags":["Android","OS","cell","device","hardware","iOS","mobile","phone","settings","tablet"]},{"name":"remember_me","tags":["Android","OS","avatar","device","hardware","human","iOS","identity","me","mobile","people","person","phone","profile","remember","tablet","user"]},{"name":"kayaking","tags":["athlete","athletic","body","canoe","entertainment","exercise","hobby","human","kayak","kayaking","lake","paddle","paddling","people","person","rafting","river","row","social","sports","summer","travel","water"]},{"name":"switch_access_shortcut_add","tags":["+","access","add","arrow","arrows","direction","navigation","new","north","plus","shortcut","switch","symbol","up"]},{"name":"app_blocking","tags":["Android","OS","app","application","block","blocking","cancel","cell","device","hardware","iOS","mobile","phone","stop","stopped","tablet"]},{"name":"elevator","tags":["body","down","elevator","human","people","person","up"]},{"name":"work_off","tags":["bag","baggage","briefcase","business","case","disabled","enabled","job","off","on","slash","suitcase","work"]},{"name":"sensors_off","tags":["connection","disabled","enabled","network","off","on","scan","sensors","signal","slash","wireless"]},{"name":"stay_primary_portrait","tags":["Android","OS","current","device","hardware","iOS","mobile","phone","portrait","primary","stay","tablet"]},{"name":"cell_tower","tags":["broadcast","casting","cell","network","signal","tower","transmitting","wireless"]},{"name":"moped","tags":["automobile","bike","car","cars","maps","scooter","transportation","vehicle","vespa"]},{"name":"wrong_location","tags":["cancel","close","destination","direction","exit","location","maps","no","pin","place","quit","remove","stop","wrong","x"]},{"name":"groups_2","tags":["body","club","collaboration","crowd","gathering","groups","hair","human","meeting","people","person","social","teams"]},{"name":"public_off","tags":["disabled","earth","enabled","global","globe","map","network","off","on","planet","public","slash","social","space","web","world"]},{"name":"picture_in_picture_alt","tags":["crop","cropped","overlap","photo","picture","position","shape"]},{"name":"chair_alt","tags":["cahir","furniture","home","house","kitchen","lounging","seating","table"]},{"name":"car_repair","tags":["automobile","car","cars","maps","repair","transportation","vehicle"]},{"name":"airplay","tags":["airplay","arrow","connect","control","desktop","device","display","monitor","screen","signal"]},{"name":"nfc","tags":["communication","data","field","mobile","near","nfc","wireless"]},{"name":"line_style","tags":["dash","dotted","line","rule","spacing","style"]},{"name":"transform","tags":["adjust","crop","edit","editing","image","photo","picture","transform"]},{"name":"single_bed","tags":["bed","bedroom","double","furniture","home","hotel","house","king","night","pillows","queen","rest","room","single","sleep","twin"]},{"name":"pattern","tags":["key","login","password","pattern","pin","security","star","unlock"]},{"name":"local_movies","tags":[]},{"name":"repeat_one","tags":["1","arrow","arrows","control","controls","digit","media","music","number","one","repeat","symbol","video"]},{"name":"swap_calls","tags":["arrow","arrows","calls","device","direction","mobile","share","swap"]},{"name":"do_not_disturb_alt","tags":["cancel","close","denied","deny","disturb","do","remove","silence","stop"]},{"name":"smoking_rooms","tags":["allowed","cigarette","places","rooms","smoke","smoking","tobacco","zone"]},{"name":"remove_moderator","tags":["certified","disabled","enabled","moderator","off","on","privacy","private","protect","protection","remove","security","shield","slash","verified"]},{"name":"perm_device_information","tags":["Android","OS","alert","announcement","device","hardware","i","iOS","info","information","mobile","perm","phone","tablet"]},{"name":"wash","tags":["bathroom","clean","fingers","gesture","hand","wash","wc"]},{"name":"mode_standby","tags":["disturb","mode","power","sleep","standby","target"]},{"name":"door_sliding","tags":["auto","automatic","door","doorway","double","entrance","exit","glass","home","house","sliding","two"]},{"name":"skateboarding","tags":["athlete","athletic","body","entertainment","exercise","hobby","human","people","person","skate","skateboarder","skateboarding","social","sports"]},{"name":"difference","tags":["compare","content","copy","cut","diff","difference","doc","document","duplicate","file","multiple","past"]},{"name":"group_remove","tags":["accounts","committee","face","family","friends","group","humans","network","people","persons","profiles","remove","social","team","users"]},{"name":"brightness_high","tags":["auto","brightness","control","high","mobile","monitor","phone","sun"]},{"name":"cabin","tags":["architecture","cabin","camping","cottage","estate","home","house","log","maps","place","real","residence","residential","stay","traveling","wood"]},{"name":"camera_outdoor","tags":["architecture","building","camera","estate","film","filming","home","house","image","motion","nest","outdoor","outside","picture","place","real","residence","residential","shelter","video","videography"]},{"name":"troubleshoot","tags":["analytics","chart","data","diagram","find","glass","graph","infographic","line","look","magnify","magnifying","measure","metrics","search","see","statistics","tracking","troubleshoot"]},{"name":"tablet_android","tags":["OS","android","device","hardware","iOS","ipad","mobile","tablet","web"]},{"name":"house_siding","tags":["architecture","building","construction","estate","exterior","facade","home","house","real","residential","siding"]},{"name":"satellite","tags":["bluetooth","connect","connection","connectivity","data","device","image","internet","landscape","location","maps","mountain","mountains","network","photo","photography","picture","satellite","scan","service","signal","symbol","wireless-- wifi"]},{"name":"motion_photos_on","tags":["animation","circle","disabled","enabled","motion","off","on","photos","play","slash","video"]},{"name":"door_back","tags":["back","closed","door","doorway","entrance","exit","home","house","way"]},{"name":"strikethrough_s","tags":["alphabet","character","cross","doc","edit","editing","editor","font","letter","out","s","sheet","spreadsheet","strikethrough","styles","symbol","text","type","writing"]},{"name":"co2","tags":["carbon","chemical","co2","dioxide","gas"]},{"name":"notifications_paused","tags":["active","alarm","alert","bell","chime","ignore","notifications","notify","paused","quiet","reminder","ring --- pause","sleep","snooze","sound","z","zzz"]},{"name":"currency_yen","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","shopping","symbol","yen"]},{"name":"call_to_action","tags":["action","alert","bar","call","components","cta","design","info","information","interface","layout","message","notification","screen","site","to","ui","ux","web","website","window"]},{"name":"photo_camera_front","tags":["account","camera","face","front","human","image","people","person","photo","photography","picture","portrait","profile","user"]},{"name":"directions_boat_filled","tags":["automobile","boat","car","cars","direction","directions","ferry","filled","maps","public","transportation","vehicle"]},{"name":"subtitles_off","tags":["accessibility","accessible","caption","cc","closed","disabled","enabled","language","off","on","slash","subtitle","subtitles","translate","video"]},{"name":"rotate_90_degrees_ccw","tags":["90","arrow","arrows","ccw","degrees","direction","edit","editing","image","photo","rotate","turn"]},{"name":"vertical_align_center","tags":["align","alignment","arrow","center","doc","down","edit","editing","editor","sheet","spreadsheet","text","type","up","vertical","writing"]},{"name":"living","tags":["chair","comfort","couch","decoration","furniture","home","house","living","lounging","loveseat","room","seat","seating","sofa"]},{"name":"battery_saver","tags":["+","add","battery","charge","charging","new","plus","power","saver","symbol"]},{"name":"hot_tub","tags":["bath","bathing","bathroom","bathtub","hot","hotel","human","jacuzzi","person","shower","spa","steam","travel","tub","water"]},{"name":"play_lesson","tags":["audio","book","bookmark","digital","ebook","lesson","multimedia","play","play lesson","read","reading","ribbon"]},{"name":"update_disabled","tags":["arrow","back","backwards","clock","date","disabled","enabled","forward","history","load","off","on","refresh","reverse","rotate","schedule","slash","time","update"]},{"name":"psychology_alt","tags":["?","assistance","behavior","body","brain","cognitive","function","gear","head","help","human","info","information","intellectual","mental","mind","people","person","preferences","psychiatric","psychology","punctuation","question mark","science","settings","social","support","symbol","therapy","thinking","thoughts"]},{"name":"cast_connected","tags":["Android","OS","airplay","cast","chrome","connect","connected","desktop","device","display","hardware","iOS","mac","monitor","screen","screencast","streaming","television","tv","web","window","wireless"]},{"name":"format_color_reset","tags":["clear","color","disabled","doc","droplet","edit","editing","editor","enabled","fill","format","off","on","paint","reset","sheet","slash","spreadsheet","style","text","type","water","writing"]},{"name":"snooze","tags":["alarm","bell","clock","duration","notification","snooze","time","timer","watch","z"]},{"name":"person_remove_alt_1","tags":[]},{"name":"align_horizontal_left","tags":["align","alignment","format","horizontal","layout","left","lines","paragraph","rule","rules","style","text"]},{"name":"boy","tags":["body","boy","gender","human","male","man","people","person","social","symbol"]},{"name":"battery_5_bar","tags":["5","bar","battery","cell","charge","mobile","power"]},{"name":"mic_external_on","tags":["audio","disabled","enabled","external","mic","microphone","off","on","slash","sound","voice"]},{"name":"voicemail","tags":["call","device","message","missed","mobile","phone","recording","voice","voicemail"]},{"name":"join_full","tags":["circle","combine","command","full","join","left","outer","overlap","right","sql"]},{"name":"looks_5","tags":["5","digit","looks","numbers","square","symbol"]},{"name":"countertops","tags":["counter","countertops","home","house","kitchen","sink","table","tops"]},{"name":"energy_savings_leaf","tags":["eco","energy","leaf","leaves","nest","savings","usage"]},{"name":"safety_divider","tags":["apart","distance","divider","safety","separate","social","space"]},{"name":"move_up","tags":["arrow","direction","jump","move","navigation","transfer","up"]},{"name":"storm","tags":["forecast","hurricane","storm","temperature","twister","weather","wind"]},{"name":"sync_disabled","tags":["360","around","arrow","arrows","direction","disabled","enabled","inprogress","load","loading refresh","off","on","renew","rotate","slash","sync","turn"]},{"name":"javascript","tags":["alphabet","brackets","character","code","css","develop","developer","engineer","engineering","font","html","javascript","letter","platform","symbol","text","type"]},{"name":"tram","tags":["automobile","car","cars","direction","maps","public","rail","subway","train","tram","transportation","vehicle"]},{"name":"app_shortcut","tags":["app","bookmarked","favorite","highlight","important","marked","mobile","save","saved","shortcut","software","special","star"]},{"name":"data_saver_off","tags":["analytics","bar","bars","chart","data","diagram","donut","graph","infographic","measure","metrics","off","on","ring","saver","statistics","tracking"]},{"name":"laptop_windows","tags":["Android","OS","chrome","device","display","hardware","iOS","laptop","mac","monitor","screen","web","window","windows"]},{"name":"doorbell","tags":["alarm","bell","door","doorbell","home","house","ringing"]},{"name":"hd","tags":["alphabet","character","definition","display","font","hd","high","letter","movie","movies","resolution","screen","symbol","text","tv","type"]},{"name":"file_download_off","tags":["arrow","disabled","down","download","drive","enabled","export","file","install","off","on","save","slash","upload"]},{"name":"apps_outage","tags":["all","applications","apps","circles","collection","components","dots","grid","interface","outage","squares","ui","ux"]},{"name":"taxi_alert","tags":["!","alert","attention","automobile","cab","car","cars","caution","danger","direction","error","exclamation","important","lyft","maps","mark","notification","public","symbol","taxi","transportation","uber","vehicle","warning","yellow"]},{"name":"breakfast_dining","tags":["bakery","bread","breakfast","butter","dining","food","toast"]},{"name":"brightness_medium","tags":["auto","brightness","control","medium","mobile","monitor","phone","sun"]},{"name":"gradient","tags":["color","edit","editing","effect","filter","gradient","image","images","photography","picture","pictures"]},{"name":"swipe_left","tags":["arrow","arrows","finger","hand","hit","left","navigation","reject","strike","swing","swipe","take"]},{"name":"soup_kitchen","tags":["breakfast","brunch","dining","food","kitchen","lunch","meal","soup"]},{"name":"voice_over_off","tags":["account","disabled","enabled","face","human","off","on","over","people","person","profile","recording","slash","speak","speaking","speech","transcript","user","voice"]},{"name":"water_damage","tags":["architecture","building","damage","drop","droplet","estate","house","leak","plumbing","real","residence","residential","shelter","water"]},{"name":"abc","tags":["alphabet","character","font","letter","symbol","text","type"]},{"name":"data_saver_on","tags":["+","add","analytics","chart","data","diagram","graph","infographic","measure","metrics","new","on","plus","ring","saver","statistics","symbol","tracking"]},{"name":"signal_wifi_0_bar","tags":["0","bar","cell","cellular","data","internet","mobile","network","phone","signal","wifi","wireless"]},{"name":"brightness_low","tags":["auto","brightness","control","low","mobile","monitor","phone","sun"]},{"name":"device_unknown","tags":["?","Android","OS","assistance","cell","device","hardware","help","iOS","info","information","mobile","phone","punctuation","question mark","support","symbol","tablet","unknown"]},{"name":"fire_extinguisher","tags":["emergency","extinguisher","fire","water"]},{"name":"fitbit","tags":["athlete","athletic","exercise","fitbit","fitness","hobby","logo"]},{"name":"bedroom_child","tags":["bed","bedroom","child","children","furniture","home","hotel","house","kid","night","pillows","rest","room","size","sleep","twin","young"]},{"name":"closed_caption_off","tags":["accessible","alphabet","caption","cc","character","closed","decoder","font","language","letter","media","movies","off","outline","subtitle","subtitles","symbol","text","tv","type"]},{"name":"bluetooth_searching","tags":["bluetooth","connection","device","paring","search","searching","symbol"]},{"name":"content_paste_off","tags":["clipboard","content","disabled","doc","document","enabled","file","off","on","paste","slash"]},{"name":"hexagon","tags":["hexagon","shape","six sides"]},{"name":"tap_and_play","tags":["Android","OS wifi","cell","connection","device","hardware","iOS","internet","mobile","network","phone","play","signal","tablet","tap","to","wireless"]},{"name":"domain_add","tags":["+","add","apartment","architecture","building","business","domain","estate","home","new","place","plus","real","residence","residential","shelter","symbol","web","www"]},{"name":"signpost","tags":["arrow","direction","left","maps","right","signal","signs","street","traffic"]},{"name":"screenshot","tags":["Android","OS","cell","crop","device","hardware","iOS","mobile","phone","screen","screenshot","tablet"]},{"name":"network_cell","tags":["cell","cellular","data","internet","mobile","network","phone","speed","wifi","wireless"]},{"name":"repeat_on","tags":["arrow","arrows","control","controls","media","music","on","repeat","video"]},{"name":"charging_station","tags":["Android","OS","battery","bolt","cell","charging","device","electric","hardware","iOS","lightning","mobile","phone","station","tablet","thunderbolt"]},{"name":"grid_4x4","tags":["4","by","grid","layout","lines","space"]},{"name":"assistant_photo","tags":["assistant","flag","photo","recommendation","smart","star","suggestion"]},{"name":"carpenter","tags":["building","carpenter","construction","cutting","handyman","repair","saw","tool"]},{"name":"private_connectivity","tags":["connectivity","lock","locked","password","privacy","private","protection","safety","secure","security"]},{"name":"mobiledata_off","tags":["arrow","data","disabled","down","enabled","internet","mobile","network","off","on","slash","speed","up","wifi","wireless"]},{"name":"atm","tags":["alphabet","atm","automated","bill","card","cart","cash","character","coin","commerce","credit","currency","dollars","font","letter","machine","money","online","pay","payment","shopping","symbol","teller","text","type"]},{"name":"rv_hookup","tags":["arrow","attach","automobile","automotive","back","car","cars","connect","direction","hookup","left","maps","public","right","rv","trailer","transportation","travel","truck","van","vehicle"]},{"name":"replay_30","tags":["30","arrow","arrows","control","controls","digit","music","number","refresh","renew","repeat","replay","symbol","thirty","video"]},{"name":"offline_share","tags":["Android","OS","arrow","cell","connect","device","direction","hardware","iOS","link","mobile","multiple","offline","phone","right","share","tablet"]},{"name":"settings_input_svideo","tags":["cable","connection","connectivity","definition","input","plug","plugin","points","settings","standard","svideo","video"]},{"name":"soap","tags":["bathroom","clean","fingers","gesture","hand","soap","wash","wc"]},{"name":"baby_changing_station","tags":["babies","baby","bathroom","body","changing","child","children","father","human","infant","kids","mother","newborn","people","person","station","toddler","wc","young"]},{"name":"sports_cricket","tags":["athlete","athletic","ball","bat","cricket","entertainment","exercise","game","hobby","social","sports"]},{"name":"ad_units","tags":["Android","OS","ad","banner","cell","device","hardware","iOS","mobile","notification","notifications","phone","tablet","top","units"]},{"name":"wb_twilight","tags":["balance","light","lighting","noon","sun","sunset","twilight","wb","white"]},{"name":"no_encryption","tags":["disabled","enabled","encryption","lock","no","off","on","password","safety","security","slash"]},{"name":"table_bar","tags":["bar","cafe","round","table"]},{"name":"diversity_2","tags":["committee","diverse","diversity","family","friends","group","groups","heart","humans","network","people","persons","social","team"]},{"name":"subway","tags":["automobile","bike","car","cars","maps","rail","scooter","subway","train","transportation","travel","tunnel","underground","vehicle","vespa"]},{"name":"browser_updated","tags":["Android","OS","arrow","browser","chrome","desktop","device","display","download","hardware","iOS","mac","monitor","screen","updated","web","window"]},{"name":"currency_pound","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","pound","price","shopping","symbol"]},{"name":"transit_enterexit","tags":["arrow","direction","enterexit","maps","navigation","route","transit","transportation"]},{"name":"contrast","tags":["black","contrast","edit","editing","effect","filter","grayscale","image","images","photography","picture","pictures","settings","white"]},{"name":"lightbulb_circle","tags":["alert","announcement","idea","info","information","light","lightbulb"]},{"name":"rectangle","tags":["four sides","parallelograms","polygons","quadrilaterals","recangle","shape"]},{"name":"call_merge","tags":["arrow","call","device","merge","mobile"]},{"name":"hide_image","tags":["disabled","enabled","hide","image","landscape","mountain","mountains","off","on","photo","photography","picture","slash"]},{"name":"shield_moon","tags":["certified","do not disturb","moon","night","privacy","private","protect","protection","security","shield","verified"]},{"name":"group_off","tags":["body","club","collaboration","crowd","gathering","group","human","meeting","off","people","person","social","teams"]},{"name":"music_off","tags":["audio","audiotrack","disabled","enabled","key","music","note","off","on","slash","sound","track"]},{"name":"bluetooth_disabled","tags":["bluetooth","cast","connect","connection","device","disabled","enabled","off","offline","on","paring","slash","streaming","symbol","wireless"]},{"name":"flip_to_back","tags":["arrange","arrangement","back","flip","format","front","layout","move","order","sort","to"]},{"name":"sd_card","tags":["camera","card","digital","memory","photos","sd","secure","storage"]},{"name":"exposure_plus_1","tags":["1","add","brightness","contrast","digit","edit","editing","effect","exposure","image","number","photo","photography","plus","settings","symbol"]},{"name":"view_array","tags":["array","design","format","grid","layout","view","website"]},{"name":"sports_mma","tags":["arts","athlete","athletic","boxing","combat","entertainment","exercise","fighting","game","glove","hobby","martial","mixed","mma","social","sports"]},{"name":"straight","tags":["arrow","arrows","direction","directions","maps","navigation","path","route","sign","straight","traffic","up"]},{"name":"thermostat_auto","tags":["A","auto","celsius","fahrenheit","meter","temp","temperature","thermometer","thermostat"]},{"name":"mobile_screen_share","tags":["Android","OS","cast","cell","device","hardware","iOS","mirror","mobile","monitor","phone","screen","screencast","share","stream","streaming","tablet","tv","wireless"]},{"name":"phone_missed","tags":["arrow","call","cell","contact","device","hardware","missed","mobile","phone","telephone"]},{"name":"brunch_dining","tags":["breakfast","brunch","champagne","dining","drink","food","lunch","meal"]},{"name":"featured_video","tags":["advertised","advertisement","featured","highlighted","recommended","video","watch"]},{"name":"merge","tags":["arrow","arrows","direction","directions","maps","merge","navigation","path","route","sign","traffic"]},{"name":"open_in_new_off","tags":["arrow","box","disabled","enabled","export","in","new","off","on","open","slash","window"]},{"name":"hdr_auto","tags":["A","alphabet","auto","camera","character","circle","dynamic","font","hdr","high","letter","photo","range","symbol","text","type"]},{"name":"join_inner","tags":["circle","command","inner","join","matching","overlap","sql","values"]},{"name":"solar_power","tags":["eco","energy","heat","nest","power","solar","sun","sunny"]},{"name":"crop_16_9","tags":["16","9","adjust","adjustments","area","by","crop","edit","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"swipe_right","tags":["accept","arrows","direction","finger","hands","hit","navigation","right","strike","swing","swpie","take"]},{"name":"phonelink_erase","tags":["Android","OS","cancel","cell","close","connection","device","erase","exit","hardware","iOS","mobile","no","phone","phonelink","remove","stop","tablet","x"]},{"name":"smoke_free","tags":["cigarette","disabled","enabled","free","never","no","off","on","places","prohibited","slash","smoke","smoking","tobacco","warning","zone"]},{"name":"install_desktop","tags":["Android","OS","chrome","desktop","device","display","fix","hardware","iOS","install","mac","monitor","place","pwa","screen","web","window"]},{"name":"shutter_speed","tags":["aperture","camera","duration","image","lens","photo","photography","photos","picture","setting","shutter","speed","stop","time","timer","watch"]},{"name":"keyboard_hide","tags":["arrow","computer","device","down","hardware","hide","input","keyboard","keypad","text"]},{"name":"exposure","tags":["add","brightness","contrast","edit","editing","effect","exposure","image","minus","photo","photography","picture","plus","settings","subtract"]},{"name":"nordic_walking","tags":["athlete","athletic","body","entertainment","exercise","hiking","hobby","human","nordic","people","person","social","sports","travel","walker","walking"]},{"name":"umbrella","tags":["beach","protection","rain","sun","sunny","umbrella"]},{"name":"move_down","tags":["arrow","direction","down","jump","move","navigation","transfer"]},{"name":"filter_2","tags":["2","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"photo_album","tags":["album","archive","bookmark","image","label","library","mountain","mountains","photo","photography","picture","ribbon","save","tag"]},{"name":"security_update_good","tags":["Android","OS","checkmark","device","good","hardware","iOS","mobile","ok","phone","security","tablet","tick","update"]},{"name":"ssid_chart","tags":["chart","graph","lines","network","ssid","wifi"]},{"name":"score","tags":["2k","alphabet","analytics","bar","bars","character","chart","data","diagram","digit","font","graph","infographic","letter","measure","metrics","number","score","statistics","symbol","text","tracking","type"]},{"name":"swipe_up","tags":["arrows","direction","disable","enable","finger","hands","hit","navigation","strike","swing","swpie","take","up"]},{"name":"battery_4_bar","tags":["4","bar","battery","cell","charge","mobile","power"]},{"name":"all_out","tags":["all","circle","out","shape"]},{"name":"battery_unknown","tags":["?","assistance","battery","cell","charge","help","info","information","mobile","power","punctuation","question mark","support","symbol","unknown"]},{"name":"sports_golf","tags":["athlete","athletic","ball","club","entertainment","exercise","game","golf","golfer","golfing","hobby","social","sports"]},{"name":"sports_martial_arts","tags":["arts","athlete","athletic","entertainment","exercise","hobby","human","karate","martial","people","person","social","sports"]},{"name":"filter_tilt_shift","tags":["blur","center","edit","editing","effect","filter","focus","image","images","photography","picture","pictures","shift","tilt"]},{"name":"electric_bike","tags":["bike","electric","electricity","maps","scooter","transportation","travel","vespa"]},{"name":"border_all","tags":["all","border","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"auto_mode","tags":["ai","around","arrow","arrows","artificial","auto","automatic","automation","custom","direction","genai","inprogress","intelligence","load","loading refresh","magic","mode","navigation","nest","renew","rotate","smart","spark","sparkle","star","turn"]},{"name":"hvac","tags":["air","conditioning","heating","hvac","ventilation"]},{"name":"scanner","tags":["copy","device","hardware","machine","scan","scanner"]},{"name":"shuffle_on","tags":["arrow","arrows","control","controls","music","on","random","shuffle","video"]},{"name":"wifi_calling_3","tags":["3","calling","cell","cellular","data","internet","mobile","network","phone","speed","wifi","wireless"]},{"name":"signal_wifi_off","tags":["cell","cellular","data","disabled","enabled","internet","mobile","network","off","on","phone","signal","slash","speed","wifi","wireless"]},{"name":"girl","tags":["body","female","gender","girl","human","lady","people","person","social","symbol","woman","women"]},{"name":"shop_2","tags":["2","add","arrow","buy","cart","google","play","purchase","shop","shopping"]},{"name":"hdr_strong","tags":["circles","dots","dynamic","enhance","hdr","high","range","strong"]},{"name":"directions_transit","tags":["automobile","car","cars","direction","directions","maps","public","rail","subway","train","transit","transportation","vehicle"]},{"name":"label_off","tags":["disabled","enabled","favorite","indent","label","library","mail","off","on","remember","save","slash","stamp","sticker","tag","wing"]},{"name":"tablet","tags":["Android","OS","device","hardware","iOS","ipad","mobile","tablet","web"]},{"name":"5g","tags":["5g","alphabet","cellular","character","data","digit","font","letter","mobile","network","number","phone","signal","speed","symbol","text","type","wifi"]},{"name":"vrpano","tags":["angle","image","landscape","mountain","mountains","panorama","photo","photography","picture","view","vrpano","wide"]},{"name":"forward_30","tags":["30","arrow","control","controls","digit","fast","forward","music","number","seconds","symbol","video"]},{"name":"battery_0_bar","tags":["0","bar","battery","cell","charge","mobile","power"]},{"name":"airline_seat_recline_extra","tags":["airline","body","extra","feet","human","leg","legroom","people","person","seat","sitting","space","travel"]},{"name":"looks","tags":["circle","half","looks","rainbow"]},{"name":"linked_camera","tags":["camera","connect","connection","lens","linked","network","photo","photography","picture","signal","signals","sync","wireless"]},{"name":"paragliding","tags":["athlete","athletic","body","entertainment","exercise","fly","gliding","hobby","human","parachute","paragliding","people","person","sky","skydiving","social","sports","travel"]},{"name":"electric_scooter","tags":["bike","electric","maps","scooter","transportation","vehicle","vespa"]},{"name":"settings_system_daydream","tags":["backup","cloud","daydream","drive","settings","storage","system"]},{"name":"format_indent_decrease","tags":["align","alignment","decrease","doc","edit","editing","editor","format","indent","indentation","paragraph","sheet","spreadsheet","text","type","writing"]},{"name":"tapas","tags":["appetizer","brunch","dinner","food","lunch","restaurant","snack","tapas"]},{"name":"brightness_3","tags":["3","brightness","circle","control","crescent","level","moon","screen"]},{"name":"tab_unselected","tags":["browser","computer","document","documents","folder","internet","tab","tabs","unselected","web","website","window","windows"]},{"name":"density_small","tags":["density","horizontal","lines","rule","rules","small"]},{"name":"blur_circular","tags":["blur","circle","circular","dots","edit","editing","effect","enhance","filter"]},{"name":"rice_bowl","tags":["bowl","dinner","food","lunch","meal","restaurant","rice"]},{"name":"rounded_corner","tags":["adjust","corner","edit","rounded","shape","square","transform"]},{"name":"person_add_disabled","tags":["+","account","add","disabled","enabled","face","human","new","off","offline","on","people","person","plus","profile","slash","symbol","user"]},{"name":"music_video","tags":["band","music","recording","screen","tv","video","watch"]},{"name":"looks_6","tags":["6","digit","looks","numbers","square","symbol"]},{"name":"do_not_touch","tags":["disabled","do","enabled","fingers","gesture","hand","not","off","on","slash","touch"]},{"name":"playlist_add_circle","tags":["add","album","artist","audio","cd","check","circle","collection","list","mark","music","playlist","record","sound","track"]},{"name":"domain_disabled","tags":["apartment","architecture","building","business","company","disabled","domain","enabled","estate","home","internet","maps","off","office","offline","on","place","real","residence","residential","slash","web","website"]},{"name":"flash_auto","tags":["a","auto","bolt","electric","fast","flash","lightning","thunderbolt"]},{"name":"6_ft_apart","tags":["6","apart","body","covid","distance","feet","ft","human","people","person","social"]},{"name":"signal_wifi_bad","tags":["bad","bar","cancel","cell","cellular","close","data","exit","internet","mobile","network","no","phone","quit","remove","signal","stop","wifi","wireless","x"]},{"name":"crisis_alert","tags":["!","alert","attention","bullseye","caution","crisis","danger","error","exclamation","important","mark","notification","symbol","target","warning"]},{"name":"queue_play_next","tags":["+","add","arrow","desktop","device","display","hardware","monitor","new","next","play","plus","queue","screen","steam","symbol","tv"]},{"name":"format_clear","tags":["T","alphabet","character","clear","disabled","doc","edit","editing","editor","enabled","font","format","letter","off","on","sheet","slash","spreadsheet","style","symbol","text","type","writing"]},{"name":"bus_alert","tags":["!","alert","attention","automobile","bus","car","cars","caution","danger","error","exclamation","important","maps","mark","notification","symbol","transportation","vehicle","warning"]},{"name":"party_mode","tags":["camera","lens","mode","party","photo","photography","picture"]},{"name":"snowboarding","tags":["athlete","athletic","body","entertainment","exercise","hobby","human","people","person","snow","snowboarding","social","sports","travel","winter"]},{"name":"text_rotate_vertical","tags":["A","alphabet","arrow","character","down","field","font","letter","move","rotate","symbol","text","type","vertical"]},{"name":"motion_photos_auto","tags":["A","alphabet","animation","auto","automatic","character","circle","font","gif","letter","live","motion","photos","symbol","text","type","video"]},{"name":"crop_portrait","tags":["adjust","adjustments","area","crop","edit","editing","frame","image","images","photo","photos","portrait","rectangle","settings","size","square"]},{"name":"thunderstorm","tags":["bolt","climate","cloud","cloudy","lightning","rain","rainfall","rainstorm","storm","thunder","thunderstorm","weather"]},{"name":"battery_6_bar","tags":["6","bar","battery","cell","charge","mobile","power"]},{"name":"space_bar","tags":["bar","keyboard","line","space"]},{"name":"replay_5","tags":["5","arrow","arrows","control","controls","digit","five","music","number","refresh","renew","repeat","replay","symbol","video"]},{"name":"local_car_wash","tags":["automobile","car","cars","local","maps","transportation","travel","vehicle","wash"]},{"name":"folder_delete","tags":["bin","can","data","delete","doc","document","drive","file","folder","folders","garbage","remove","sheet","slide","storage","trash"]},{"name":"data_thresholding","tags":["data","hidden","privacy","thresholding","thresold"]},{"name":"connecting_airports","tags":["airplane","airplanes","airport","airports","connecting","flight","plane","transportation","travel","trip"]},{"name":"access_alarms","tags":[]},{"name":"tty","tags":["call","cell","contact","deaf","device","hardware","impaired","mobile","phone","speech","talk","telephone","text","tty"]},{"name":"audio_file","tags":["audio","doc","document","key","music","note","sound","track"]},{"name":"egg","tags":["breakfast","brunch","egg","food"]},{"name":"balcony","tags":["architecture","balcony","doors","estate","home","house","maps","out","outside","place","real","residence","residential","stay","terrace","window"]},{"name":"kitesurfing","tags":["athlete","athletic","beach","body","entertainment","exercise","hobby","human","kitesurfing","people","person","social","sports","surf","travel","water"]},{"name":"call_missed_outgoing","tags":["arrow","call","device","missed","mobile","outgoing"]},{"name":"local_hotel","tags":["body","hotel","human","local","people","person","sleep","stay","travel","trip"]},{"name":"text_increase","tags":["+","add","alphabet","character","font","increase","letter","new","plus","resize","symbol","text","type"]},{"name":"speaker_phone","tags":["Android","OS","cell","device","hardware","iOS","mobile","phone","sound","speaker","tablet","volume"]},{"name":"no_food","tags":["disabled","drink","enabled","fastfood","food","hamburger","meal","no","off","on","slash"]},{"name":"brightness_2","tags":["2","brightness","circle","control","crescent","level","moon","screen"]},{"name":"mode_of_travel","tags":["arrow","destination","direction","location","maps","mode","of","pin","place","stop","transportation","travel","trip"]},{"name":"format_line_spacing","tags":["align","alignment","doc","edit","editing","editor","format","line","sheet","spacing","spreadsheet","text","type","writing"]},{"name":"iso","tags":["add","edit","editing","effect","image","iso","minus","photography","picture","plus","sensor","shutter","speed","subtract"]},{"name":"explore_off","tags":["compass","destination","direction","disabled","east","enabled","explore","location","maps","needle","north","off","on","slash","south","travel","west"]},{"name":"drive_file_move_rtl","tags":["arrow","arrows","data","direction","doc","document","drive","file","folder","folders","left","move","rtl","sheet","side","slide","storage"]},{"name":"cell_wifi","tags":["cell","connection","data","internet","mobile","network","phone","service","signal","wifi","wireless"]},{"name":"tonality","tags":["circle","edit","editing","filter","image","photography","picture","tonality"]},{"name":"spoke","tags":["connection","network","radius","spoke"]},{"name":"photo_filter","tags":["ai","artificial","automatic","automation","custom","filter","filters","genai","image","intelligence","magic","photo","photography","picture","smart","spark","sparkle","star"]},{"name":"desktop_access_disabled","tags":["Android","OS","access","chrome","desktop","device","disabled","display","enabled","hardware","iOS","mac","monitor","off","offline","on","screen","slash","web","window"]},{"name":"sports_gymnastics","tags":["athlete","athletic","entertainment","exercise","gymnastics","hobby","social","sports"]},{"name":"houseboat","tags":["architecture","beach","boat","estate","floating","home","house","houseboat","maps","place","real","residence","residential","sea","stay","traveling","vacation"]},{"name":"fence","tags":["backyard","barrier","boundaries","boundary","fence","home","house","protection","yard"]},{"name":"commit","tags":["accomplish","bind","circle","commit","dedicate","execute","line","perform","pledge"]},{"name":"photo_size_select_small","tags":["adjust","album","edit","editing","image","large","library","mountain","mountains","photo","photography","picture","select","size","small"]},{"name":"signal_wifi_connected_no_internet_4","tags":["4","cell","cellular","connected","data","internet","mobile","network","no","offline","phone","signal","wifi","wireless","x"]},{"name":"horizontal_distribute","tags":["alignment","distribute","format","horizontal","layout","lines","paragraph","rule","rules","style","text"]},{"name":"report_off","tags":["!","alert","attention","caution","danger","disabled","enabled","error","exclamation","important","mark","notification","octagon","off","offline","on","report","slash","symbol","warning"]},{"name":"polyline","tags":["compose","create","design","draw","line","polyline","vector"]},{"name":"art_track","tags":["album","art","artist","audio","image","music","photo","photography","picture","sound","track","tracks"]},{"name":"crop_7_5","tags":["5","7","adjust","adjustments","area","by","crop","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"filter_hdr","tags":["camera","edit","editing","effect","filter","hdr","image","mountain","mountains","photo","photography","picture"]},{"name":"text_rotation_none","tags":["A","alphabet","arrow","character","field","font","letter","move","none","rotate","symbol","text","type"]},{"name":"battery_3_bar","tags":["3","bar","battery","cell","charge","mobile","power"]},{"name":"align_vertical_bottom","tags":["align","alignment","bottom","format","layout","lines","paragraph","rule","rules","style","text","vertical"]},{"name":"stop_screen_share","tags":["Android","OS","arrow","cast","chrome","device","disabled","display","enabled","hardware","iOS","laptop","mac","mirror","monitor","off","offline","on","screen","share","slash","steam","stop","streaming","web","window"]},{"name":"imagesearch_roller","tags":["art","image","imagesearch","paint","roller","search"]},{"name":"bento","tags":["bento","box","dinner","food","lunch","meal","restaurant","takeout"]},{"name":"rotate_90_degrees_cw","tags":["90","arrow","arrows","ccw","degrees","direction","edit","editing","image","photo","rotate","turn"]},{"name":"install_mobile","tags":["Android","OS","cell","device","hardware","iOS","install","mobile","phone","pwa","tablet"]},{"name":"hearing_disabled","tags":["accessibility","accessible","aid","disabled","ear","enabled","handicap","hearing","help","impaired","listen","off","on","slash","sound","volume"]},{"name":"video_file","tags":["camera","doc","document","film","filming","hardware","image","motion","picture","video","videography"]},{"name":"mms","tags":["bubble","chat","comment","communicate","feedback","image","landscape","message","mms","mountain","mountains","multimedia","photo","photography","picture","speech"]},{"name":"crop_rotate","tags":["adjust","adjustments","area","arrow","arrows","crop","edit","editing","frame","image","images","photo","photos","rotate","settings","size","turn"]},{"name":"wheelchair_pickup","tags":["accessibility","accessible","body","handicap","help","human","person","pickup","wheelchair"]},{"name":"aod","tags":["Android","OS","always","aod","device","display","hardware","homescreen","iOS","mobile","on","phone","tablet"]},{"name":"castle","tags":["castle","fort","fortress","mansion","palace"]},{"name":"interpreter_mode","tags":["interpreter","language","microphone","mode","person","speaking","symbol"]},{"name":"access_alarm","tags":[]},{"name":"forward_5","tags":["10","5","arrow","control","controls","digit","fast","forward","music","number","seconds","symbol","video"]},{"name":"add_to_home_screen","tags":["Android","OS","add to","arrow","cell","device","hardware","home","iOS","mobile","phone","screen","tablet","up"]},{"name":"not_accessible","tags":["accessibility","accessible","body","handicap","help","human","not","person","wheelchair"]},{"name":"signal_cellular_0_bar","tags":["0","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","wifi","wireless"]},{"name":"stadium","tags":["activity","amphitheater","arena","coliseum","event","local","stadium","star","things","ticket"]},{"name":"photo_size_select_large","tags":["adjust","album","edit","editing","image","large","library","mountain","mountains","photo","photography","picture","select","size"]},{"name":"groups_3","tags":["abstract","body","club","collaboration","crowd","gathering","groups","human","meeting","people","person","social","teams"]},{"name":"snowshoeing","tags":["body","human","people","person","snow","snowshoe","snowshoeing","sports","travel","walking","winter"]},{"name":"view_kanban","tags":["grid","kanban","layout","pattern","squares","view"]},{"name":"candlestick_chart","tags":["analytics","candlestick","chart","data","diagram","finance","graph","infographic","measure","metrics","statistics","tracking"]},{"name":"filter_3","tags":["3","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"arrow_outward","tags":["app","application","arrow","arrows","components","direction","forward","interface","navigation","right","screen","site","ui","ux","web","website"]},{"name":"align_horizontal_center","tags":["align","alignment","center","format","horizontal","layout","lines","paragraph","rule","rules","style","text"]},{"name":"flashlight_off","tags":["disabled","enabled","flash","flashlight","light","off","on","slash"]},{"name":"security_update","tags":["Android","OS","arrow","device","down","download","hardware","iOS","mobile","phone","security","tablet","update"]},{"name":"iron","tags":["appliance","clothes","electric","iron","ironing","machine","object"]},{"name":"print_disabled","tags":["disabled","enabled","off","on","paper","print","printer","slash"]},{"name":"pin_invoke","tags":["action","arrow","dot","invoke","pin"]},{"name":"speaker_group","tags":["box","electronic","group","loud","multiple","music","sound","speaker","stereo","system","video"]},{"name":"exposure_zero","tags":["0","brightness","contrast","digit","edit","editing","effect","exposure","image","number","photo","photography","settings","symbol","zero"]},{"name":"bungalow","tags":["architecture","bungalow","cottage","estate","home","house","maps","place","real","residence","residential","stay","traveling"]},{"name":"streetview","tags":["maps","street","streetview","view"]},{"name":"swipe_down","tags":["arrows","direction","disable","down","enable","finger","hands","hit","navigation","strike","swing","swpie","take"]},{"name":"hdr_weak","tags":["circles","dots","dynamic","enhance","hdr","high","range","weak"]},{"name":"css","tags":["alphabet","brackets","character","code","css","develop","developer","engineer","engineering","font","html","letter","platform","symbol","text","type"]},{"name":"call_missed","tags":["arrow","call","device","missed","mobile"]},{"name":"gps_off","tags":["destination","direction","disabled","enabled","gps","location","maps","not fixed","off","offline","on","place","pointer","slash","tracking"]},{"name":"sports_hockey","tags":["athlete","athletic","entertainment","exercise","game","hobby","hockey","social","sports","sticks"]},{"name":"ice_skating","tags":["athlete","athletic","entertainment","exercise","hobby","ice","shoe","skates","skating","social","sports","travel"]},{"name":"keyboard_capslock","tags":["arrow","capslock","keyboard","up"]},{"name":"earbuds","tags":["accessory","audio","earbuds","earphone","headphone","listen","music","sound"]},{"name":"camera_front","tags":["body","camera","front","human","lens","mobile","person","phone","photography","portrait","selfie"]},{"name":"vertical_distribute","tags":["alignment","distribute","format","layout","lines","paragraph","rule","rules","style","text","vertical"]},{"name":"currency_ruble","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","ruble","shopping","symbol"]},{"name":"signal_wifi_statusbar_null","tags":["cell","cellular","data","internet","mobile","network","null","phone","signal","speed","statusbar","wifi","wireless"]},{"name":"align_horizontal_right","tags":["align","alignment","format","horizontal","layout","lines","paragraph","right","rule","rules","style","text"]},{"name":"crop_5_4","tags":["4","5","adjust","adjustments","area","by","crop","edit","editing settings","frame","image","images","photo","photos","rectangle","size","square"]},{"name":"format_strikethrough","tags":["alphabet","character","doc","edit","editing","editor","font","format","letter","sheet","spreadsheet","strikethrough","style","symbol","text","type","writing"]},{"name":"face_6","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"join_left","tags":["circle","command","join","left","matching","overlap","sql","values"]},{"name":"explicit","tags":["adult","alphabet","character","content","e","explicit","font","language","letter","media","movies","music","symbol","text","type"]},{"name":"extension_off","tags":["disabled","enabled","extended","extension","jigsaw","off","on","piece","puzzle","shape","slash"]},{"name":"perm_camera_mic","tags":["camera","image","microphone","min","perm","photo","photography","picture","speaker"]},{"name":"sports_rugby","tags":["athlete","athletic","ball","entertainment","exercise","game","hobby","rugby","social","sports"]},{"name":"pause_presentation","tags":["app","application desktop","device","pause","present","presentation","screen","share","site","slides","web","website","window","www"]},{"name":"south_america","tags":["continent","landscape","place","region","south america"]},{"name":"sd_storage","tags":["camera","card","data","digital","memory","sd","secure","storage"]},{"name":"superscript","tags":["2","doc","edit","editing","editor","gmail","novitas","sheet","spreadsheet","style","superscript","symbol","text","writing","x"]},{"name":"4g_mobiledata","tags":["4g","alphabet","cellular","character","digit","font","letter","mobile","mobiledata","network","number","phone","signal","speed","symbol","text","type","wifi"]},{"name":"pinch","tags":["arrow","arrows","compress","direction","finger","grasp","hand","navigation","nip","pinch","squeeze","tweak"]},{"name":"lock_person","tags":[]},{"name":"grid_3x3","tags":["3","grid","layout","line","space"]},{"name":"mark_unread_chat_alt","tags":["bubble","chat","circle","comment","communicate","mark","message","notification","speech","unread"]},{"name":"web_stories","tags":["google","images","logo","stories","web"]},{"name":"safety_check","tags":["certified","check","clock","privacy","private","protect","protection","safety","schedule","security","shield","time","verified"]},{"name":"filter_frames","tags":["boarders","border","camera","center","edit","editing","effect","filter","filters","focus","frame","frames","image","options","photo","photography","picture"]},{"name":"spatial_audio_off","tags":["audio","disabled","enabled","music","note","off","offline","on","slash","sound","spatial"]},{"name":"directions_subway","tags":["automobile","car","cars","direction","directions","maps","public","rail","subway","train","transportation","vehicle"]},{"name":"reset_tv","tags":["arrow","device","hardware","monitor","reset","television","tv"]},{"name":"4k","tags":["4000","4K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"burst_mode","tags":["burst","image","landscape","mode","mountain","mountains","multiple","photo","photography","picture"]},{"name":"chalet","tags":["architecture","chalet","cottage","estate","home","house","maps","place","real","residence","residential","stay","traveling"]},{"name":"battery_1_bar","tags":["1","bar","battery","cell","charge","mobile","power"]},{"name":"elderly_woman","tags":["body","cane","elderly","female","gender","girl","human","lady","old","people","person","senior","social","symbol","woman","women"]},{"name":"headset_off","tags":["accessory","audio","chat","device","disabled","ear","earphone","enabled","headphones","headset","listen","mic","music","off","on","slash","sound","talk"]},{"name":"swipe_vertical","tags":["arrows","direction","finger","hands","hit","navigation","strike","swing","swpie","take","verticle"]},{"name":"crib","tags":["babies","baby","bassinet","bed","child","children","cradle","crib","infant","kid","newborn","sleeping","toddler"]},{"name":"video_label","tags":["label","screen","video","window"]},{"name":"fiber_smart_record","tags":["circle","dot","fiber","play","record","smart","watch"]},{"name":"brightness_auto","tags":["A","auto","brightness","control","display","level","mobile","monitor","phone","screen","sun"]},{"name":"margin","tags":["design","layout","margin","padding","size","square"]},{"name":"punch_clock","tags":["clock","date","punch","schedule","time","timer","timesheet"]},{"name":"compass_calibration","tags":["calibration","compass","connection","internet","location","maps","network","refresh","service","signal","wifi","wireless"]},{"name":"mosque","tags":["islam","islamic","masjid","muslim","religion","spiritual","worship"]},{"name":"medication_liquid","tags":["+","bottle","doctor","drug","health","hospital","liquid","medications","medicine","pharmacy","spoon","vessel"]},{"name":"camera_roll","tags":["camera","film","image","library","photo","photography","roll"]},{"name":"pin_end","tags":["action","arrow","dot","end","pin"]},{"name":"dialer_sip","tags":["alphabet","call","cell","character","contact","device","dialer","font","hardware","initiation","internet","letter","mobile","over","phone","protocol","routing","session","sip","symbol","telephone","text","type","voice"]},{"name":"oil_barrel","tags":["barrel","droplet","gas","gasoline","nest","oil","water"]},{"name":"disc_full","tags":["!","alert","attention","caution","cd","danger","disc","error","exclamation","full","important","mark","music","notification","storage","symbol","warning"]},{"name":"signal_cellular_connected_no_internet_4_bar","tags":["!","4","alert","attention","bar","caution","cell","cellular","connected","danger","data","error","exclamation","important","internet","mark","mobile","network","no","notification","phone","signal","symbol","warning","wifi","wireless"]},{"name":"wind_power","tags":["eco","energy","nest","power","wind","windy"]},{"name":"logo_dev","tags":["dev","dev.to","logo"]},{"name":"sledding","tags":["athlete","athletic","body","entertainment","exercise","hobby","human","people","person","sled","sledding","sledge","snow","social","sports","travel","winter"]},{"name":"invert_colors_off","tags":["colors","disabled","drop","droplet","enabled","hue","invert","inverted","off","offline","on","opacity","palette","slash","tone","water"]},{"name":"wifi_lock","tags":["cellular","connection","data","internet","lock","locked","mobile","network","password","privacy","private","protection","safety","secure","security","service","signal","wifi","wireless"]},{"name":"noise_aware","tags":["audio","aware","cancellation","music","noise","note","sound"]},{"name":"face_3","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"car_crash","tags":["accident","automobile","car","cars","collision","crash","direction","maps","public","transportation","vehicle"]},{"name":"comments_disabled","tags":["bubble","chat","comment","comments","communicate","disabled","enabled","feedback","message","off","offline","on","slash","speech"]},{"name":"data_array","tags":["array","brackets","code","coder","data","parentheses"]},{"name":"do_not_disturb_on_total_silence","tags":["busy","disturb","do","mute","no","not","on total","quiet","silence"]},{"name":"filter_b_and_w","tags":["and","b","black","contrast","edit","editing","effect","filter","grayscale","image","images","photography","picture","pictures","settings","w","white"]},{"name":"no_encryption_gmailerrorred","tags":["disabled","enabled","encryption","error","gmail","lock","locked","no","off","on","slash"]},{"name":"blur_linear","tags":["blur","dots","edit","editing","effect","enhance","filter","linear"]},{"name":"view_cozy","tags":["comfy","cozy","design","format","layout","view","web"]},{"name":"wifi_calling","tags":["call","calling","cell","connect","connection","connectivity","contact","device","hardware","mobile","phone","signal","telephone","wifi","wireless"]},{"name":"electric_rickshaw","tags":["automobile","car","cars","electric","india","maps","rickshaw","transportation","truck","vehicle"]},{"name":"rtt","tags":["call","real","rrt","text","time"]},{"name":"join_right","tags":["circle","command","join","matching","overlap","right","sql","values"]},{"name":"crop_3_2","tags":["2","3","adjust","adjustments","area","by","crop","edit","editing","frame","image","images","photo","photos","rectangle","settings","size","square"]},{"name":"crop_landscape","tags":["adjust","adjustments","area","crop","edit","editing","frame","image","images","landscape","photo","photos","settings","size"]},{"name":"nearby_error","tags":["!","alert","attention","caution","danger","error","exclamation","important","mark","nearby","notification","symbol","warning"]},{"name":"airplanemode_inactive","tags":["airplane","airplanemode","airport","disabled","enabled","flight","fly","inactive","maps","mode","off","offline","on","slash","transportation","travel"]},{"name":"airline_stops","tags":["airline","arrow","destination","direction","layover","location","maps","place","stops","transportation","travel","trip"]},{"name":"bluetooth_audio","tags":["audio","bluetooth","connect","connection","device","music","signal","sound","symbol"]},{"name":"portable_wifi_off","tags":["connection","data","disabled","enabled","internet","network","off","offline","on","portable","service","signal","slash","wifi","wireless"]},{"name":"turn_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sign","traffic","turn"]},{"name":"1x_mobiledata","tags":["1x","alphabet","cellular","character","digit","font","letter","mobile","mobiledata","network","number","phone","signal","speed","symbol","text","type","wifi"]},{"name":"do_not_step","tags":["boot","disabled","do","enabled","feet","foot","not","off","on","shoe","slash","sneaker","step","steps"]},{"name":"sensor_occupied","tags":["body","body response","connection","fitbit","human","network","people","person","scan","sensors","signal","smart body scan sensor","wireless"]},{"name":"directions_railway","tags":["automobile","car","cars","direction","directions","maps","public","railway","train","transportation","vehicle"]},{"name":"security_update_warning","tags":["!","Android","OS","alert","attention","caution","danger","device","download","error","exclamation","hardware","iOS","important","mark","mobile","notification","phone","security","symbol","tablet","update","warning"]},{"name":"pentagon","tags":["five sides","pentagon","shape"]},{"name":"wrap_text","tags":["arrow writing","doc","edit","editing","editor","sheet","spreadsheet","text","type","wrap","write","writing"]},{"name":"no_meeting_room","tags":["building","disabled","door","doorway","enabled","entrance","home","house","interior","meeting","no","off","office","on","open","places","room","slash"]},{"name":"sd_card_alert","tags":["!","alert","attention","camera","card","caution","danger","digital","error","exclamation","important","mark","memory","notification","photos","sd","secure","storage","symbol","warning"]},{"name":"deselect","tags":["all","disabled","enabled","off","on","selection","slash","square","tool"]},{"name":"switch_camera","tags":["arrow","arrows","camera","photo","photography","picture","switch"]},{"name":"text_rotate_up","tags":["A","alphabet","arrow","character","field","font","letter","move","rotate","symbol","text","type","up"]},{"name":"sync_lock","tags":["around","arrow","arrows","lock","locked","password","privacy","private","protection","renew","rotate","safety","secure","security","sync","turn"]},{"name":"switch_video","tags":["arrow","arrows","camera","photography","switch","video","videos"]},{"name":"border_clear","tags":["border","clear","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"repeat_one_on","tags":["arrow","arrows","control","controls","digit","media","music","number","on","one","repeat","symbol","video"]},{"name":"no_meals","tags":["dining","disabled","eat","enabled","food","fork","knife","meal","meals","no","off","on","restaurant","slash","spoon","utensils"]},{"name":"align_vertical_top","tags":["align","alignment","format","layout","lines","paragraph","rule","rules","style","text","top","vertical"]},{"name":"subscript","tags":["2","doc","edit","editing","editor","gmail","novitas","sheet","spreadsheet","style","subscript","symbol","text","writing","x"]},{"name":"font_download_off","tags":["alphabet","character","disabled","download","enabled","font","letter","off","on","slash","square","symbol","text","type"]},{"name":"scoreboard","tags":["board","points","score","scoreboard","sports"]},{"name":"swipe_right_alt","tags":["accept","alt","arrows","direction","finger","hands","hit","navigation","right","strike","swing","swpie","take"]},{"name":"align_vertical_center","tags":["align","alignment","center","format","layout","lines","paragraph","rule","rules","style","text","vertical"]},{"name":"electric_meter","tags":["bolt","electric","energy","fast","lightning","measure","meter","nest","thunderbolt","usage","voltage","volts"]},{"name":"contact_emergency","tags":["account","avatar","call","cell","contacts","face","human","info","information","mobile","people","person","phone","profile","user"]},{"name":"signal_cellular_connected_no_internet_0_bar","tags":["!","0","alert","attention","bar","caution","cell","cellular","connected","danger","data","error","exclamation","important","internet","mark","mobile","network","no","notification","phone","signal","symbol","warning","wifi","wireless"]},{"name":"sim_card_alert","tags":["!","alert","attention","camera","card","caution","danger","digital","error","exclamation","important","mark","memory","notification","photos","sd","secure","storage","symbol","warning"]},{"name":"battery_2_bar","tags":["2","bar","battery","cell","charge","mobile","power"]},{"name":"text_rotation_angleup","tags":["A","alphabet","angleup","arrow","character","field","font","letter","move","rotate","symbol","text","type"]},{"name":"text_rotation_down","tags":["A","alphabet","arrow","character","dow","field","font","letter","move","rotate","symbol","text","type"]},{"name":"railway_alert","tags":["!","alert","attention","automobile","bike","car","cars","caution","danger","direction","error","exclamation","important","maps","mark","notification","public","railway","scooter","subway","symbol","train","transportation","vehicle","vespa","warning"]},{"name":"escalator","tags":["down","escalator","staircase","up"]},{"name":"electric_moped","tags":["automobile","bike","car","cars","electric","maps","moped","scooter","transportation","travel","vehicle","vespa"]},{"name":"closed_caption_disabled","tags":["accessible","alphabet","caption","cc","character","closed","decoder","disabled","enabled","font","language","letter","media","movies","off","on","slash","subtitle","subtitles","symbol","text","tv","type"]},{"name":"filter_7","tags":["7","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"heat_pump","tags":["air conditioner","cool","energy","furnance","heat","nest","pump","usage"]},{"name":"dry","tags":["air","bathroom","dry","dryer","fingers","gesture","hand","wc"]},{"name":"fork_right","tags":["arrow","arrows","direction","directions","fork","maps","navigation","path","right","route","sign","traffic"]},{"name":"text_rotation_angledown","tags":["A","alphabet","angledown","arrow","character","field","font","letter","move","rotate","symbol","text","type"]},{"name":"do_not_disturb_off","tags":["cancel","close","denied","deny","disabled","disturb","do","enabled","off","on","remove","silence","slash","stop"]},{"name":"screen_lock_portrait","tags":["Android","OS","device","hardware","iOS","lock","mobile","phone","portrait","rotate","screen","tablet"]},{"name":"send_time_extension","tags":["deliver","dispatch","envelop","extension","mail","message","schedule","send","time"]},{"name":"keyboard_command_key","tags":["button","command key","control","keyboard"]},{"name":"remove_from_queue","tags":["desktop","device","display","from","hardware","monitor","queue","remove","screen","steam"]},{"name":"filter_4","tags":["4","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"filter_9_plus","tags":["+","9","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","plus","settings","stack","symbol"]},{"name":"exposure_plus_2","tags":["2","add","brightness","contrast","digit","edit","editing","effect","exposure","image","number","photo","photography","plus","settings","symbol"]},{"name":"surround_sound","tags":["circle","signal","sound","speaker","surround","system","volumn","wireless"]},{"name":"airline_seat_individual_suite","tags":["airline","body","business","class","first","human","individual","people","person","rest","seat","sleep","suite","travel"]},{"name":"home_max","tags":["device","gadget","hardware","home","internet","iot","max","nest","smart","things"]},{"name":"phone_paused","tags":["call","cell","contact","device","hardware","mobile","pause","paused","phone","telephone"]},{"name":"local_play","tags":[]},{"name":"stroller","tags":["baby","care","carriage","child","children","infant","kid","newborn","stroller","toddler","young"]},{"name":"wifi_password","tags":["(scan)","[cellular","connection","data","internet","lock","mobile]","network","password","secure","service","signal","wifi","wireless"]},{"name":"browse_gallery","tags":["clock","collection","gallery","library","stack","watch"]},{"name":"system_security_update","tags":["Android","OS","arrow","cell","device","down","hardware","iOS","mobile","phone","security","system","tablet","update"]},{"name":"person_2","tags":["account","face","human","people","person","profile","user"]},{"name":"screenshot_monitor","tags":["Android","OS","chrome","desktop","device","display","hardware","iOS","mac","monitor","screen","screengrab","screenshot","web","window"]},{"name":"wb_iridescent","tags":["balance","bright","edit","editing","iridescent","light","lighting","setting","settings","white","wp"]},{"name":"grid_off","tags":["collage","disabled","enabled","grid","image","layout","off","on","slash","view"]},{"name":"system_security_update_warning","tags":["!","Android","OS","alert","attention","caution","cell","danger","device","error","exclamation","hardware","iOS","important","mark","mobile","notification","phone","security","symbol","system","tablet","update","warning"]},{"name":"play_disabled","tags":["control","controls","disabled","enabled","media","music","off","on","play","slash","video"]},{"name":"php","tags":["alphabet","brackets","character","code","css","develop","developer","engineer","engineering","font","html","letter","php","platform","symbol","text","type"]},{"name":"phishing","tags":["fish","fishing","fraud","hook","phishing","scam"]},{"name":"border_style","tags":["border","color","doc","edit","editing","editor","sheet","spreadsheet","stroke","style","text","type","writing"]},{"name":"motion_photos_paused","tags":["animation","circle","motion","pause","paused","photos","video"]},{"name":"headphones_battery","tags":["accessory","audio","battery","charging","device","ear","earphone","headphones","headset","listen","music","sound"]},{"name":"monochrome_photos","tags":["black","camera","image","monochrome","photo","photography","photos","picture","white"]},{"name":"web_asset_off","tags":["asset","browser","disabled","enabled","internet","off","on","page","screen","slash","web","webpage","website","windows","www"]},{"name":"wifi_tethering_off","tags":["cell","cellular","connection","data","disabled","enabled","internet","mobile","network","off","offline","on","phone","scan","service","signal","slash","speed","tethering","wifi","wireless"]},{"name":"text_decrease","tags":["-","alphabet","character","decrease","font","letter","minus","remove","resize","subtract","symbol","text","type"]},{"name":"view_comfy_alt","tags":["alt","comfy","cozy","design","format","layout","view","web"]},{"name":"photo_camera_back","tags":["back","camera","image","landscape","mountain","mountains","photo","photography","picture","rear"]},{"name":"folder_off","tags":["data","disabled","doc","document","drive","enabled","file","folder","folders","off","on","online","sheet","slash","slide","storage"]},{"name":"gas_meter","tags":["droplet","energy","gas","measure","meter","nest","usage","water"]},{"name":"edgesensor_high","tags":["Android","OS","cell","device","edge","hardware","high","iOS","mobile","move","phone","sensitivity","sensor","tablet","vibrate"]},{"name":"filter_5","tags":["5","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"stay_current_landscape","tags":["Android","OS","current","device","hardware","iOS","landscape","mobile","phone","stay","tablet"]},{"name":"sip","tags":["alphabet","call","character","dialer","font","initiation","internet","letter","over","phone","protocol","routing","session","sip","symbol","text","type","voice"]},{"name":"power_input","tags":["input","lines","power","supply"]},{"name":"smart_screen","tags":["Android","OS","airplay","cast","cell","connect","device","hardware","iOS","mobile","phone","screen","screencast","smart","stream","tablet","video"]},{"name":"mail_lock","tags":["email","envelop","letter","lock","locked","mail","message","password","privacy","private","protection","safety","secure","security","send"]},{"name":"dataset","tags":[]},{"name":"nat","tags":["communication","nat"]},{"name":"do_disturb_off","tags":["cancel","close","denied","deny","disabled","disturb","do","enabled","off","on","remove","silence","slash","stop"]},{"name":"no_drinks","tags":["alcohol","beverage","bottle","cocktail","drink","drinks","food","liquor","no","wine"]},{"name":"bike_scooter","tags":["automobile","bike","car","cars","maps","scooter","transportation","vehicle","vespa"]},{"name":"dock","tags":["Android","OS","cell","charging","connector","device","dock","hardware","iOS","mobile","phone","power","station","tablet"]},{"name":"face_2","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"face_retouching_off","tags":["disabled","edit","editing","effect","emoji","emotion","enabled","face","faces","image","natural","off","on","photo","photography","retouch","retouching","settings","slash","tag"]},{"name":"auto_fix_off","tags":["ai","artificial","auto","automatic","automation","custom","disabled","edit","enabled","erase","fix","genai","intelligence","magic","modify","off","on","slash","smart","spark","sparkle","star","wand"]},{"name":"airline_seat_flat","tags":["airline","body","business","class","first","flat","human","people","person","rest","seat","sleep","travel"]},{"name":"phone_locked","tags":["call","cell","contact","device","hardware","lock","locked","mobile","password","phone","privacy","private","protection","safety","secure","security","telephone"]},{"name":"network_locked","tags":["alert","available","cellular","connection","data","error","internet","lock","locked","mobile","network","not","privacy","private","protection","restricted","safety","secure","security","service","signal","warning","wifi","wireless"]},{"name":"padding","tags":["design","layout","margin","padding","size","square"]},{"name":"browser_not_supported","tags":["browser","disabled","enabled","internet","not","off","on","page","screen","site","slash","supported","web","website","www"]},{"name":"border_outer","tags":["border","doc","edit","editing","editor","outer","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"exposure_neg_1","tags":["1","brightness","contrast","digit","edit","editing","effect","exposure","image","neg","negative","number","photo","photography","settings","symbol"]},{"name":"view_compact_alt","tags":["alt","compact","design","format","layout dense","view","web"]},{"name":"pest_control_rodent","tags":["control","exterminator","mice","pest","rodent"]},{"name":"swipe_down_alt","tags":["alt","arrows","direction","disable","down","enable","finger","hands","hit","navigation","strike","swing","swpie","take"]},{"name":"airlines","tags":["airlines","airplane","airport","flight","plane","transportation","travel","trip"]},{"name":"turn_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","route","sign","traffic","turn"]},{"name":"sd","tags":["alphabet","camera","card","character","data","device","digital","drive","flash","font","image","letter","memory","photo","sd","secure","symbol","text","type"]},{"name":"near_me_disabled","tags":["destination","direction","disabled","enabled","location","maps","me","navigation","near","off","on","pin","place","point","slash"]},{"name":"face_4","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"stay_primary_landscape","tags":["Android","OS","current","device","hardware","iOS","landscape","mobile","phone","primary","stay","tablet"]},{"name":"4g_plus_mobiledata","tags":["4g","alphabet","cellular","character","digit","font","letter","mobile","mobiledata","network","number","phone","plus","signal","speed","symbol","text","type","wifi"]},{"name":"snowmobile","tags":["automobile","car","direction","skimobile","snow","snowmobile","social","sports","transportation","travel","vehicle","winter"]},{"name":"sign_language","tags":["communication","deaf","fingers","gesture","hand","language","sign"]},{"name":"network_ping","tags":["alert","available","cellular","connection","data","internet","ip","mobile","network","ping","service","signal","wifi","wireless"]},{"name":"signal_cellular_off","tags":["cell","cellular","data","disabled","enabled","internet","mobile","network","off","offline","on","phone","signal","slash","wifi","wireless"]},{"name":"signal_cellular_nodata","tags":["cell","cellular","data","internet","mobile","network","no","nodata","offline","phone","quit","signal","wifi","wireless","x"]},{"name":"no_sim","tags":["camera","card","device","eject","insert","memory","no","phone","sim","storage"]},{"name":"signal_wifi_4_bar_lock","tags":["4","bar","cell","cellular","data","internet","lock","locked","mobile","network","password","phone","privacy","private","protection","safety","secure","security","signal","wifi","wireless"]},{"name":"missed_video_call","tags":["arrow","call","camera","film","filming","hardware","image","missed","motion","picture","record","video","videography"]},{"name":"lte_mobiledata","tags":["alphabet","character","data","font","internet","letter","lte","mobile","network","speed","symbol","text","type","wifi","wireless"]},{"name":"earbuds_battery","tags":["accessory","audio","battery","charging","earbuds","earphone","headphone","listen","music","sound"]},{"name":"panorama_photosphere","tags":["angle","horizontal","image","panorama","photo","photography","photosphere","picture","wide"]},{"name":"no_crash","tags":["accident","auto","automobile","car","cars","check","collision","confirm","correct","crash","direction","done","enter","maps","mark","no","ok","okay","select","tick","transportation","vehicle","yes"]},{"name":"add_alarm","tags":[]},{"name":"directions_transit_filled","tags":["automobile","car","cars","direction","directions","filled","maps","public","rail","subway","train","transit","transportation","vehicle"]},{"name":"u_turn_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","route","sign","traffic","u-turn"]},{"name":"line_axis","tags":["axis","dash","horizontal","line","stroke","vertical"]},{"name":"density_large","tags":["density","horizontal","large","lines","rule","rules"]},{"name":"location_disabled","tags":["destination","direction","disabled","enabled","location","maps","off","on","pin","place","pointer","slash","stop","tracking"]},{"name":"bluetooth_drive","tags":["automobile","bluetooth","car","cars","cast","connect","connection","device","drive","maps","paring","streaming","symbol","transportation","travel","vehicle","wireless"]},{"name":"30fps","tags":["30fps","alphabet","camera","character","digit","font","fps","frames","letter","number","symbol","text","type","video"]},{"name":"no_luggage","tags":["bag","baggage","carry","disabled","enabled","luggage","no","off","on","slash","suitcase","travel"]},{"name":"leak_remove","tags":["connection","data","disabled","enabled","leak","link","network","off","offline","on","remove","service","signals","slash","synce","wireless"]},{"name":"filter_8","tags":["8","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"mobile_off","tags":["Android","OS","cell","device","disabled","enabled","hardware","iOS","mobile","off","on","phone","silence","slash","tablet"]},{"name":"key_off","tags":["disabled","enabled","key","lock","off","offline","on","password","slash","unlock"]},{"name":"signal_cellular_null","tags":["cell","cellular","data","internet","mobile","network","null","phone","signal","wifi","wireless"]},{"name":"phonelink_off","tags":["Android","OS","chrome","computer","connect","desktop","device","disabled","enabled","hardware","iOS","link","mac","mobile","off","on","phone","phonelink","slash","sync","tablet","web","windows"]},{"name":"filter_9","tags":["9","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"home_mini","tags":["Internet","device","gadget","hardware","home","iot","mini","nest","smart","things"]},{"name":"on_device_training","tags":["arrow","bulb","call","cell","contact","device","hardware","idea","inprogress","light","load","loading","mobile","model","phone","refresh","renew","restore","reverse","rotate","telephone","training"]},{"name":"egg_alt","tags":["breakfast","brunch","egg","food"]},{"name":"media_bluetooth_on","tags":["bluetooth","connect","connection","connectivity","device","disabled","enabled","media","music","note","off","on","online","paring","signal","slash","symbol","wireless"]},{"name":"10k","tags":["10000","10K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"video_stable","tags":["film","filming","recording","setting","stability","stable","taping","video"]},{"name":"add_home","tags":[]},{"name":"no_transfer","tags":["automobile","bus","car","cars","direction","disabled","enabled","maps","no","off","on","public","slash","transfer","transportation","vehicle"]},{"name":"timer_10","tags":["10","digits","duration","number","numbers","seconds","time","timer"]},{"name":"directions_subway_filled","tags":["automobile","car","cars","direction","directions","filled","maps","public","rail","subway","train","transportation","vehicle"]},{"name":"wb_shade","tags":["balance","house","light","lighting","shade","wb","white"]},{"name":"swipe_left_alt","tags":["alt","arrow","arrows","finger","hand","hit","left","navigation","reject","strike","swing","swipe","take"]},{"name":"filter_6","tags":["6","digit","edit","editing","effect","filter","image","images","multiple","number","photography","picture","pictures","settings","stack","symbol"]},{"name":"cyclone","tags":["crisis","disaster","natural","rain","storm","weather","wind","winds"]},{"name":"network_wifi_1_bar","tags":[]},{"name":"directions_railway_filled","tags":["automobile","car","cars","direction","directions","filled","maps","public","railway","train","transportation","vehicle"]},{"name":"wifi_find","tags":["(scan)","[cellular","connection","data","detect","discover","find","internet","look","magnifying glass","mobile]","network","notice","search","service","signal","wifi","wireless"]},{"name":"blur_off","tags":["blur","disabled","dots","edit","editing","effect","enabled","enhance","off","on","slash"]},{"name":"motion_photos_off","tags":["animation","circle","disabled","enabled","motion","off","on","photos","slash","video"]},{"name":"lyrics","tags":["audio","bubble","chat","comment","communicate","feedback","key","lyrics","message","music","note","song","sound","speech","track"]},{"name":"raw_on","tags":["alphabet","character","disabled","enabled","font","image","letter","off","on","original","photo","photography","raw","slash","symbol","text","type"]},{"name":"flight_class","tags":["airplane","business","class","first","flight","plane","seat","transportation","travel","trip","window"]},{"name":"insert_page_break","tags":["break","doc","document","file","page","paper"]},{"name":"rsvp","tags":["alphabet","character","font","invitation","invite","letter","plaît","respond","rsvp","répondez","sil","symbol","text","type","vous"]},{"name":"tire_repair","tags":["auto","automobile","car","cars","gauge","mechanic","pressure","repair","tire","vehicle"]},{"name":"swipe_up_alt","tags":["alt","arrows","direction","disable","enable","finger","hands","hit","navigation","strike","swing","swpie","take","up"]},{"name":"3g_mobiledata","tags":["3g","alphabet","cellular","character","digit","font","letter","mobile","mobiledata","network","number","phone","signal","speed","symbol","text","type","wifi"]},{"name":"tv_off","tags":["Android","OS","chrome","desktop","device","disabled","enabled","hardware","iOS","mac","monitor","off","on","slash","television","tv","web","window"]},{"name":"hdr_on","tags":["add","alphabet","character","dynamic","enhance","font","hdr","high","letter","on","plus","range","select","symbol","text","type"]},{"name":"add_home_work","tags":[]},{"name":"motion_photos_pause","tags":["animation","circle","motion","pause","paused","photos","video"]},{"name":"edgesensor_low","tags":["Android","cell","device","edge","hardware","iOS","low","mobile","move","phone","sensitivity","sensor","tablet","vibrate"]},{"name":"grid_goldenratio","tags":["golden","goldenratio","grid","layout","lines","ratio","space"]},{"name":"network_wifi_3_bar","tags":[]},{"name":"temple_buddhist","tags":["buddha","buddhism","buddhist","monastery","religion","spiritual","temple","worship"]},{"name":"airline_seat_flat_angled","tags":["airline","angled","body","business","class","first","flat","human","people","person","rest","seat","sleep","travel"]},{"name":"fort","tags":["castle","fort","fortress","mansion","palace"]},{"name":"spatial_tracking","tags":["audio","disabled","enabled","music","note","off","offline","on","slash","sound","spatial","tracking"]},{"name":"screen_lock_rotation","tags":["Android","OS","arrow","device","hardware","iOS","lock","mobile","phone","rotate","rotation","screen","tablet","turn"]},{"name":"fiber_pin","tags":["alphabet","character","fiber","font","letter","network","pin","symbol","text","type"]},{"name":"phone_bluetooth_speaker","tags":["bluetooth","call","cell","connect","connection","connectivity","contact","device","hardware","mobile","phone","signal","speaker","symbol","telephone","wireless"]},{"name":"vignette","tags":["border","edit","editing","filter","gradient","image","photo","photography","setting","vignette"]},{"name":"panorama_horizontal","tags":["angle","horizontal","image","panorama","photo","photography","picture","wide"]},{"name":"propane_tank","tags":["bbq","gas","grill","nest","propane","tank"]},{"name":"kebab_dining","tags":["dining","dinner","food","kebab","meal","meat","skewer"]},{"name":"developer_board_off","tags":["board","chip","computer","developer","development","disabled","enabled","hardware","microchip","off","on","processor","slash"]},{"name":"adf_scanner","tags":["adf","document","feeder","machine","office","scan","scanner"]},{"name":"no_cell","tags":["Android","OS","cell","device","disabled","enabled","hardware","iOS","mobile","no","off","on","phone","slash","tablet"]},{"name":"dirty_lens","tags":["camera","dirty","lens","photo","photography","picture","splat"]},{"name":"usb_off","tags":["cable","connection","device","off","usb","wire"]},{"name":"image_aspect_ratio","tags":["aspect","image","photo","photography","picture","ratio","rectangle","square"]},{"name":"30fps_select","tags":["30","camera","digits","fps","frame","frequency","image","numbers","per","rate","second","seconds","select","video"]},{"name":"60fps","tags":["60fps","camera","digit","fps","frames","number","symbol","video"]},{"name":"screen_lock_landscape","tags":["Android","OS","device","hardware","iOS","landscape","lock","mobile","phone","rotate","screen","tablet"]},{"name":"lte_plus_mobiledata","tags":["+","alphabet","character","data","font","internet","letter","lte","mobile","network","plus","speed","symbol","text","type","wifi","wireless"]},{"name":"piano_off","tags":["disabled","enabled","instrument","keyboard","keys","music","musical","off","on","piano","slash","social"]},{"name":"unfold_more_double","tags":["arrow","arrows","chevron","collapse","direction","double","down","expand","expandable","list","more","navigation","unfold"]},{"name":"deblur","tags":["adjust","deblur","edit","editing","enhance","face","image","lines","photo","photography","sharpen"]},{"name":"person_4","tags":["account","face","human","people","person","profile","user"]},{"name":"spatial_audio","tags":["audio","music","note","sound","spatial"]},{"name":"camera_rear","tags":["camera","front","lens","mobile","phone","photo","photography","picture","portrait","rear","selfie"]},{"name":"timer_10_select","tags":["10","alphabet","camera","character","digit","font","letter","number","seconds","select","symbol","text","timer","type"]},{"name":"face_5","tags":["account","emoji","eyes","face","human","lock","log","login","logout","people","person","profile","recognition","security","social","thumbnail","unlock","user"]},{"name":"minor_crash","tags":["accident","auto","automobile","car","cars","collision","directions","maps","public","transportation","vehicle"]},{"name":"sos","tags":["font","help","letters","save","sos","text","type"]},{"name":"videogame_asset_off","tags":["asset","console","controller","device","disabled","enabled","game","gamepad","gaming","off","on","playstation","slash","video","videogame"]},{"name":"flood","tags":["crisis","disaster","natural","rain","storm","weather"]},{"name":"60fps_select","tags":["60","camera","digits","fps","frame","frequency","numbers","per","rate","second","seconds","select","video"]},{"name":"timer_3","tags":["3","digits","duration","number","numbers","seconds","time","timer"]},{"name":"vpn_key_off","tags":["code","disabled","enabled","key","lock","network","off","offline","on","passcode","password","slash","unlock","vpn"]},{"name":"directions_off","tags":["arrow","directions","disabled","enabled","maps","off","on","right","route","sign","slash","traffic"]},{"name":"emergency_share","tags":["alert","attention","caution","danger","emergency","important","notification","share","warning"]},{"name":"panorama_wide_angle_select","tags":["angle","image","panorama","photo","photography","picture","select","wide"]},{"name":"airline_seat_legroom_normal","tags":["airline","body","feet","human","leg","legroom","normal","people","person","seat","sitting","space","travel"]},{"name":"fiber_dvr","tags":["alphabet","character","digital","dvr","electronics","fiber","font","letter","network","record","recorder","symbol","text","tv","type","video"]},{"name":"person_3","tags":["account","face","human","people","person","profile","user"]},{"name":"scuba_diving","tags":["diving","entertainment","exercise","hobby","scuba","social","swim","swimming"]},{"name":"signal_cellular_no_sim","tags":["camera","card","cellular","chip","device","disabled","enabled","memory","no","off","offline","on","phone","signal","sim","slash","storage"]},{"name":"24mp","tags":["24","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"exposure_neg_2","tags":["2","brightness","contrast","digit","edit","editing","effect","exposure","image","neg","negative","number","photo","photography","settings","symbol"]},{"name":"network_wifi_2_bar","tags":[]},{"name":"wifi_2_bar","tags":["2","bar","cell","cellular","connection","data","internet","mobile","network","phone","scan","service","signal","wifi","wireless"]},{"name":"u_turn_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sign","traffic","u-turn"]},{"name":"currency_yuan","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","money","online","pay","payment","price","shopping","symbol","yuan"]},{"name":"currency_lira","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","lira","money","online","pay","payment","price","shopping","symbol"]},{"name":"no_flash","tags":["bolt","camera","disabled","enabled","flash","image","lightning","no","off","on","photo","photography","picture","slash","thunderbolt"]},{"name":"temple_hindu","tags":["hindu","hinduism","hindus","mandir","religion","spiritual","temple","worship"]},{"name":"mode_fan_off","tags":["air conditioner","cool","disabled","enabled","fan","nest","off","on","slash"]},{"name":"airline_seat_legroom_extra","tags":["airline","body","extra","feet","human","leg","legroom","people","person","seat","sitting","space","travel"]},{"name":"4k_plus","tags":["+","4000","4K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"border_inner","tags":["border","doc","edit","editing","editor","inner","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"wifi_tethering_error","tags":["!","alert","attention","caution","cell","cellular","connection","danger","data","error","exclamation","important","internet","mark","mobile","network","notification","phone","rounded","scan","service","signal","speed","symbol","tethering","warning","wifi","wireless"]},{"name":"airline_seat_legroom_reduced","tags":["airline","body","feet","human","leg","legroom","people","person","reduced","seat","sitting","space","travel"]},{"name":"synagogue","tags":["jew","jewish","religion","shul","spiritual","temple","worship"]},{"name":"border_left","tags":["border","doc","edit","editing","editor","left","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"autofps_select","tags":["A","alphabet","auto","character","font","fps","frame","frequency","letter","per","rate","second","seconds","select","symbol","text","type"]},{"name":"signal_cellular_alt_2_bar","tags":["2","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","wifi","wireless"]},{"name":"g_mobiledata","tags":["alphabet","character","data","font","g","letter","mobile","network","service","symbol","text","type"]},{"name":"1k","tags":["1000","1K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"format_textdirection_l_to_r","tags":["align","alignment","doc","edit","editing","editor","format","ltr","sheet","spreadsheet","text","textdirection","type","writing"]},{"name":"border_bottom","tags":["border","bottom","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"fork_left","tags":["arrow","arrows","direction","directions","fork","left","maps","navigation","path","route","sign","traffic"]},{"name":"severe_cold","tags":["!","alert","attention","caution","climate","cold","crisis","danger","disaster","error","exclamation","important","notification","severe","snow","snowflake","warning","weather","winter"]},{"name":"tsunami","tags":["crisis","disaster","flood","rain","storm","tsunami","weather"]},{"name":"signal_cellular_alt_1_bar","tags":["1","bar","cell","cellular","data","internet","mobile","network","phone","signal","speed","wifi","wireless"]},{"name":"border_vertical","tags":["border","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","type","vertical","writing"]},{"name":"turn_sharp_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sharp","sign","traffic","turn"]},{"name":"no_backpack","tags":["accessory","backpack","bag","bookbag","knapsack","no","pack","travel"]},{"name":"remove_road","tags":["-","cancel","close","destination","direction","exit","highway","maps","minus","new","no","remove","road","stop","street","symbol","traffic","x"]},{"name":"timer_3_select","tags":["3","alphabet","camera","character","digit","font","letter","number","seconds","select","symbol","text","timer","type"]},{"name":"roller_skating","tags":["athlete","athletic","entertainment","exercise","hobby","roller","shoe","skate","skates","skating","social","sports","travel"]},{"name":"panorama_horizontal_select","tags":["angle","horizontal","image","panorama","photo","photography","picture","select","wide"]},{"name":"border_horizontal","tags":["border","doc","edit","editing","editor","horizontal","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"2k","tags":["2000","2K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"wifi_1_bar","tags":["1","bar","cell","cellular","connection","data","internet","mobile","network","phone","scan","service","signal","wifi","wireless"]},{"name":"format_textdirection_r_to_l","tags":["align","alignment","doc","edit","editing","editor","format","rtl","sheet","spreadsheet","text","textdirection","type","writing"]},{"name":"wifi_channel","tags":["(scan)","[cellular","channel","connection","data","internet","mobile]","network","service","signal","wifi","wireless"]},{"name":"roundabout_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","roundabout","route","sign","traffic"]},{"name":"wb_auto","tags":["A","W","alphabet","auto","automatic","balance","character","edit","editing","font","image","letter","photo","photography","symbol","text","type","white","wp"]},{"name":"panorama_photosphere_select","tags":["angle","horizontal","image","panorama","photo","photography","photosphere","picture","select","wide"]},{"name":"panorama_wide_angle","tags":["angle","image","panorama","photo","photography","picture","wide"]},{"name":"hdr_plus","tags":["+","add","alphabet","character","circle","dynamic","enhance","font","hdr","high","letter","plus","range","select","symbol","text","type"]},{"name":"panorama_vertical_select","tags":["angle","image","panorama","photo","photography","picture","select","vertical","wide"]},{"name":"border_top","tags":["border","doc","edit","editing","editor","sheet","spreadsheet","stroke","text","top","type","writing"]},{"name":"mic_external_off","tags":["audio","disabled","enabled","external","mic","microphone","off","on","slash","sound","voice"]},{"name":"width_full","tags":[]},{"name":"h_mobiledata","tags":["alphabet","character","data","font","h","letter","mobile","network","service","symbol","text","type"]},{"name":"roller_shades","tags":["blinds","cover","curtains","nest","open","roller","shade","shutter","sunshade"]},{"name":"no_stroller","tags":["baby","care","carriage","child","children","disabled","enabled","infant","kid","newborn","no","off","on","parents","slash","stroller","toddler","young"]},{"name":"tornado","tags":["crisis","disaster","natural","rain","storm","tornado","weather","wind"]},{"name":"keyboard_control_key","tags":["control key","keyboard"]},{"name":"turn_slight_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sharp","sign","slight","traffic","turn"]},{"name":"border_right","tags":["border","doc","edit","editing","editor","right","sheet","spreadsheet","stroke","text","type","writing"]},{"name":"1k_plus","tags":["+","1000","1K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"turn_slight_left","tags":["arrow","arrows","direction","directions","maps","navigation","path","right","route","sign","slight","traffic","turn"]},{"name":"screen_rotation_alt","tags":["Android","OS","arrow","device","hardware","iOS","mobile","phone","rotate","rotation","screen","tablet","turn"]},{"name":"dataset_linked","tags":[]},{"name":"unfold_less_double","tags":["arrow","arrows","chevron","collapse","direction","double","expand","expandable","inward","less","list","navigation","unfold","up"]},{"name":"8k","tags":["8000","8K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"landslide","tags":["crisis","disaster","natural","rain","storm","weather"]},{"name":"media_bluetooth_off","tags":["bluetooth","connect","connection","connectivity","device","disabled","enabled","media","music","note","off","offline","on","paring","signal","slash","symbol","wireless"]},{"name":"fire_truck","tags":[]},{"name":"e_mobiledata","tags":["alphabet","data","e","font","letter","mobile","mobiledata","text","type"]},{"name":"panorama_vertical","tags":["angle","image","panorama","photo","photography","picture","vertical","wide"]},{"name":"r_mobiledata","tags":["alphabet","character","data","font","letter","mobile","r","symbol","text","type"]},{"name":"12mp","tags":["12","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"repartition","tags":["arrow","arrows","data","partition","refresh","renew","repartition","restore","table"]},{"name":"width_normal","tags":[]},{"name":"h_plus_mobiledata","tags":["+","alphabet","character","data","font","h","letter","mobile","network","plus","service","symbol","text","type"]},{"name":"hdr_enhanced_select","tags":["add","alphabet","character","dynamic","enhance","font","hdr","high","letter","plus","range","select","symbol","text","type"]},{"name":"mp","tags":["alphabet","character","font","image","letter","megapixel","mp","photo","photography","pixels","quality","resolution","symbol","text","type"]},{"name":"shape_line","tags":["circle","draw","edit","editing","line","shape","square"]},{"name":"9k_plus","tags":["+","9000","9K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"5k","tags":["5000","5K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"hevc","tags":["alphabet","character","coding","efficiency","font","hevc","high","letter","symbol","text","type","video"]},{"name":"currency_franc","tags":["bill","card","cash","coin","commerce","cost","credit","currency","dollars","finance","franc","money","online","pay","payment","price","shopping","symbol"]},{"name":"8k_plus","tags":["+","7000","8K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"hdr_on_select","tags":["+","alphabet","camera","character","circle","dynamic","font","hdr","high","letter","on","photo","range","select","symbol","text","type"]},{"name":"3k","tags":["3000","3K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"transcribe","tags":[]},{"name":"width_wide","tags":[]},{"name":"hdr_auto_select","tags":["+","A","alphabet","auto","camera","character","circle","dynamic","font","hdr","high","letter","photo","range","select","symbol","text","type"]},{"name":"hls","tags":["alphabet","character","develop","developer","engineer","engineering","font","hls","letter","platform","symbol","text","type"]},{"name":"5k_plus","tags":["+","5000","5K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"assist_walker","tags":["accessibility","accessible","assist","body","disability","handicap","help","human","injured","injury","mobility","person","walk","walker"]},{"name":"hls_off","tags":["alphabet","character","develop","developer","disabled","enabled","engineer","engineering","font","hls","letter","off","offline","on","platform","slash","symbol","text","type"]},{"name":"18mp","tags":["18","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"format_overline","tags":["alphabet","character","doc","edit","editing","editor","font","format","letter","line","overline","sheet","spreadsheet","style","symbol","text","type","under","writing"]},{"name":"volcano","tags":["crisis","disaster","eruption","lava","magma","natural","volcano"]},{"name":"vaping_rooms","tags":["allowed","e-cigarette","never","no","places","prohibited","smoke","smoking","tobacco","vape","vaping","vapor","warning","zone"]},{"name":"watch_off","tags":["Android","OS","ar","clock","close","gadget","iOS","off","shut","time","vr","watch","wearables","web","wristwatch"]},{"name":"9k","tags":["9000","9K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"23mp","tags":["23","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"propane","tags":["gas","nest","propane"]},{"name":"raw_off","tags":["alphabet","character","disabled","enabled","font","image","letter","off","on","original","photo","photography","raw","slash","symbol","text","type"]},{"name":"keyboard_option_key","tags":["alt key","key","keyboard","modifier key","option"]},{"name":"woman_2","tags":["female","gender","girl","lady","social","symbol","woman","women"]},{"name":"2k_plus","tags":["+","2k","alphabet","character","digit","font","letter","number","plus","symbol","text","type"]},{"name":"6k_plus","tags":["+","6000","6K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"broadcast_on_personal","tags":[]},{"name":"10mp","tags":["10","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"man_2","tags":["boy","gender","male","man","social","symbol"]},{"name":"7k","tags":["7000","7K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"7k_plus","tags":["+","7000","7K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"nearby_off","tags":["disabled","enabled","nearby","off","on","slash"]},{"name":"3k_plus","tags":["+","3000","3K","alphabet","character","digit","display","font","letter","number","pixel","pixels","plus","resolution","symbol","text","type","video"]},{"name":"6k","tags":["6000","6K","alphabet","character","digit","display","font","letter","number","pixel","pixels","resolution","symbol","text","type","video"]},{"name":"hdr_off","tags":["alphabet","character","disabled","dynamic","enabled","enhance","font","hdr","high","letter","off","on","range","select","slash","symbol","text","type"]},{"name":"roundabout_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","roundabout","route","sign","traffic"]},{"name":"hdr_off_select","tags":["alphabet","camera","character","circle","disabled","dynamic","enabled","font","hdr","high","letter","off","on","photo","range","select","slash","symbol","text","type"]},{"name":"bedtime_off","tags":["bedtime","disabled","lunar","moon","night","nightime","off","offline","slash","sleep"]},{"name":"18_up_rating","tags":[]},{"name":"turn_sharp_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","route","sharp","sign","traffic","turn"]},{"name":"11mp","tags":["11","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"roller_shades_closed","tags":["blinds","closed","cover","curtains","nest","roller","shade","shutter","sunshade"]},{"name":"20mp","tags":["20","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"blinds","tags":["blinds","cover","curtains","nest","open","shade","shutter","sunshade"]},{"name":"3mp","tags":["3","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"blind","tags":["accessibility","accessible","assist","blind","body","cane","disability","handicap","help","human","mobility","person","walk","walker"]},{"name":"emergency_recording","tags":["alert","attention","camera","caution","danger","emergency","film","filming","hardware","image","important","motion","notification","picture","record","video","videography","warning"]},{"name":"curtains","tags":["blinds","cover","curtains","nest","open","shade","shutter","sunshade"]},{"name":"13mp","tags":["13","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"5mp","tags":["5","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"21mp","tags":["21","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"blinds_closed","tags":["blinds","closed","cover","curtains","nest","shade","shutter","sunshade"]},{"name":"16mp","tags":["16","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"17mp","tags":["17","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"2mp","tags":["2","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"15mp","tags":["15","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"desk","tags":[]},{"name":"no_adult_content","tags":[]},{"name":"14mp","tags":["14","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"22mp","tags":["22","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"vertical_shades","tags":["blinds","cover","curtains","nest","open","shade","shutter","sunshade","vertical"]},{"name":"vertical_shades_closed","tags":["blinds","closed","cover","curtains","nest","roller","shade","shutter","sunshade"]},{"name":"curtains_closed","tags":["blinds","closed","cover","curtains","nest","shade","shutter","sunshade"]},{"name":"broadcast_on_home","tags":[]},{"name":"4mp","tags":["4","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"19mp","tags":["19","camera","digits","font","image","letters","megapixel","megapixels","mp","numbers","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"nest_cam_wired_stand","tags":["camera","film","filming","hardware","image","motion","nest","picture","stand","video","videography","wired"]},{"name":"9mp","tags":["9","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"7mp","tags":["7","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"8mp","tags":["8","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"6mp","tags":["6","camera","digit","font","image","letters","megapixel","megapixels","mp","number","pixel","pixels","quality","resolution","symbol","text","type"]},{"name":"devices_fold","tags":["Android","OS","cell","device","fold","foldable","hardware","iOS","mobile","phone","tablet"]},{"name":"vape_free","tags":["disabled","e-cigarette","enabled","free","never","no","off","on","places","prohibited","slash","smoke","smoking","tobacco","vape","vaping","vapor","warning","zone"]},{"name":"ramp_left","tags":["arrow","arrows","direction","directions","left","maps","navigation","path","ramp","route","sign","traffic"]},{"name":"ramp_right","tags":["arrow","arrows","direction","directions","maps","navigation","path","ramp","right","route","sign","traffic"]},{"name":"video_chat","tags":["bubble","cam","camera","chat","comment","communicate","facetime","feedback","message","speech","video","voice"]},{"name":"type_specimen","tags":[]},{"name":"man_4","tags":["abstract","boy","gender","male","man","social","symbol"]},{"name":"fluorescent","tags":["bright","fluorescent","lamp","light","lightbulb"]},{"name":"man_3","tags":["abstract","boy","gender","male","man","social","symbol"]},{"name":"fire_hydrant_alt","tags":[]},{"name":"macro_off","tags":["camera","disabled","enabled","flower","garden","image","macro","off","offline","on","slash"]},{"name":"mdi:ab-testing","tags":["developer / languages"]},{"name":"mdi:abacus","tags":["math"]},{"name":"mdi:abjad-arabic","tags":["alpha / numeric","writing system arabic"]},{"name":"mdi:abjad-hebrew","tags":["alpha / numeric","writing system hebrew"]},{"name":"mdi:abugida-devanagari","tags":["alpha / numeric","writing system devanagari"]},{"name":"mdi:abugida-thai","tags":["alpha / numeric","writing system thai"]},{"name":"mdi:access-point","tags":["wireless"]},{"name":"mdi:access-point-check","tags":["access point success","access point tick"]},{"name":"mdi:access-point-minus","tags":[]},{"name":"mdi:access-point-network","tags":[]},{"name":"mdi:access-point-network-off","tags":[]},{"name":"mdi:access-point-off","tags":[]},{"name":"mdi:access-point-plus","tags":[]},{"name":"mdi:access-point-remove","tags":[]},{"name":"mdi:account-alert","tags":["account / user","alert / error","user alert","account warning","user warning","person alert","person warning"]},{"name":"mdi:account-alert-outline","tags":["account / user","alert / error","user alert outline","account warning outline","user warning outline","person warning outline","person alert outline"]},{"name":"mdi:account-arrow-down","tags":["account / user","account download"]},{"name":"mdi:account-arrow-down-outline","tags":["account / user","account download outline"]},{"name":"mdi:account-arrow-left","tags":["account / user","user arrow left","person arrow left"]},{"name":"mdi:account-arrow-left-outline","tags":["account / user","user arrow left outline","person arrow left outline"]},{"name":"mdi:account-arrow-right","tags":["account / user","user arrow right","person arrow right"]},{"name":"mdi:account-arrow-right-outline","tags":["account / user","user arrow right outline","person arrow right outline"]},{"name":"mdi:account-arrow-up","tags":["account / user","account upload"]},{"name":"mdi:account-arrow-up-outline","tags":["account / user","account upload outline"]},{"name":"mdi:account-badge","tags":["account / user","account online","user online"]},{"name":"mdi:account-badge-outline","tags":["account / user","user online outline","account online outline"]},{"name":"mdi:account-box-multiple-outline","tags":["account / user"]},{"name":"mdi:account-cancel","tags":["account / user","user cancel","user block","person cancel","person block"]},{"name":"mdi:account-cancel-outline","tags":["account / user","user cancel outline","user block outline","person cancel outline","person block outline"]},{"name":"mdi:account-card","tags":["account / user"]},{"name":"mdi:account-card-outline","tags":["account / user"]},{"name":"mdi:account-cash","tags":["account / user","banking","currency"]},{"name":"mdi:account-cash-outline","tags":["account / user","banking","currency"]},{"name":"mdi:account-child-outline","tags":["account / user"]},{"name":"mdi:account-clock","tags":["account / user","date / time","user clock","account pending","person clock"]},{"name":"mdi:account-clock-outline","tags":["account / user","date / time","user clock outline","account pending outline","person clock outline"]},{"name":"mdi:account-cog","tags":["account / user","settings","account settings"]},{"name":"mdi:account-cog-outline","tags":["account / user","settings","account settings outline"]},{"name":"mdi:account-convert","tags":["account / user","user convert","person convert"]},{"name":"mdi:account-convert-outline","tags":["account / user"]},{"name":"mdi:account-cowboy-hat","tags":["account / user","agriculture","rancher"]},{"name":"mdi:account-cowboy-hat-outline","tags":["account / user","agriculture","rancher outline"]},{"name":"mdi:account-credit-card","tags":["account / user","banking","account payment","cardholder"]},{"name":"mdi:account-credit-card-outline","tags":["account / user","banking","account payment outline","cardholder outline"]},{"name":"mdi:account-details-outline","tags":["account / user","settings","person details outline","user details outline"]},{"name":"mdi:account-edit","tags":["account / user","edit / modify","user edit","person edit"]},{"name":"mdi:account-edit-outline","tags":["account / user","edit / modify"]},{"name":"mdi:account-eye","tags":["account / user","account view"]},{"name":"mdi:account-eye-outline","tags":["account / user","account view outline"]},{"name":"mdi:account-filter","tags":["account / user","account funnel","leads"]},{"name":"mdi:account-filter-outline","tags":["account / user","account funnel outline","leads outline"]},{"name":"mdi:account-group","tags":["account / user","home automation","user group","users group","person group","people group","accounts group"]},{"name":"mdi:account-group-outline","tags":["account / user","user group outline","users group outline","person group outline","people group outline","accounts group outline"]},{"name":"mdi:account-hard-hat","tags":["account / user","worker","construction"]},{"name":"mdi:account-hard-hat-outline","tags":["account / user","worker outline","construction outline"]},{"name":"mdi:account-heart","tags":["account / user","medical / hospital","user heart","person heart"]},{"name":"mdi:account-heart-outline","tags":["account / user","medical / hospital","user heart outline","person heart outline"]},{"name":"mdi:account-key","tags":["account / user","user key","person key"]},{"name":"mdi:account-key-outline","tags":["account / user","user key outline","person key outline"]},{"name":"mdi:account-lock","tags":["account / user","lock","account security","account secure","user lock","person lock"]},{"name":"mdi:account-lock-open","tags":["account / user","lock","account unlocked","user unlocked","user lock open"]},{"name":"mdi:account-lock-open-outline","tags":["account / user","lock","user lock open outline","user unlocked outline","account unlocked outline"]},{"name":"mdi:account-lock-outline","tags":["account / user","lock","account security outline","account secure outline","person lock outline","user lock outline"]},{"name":"mdi:account-minus","tags":["account / user","user minus","person minus"]},{"name":"mdi:account-minus-outline","tags":["account / user","user minus outline","person minus outline"]},{"name":"mdi:account-multiple-check","tags":["account / user","user multiple check","account multiple tick","accounts check","accounts tick","users check","users tick","user multiple tick","person multiple check","person multiple tick","people check","people tick","account multiple success"]},{"name":"mdi:account-multiple-check-outline","tags":["account / user","user multiple check outline","account multiple tick outline","accounts check outline","accounts tick outline","users check outline","users tick outline","user multiple tick outline","person multiple check outline","person multiple tick outline","people check outline","people tick outline","account multiple success outline"]},{"name":"mdi:account-multiple-remove","tags":["account / user","user multiple remove","person multiple remove"]},{"name":"mdi:account-multiple-remove-outline","tags":["account / user","user multiple remove outline","person multiple remove outline"]},{"name":"mdi:account-music-outline","tags":["account / user","artist outline"]},{"name":"mdi:account-network","tags":["account / user","user network","person network"]},{"name":"mdi:account-network-off","tags":["account / user"]},{"name":"mdi:account-network-off-outline","tags":["account / user"]},{"name":"mdi:account-network-outline","tags":["account / user","user network outline","person network outline"]},{"name":"mdi:account-off","tags":["account / user","user off","person off"]},{"name":"mdi:account-off-outline","tags":["account / user","user off outline","person off outline"]},{"name":"mdi:account-plus-outline","tags":["account / user","person add outline","register outline","user plus outline","account add outline","person plus outline","user add outline","invite"]},{"name":"mdi:account-question","tags":["account / user","user help","account question mark","account help","user question","person question","person help"]},{"name":"mdi:account-question-outline","tags":["account / user","account question mark outline","user help outline","account help outline","user question outline","person question outline","person help outline"]},{"name":"mdi:account-reactivate","tags":["account / user"]},{"name":"mdi:account-reactivate-outline","tags":["account / user"]},{"name":"mdi:account-remove","tags":["account / user","user remove","person remove"]},{"name":"mdi:account-remove-outline","tags":["account / user","user remove outline","person remove outline"]},{"name":"mdi:account-school","tags":["account / user","account student","account graduation"]},{"name":"mdi:account-school-outline","tags":["account / user","account student outline","account graduation outline"]},{"name":"mdi:account-search","tags":["account / user","user search","person search"]},{"name":"mdi:account-search-outline","tags":["account / user","user search outline","person search outline"]},{"name":"mdi:account-settings","tags":["account / user","settings","user settings","person settings"]},{"name":"mdi:account-settings-outline","tags":["account / user","settings"]},{"name":"mdi:account-star","tags":["account / user","user star","person star","account favorite"]},{"name":"mdi:account-star-outline","tags":["account / user","user star outline","person star outline"]},{"name":"mdi:account-supervisor-outline","tags":["account / user"]},{"name":"mdi:account-switch","tags":["account / user","user switch","accounts switch","users switch","person switch","people switch"]},{"name":"mdi:account-switch-outline","tags":["account / user"]},{"name":"mdi:account-sync","tags":["account / user","account cache"]},{"name":"mdi:account-sync-outline","tags":["account / user","account cache outline"]},{"name":"mdi:account-tag","tags":["account / user"]},{"name":"mdi:account-tag-outline","tags":["account / user"]},{"name":"mdi:account-tie","tags":["account / user","people / family","person tie","user tie"]},{"name":"mdi:account-tie-hat","tags":["account / user","transportation + flying","account pilot"]},{"name":"mdi:account-tie-hat-outline","tags":["account / user","transportation + flying","account pilot outline"]},{"name":"mdi:account-tie-outline","tags":["account / user"]},{"name":"mdi:account-tie-voice","tags":["account / user"]},{"name":"mdi:account-tie-voice-off","tags":["account / user"]},{"name":"mdi:account-tie-voice-off-outline","tags":["account / user"]},{"name":"mdi:account-tie-voice-outline","tags":["account / user"]},{"name":"mdi:account-tie-woman","tags":["account / user","people / family","business woman"]},{"name":"mdi:account-wrench","tags":["account / user","account service"]},{"name":"mdi:account-wrench-outline","tags":["account / user","account service outline"]},{"name":"mdi:advertisements","tags":["ads"]},{"name":"mdi:advertisements-off","tags":["ads off"]},{"name":"mdi:air-conditioner","tags":["home automation","automotive","ac unit"]},{"name":"mdi:air-filter","tags":["home automation","water filter","filter"]},{"name":"mdi:air-horn","tags":[]},{"name":"mdi:air-humidifier","tags":["home automation"]},{"name":"mdi:air-humidifier-off","tags":["home automation","air dehumidifier"]},{"name":"mdi:air-purifier-off","tags":["home automation"]},{"name":"mdi:airbag","tags":["automotive"]},{"name":"mdi:airballoon","tags":["transportation + other","transportation + flying","hot air balloon"]},{"name":"mdi:airballoon-outline","tags":["transportation + flying","hot air balloon outline"]},{"name":"mdi:airplane","tags":["transportation + flying","navigation","aeroplane","airplanemode active","flight","local airport","flight mode","plane"]},{"name":"mdi:airplane-alert","tags":["transportation + flying","alert / error"]},{"name":"mdi:airplane-check","tags":["transportation + flying","airplace success","airplane tick"]},{"name":"mdi:airplane-clock","tags":["transportation + flying","date / time","airplane schedule","airplane time","airplane date"]},{"name":"mdi:airplane-cog","tags":["transportation + flying","settings","airplane settings"]},{"name":"mdi:airplane-edit","tags":["transportation + flying","edit / modify"]},{"name":"mdi:airplane-marker","tags":["transportation + flying","navigation","airplane location","airplane gps"]},{"name":"mdi:airplane-minus","tags":["transportation + flying"]},{"name":"mdi:airplane-off","tags":["transportation + flying","aeroplane off","airplanemode inactive","flight mode off","plane off"]},{"name":"mdi:airplane-plus","tags":["transportation + flying"]},{"name":"mdi:airplane-remove","tags":["transportation + flying"]},{"name":"mdi:airplane-search","tags":["transportation + flying","airplane find"]},{"name":"mdi:airplane-settings","tags":["transportation + flying","settings"]},{"name":"mdi:airport","tags":["places","transportation + flying"]},{"name":"mdi:alarm-bell","tags":["notification"]},{"name":"mdi:alarm-light","tags":["home automation"]},{"name":"mdi:alarm-light-off","tags":["home automation"]},{"name":"mdi:alarm-light-off-outline","tags":["home automation"]},{"name":"mdi:alarm-light-outline","tags":["home automation"]},{"name":"mdi:alarm-multiple","tags":["date / time","alarms","alarm clock multiple","alarm clocks"]},{"name":"mdi:alarm-note","tags":[]},{"name":"mdi:alarm-note-off","tags":[]},{"name":"mdi:alarm-panel","tags":["home automation"]},{"name":"mdi:alarm-panel-outline","tags":["home automation"]},{"name":"mdi:alert-box","tags":["alert / error","warning box"]},{"name":"mdi:alert-box-outline","tags":["alert / error","warning box outline"]},{"name":"mdi:alert-circle-check","tags":["alert / error","alert circle success"]},{"name":"mdi:alert-circle-check-outline","tags":["alert / error","alert circle success outline"]},{"name":"mdi:alert-decagram-outline","tags":["alert / error","warning decagram outline"]},{"name":"mdi:alert-minus","tags":["alert / error"]},{"name":"mdi:alert-minus-outline","tags":["alert / error"]},{"name":"mdi:alert-octagon-outline","tags":["alert / error","warning octagon outline","stop alert outline"]},{"name":"mdi:alert-octagram","tags":["alert / error","warning octagram"]},{"name":"mdi:alert-octagram-outline","tags":["alert / error","warning octagram outline"]},{"name":"mdi:alert-outline","tags":["alert / error","warning outline"]},{"name":"mdi:alert-plus","tags":["alert / error"]},{"name":"mdi:alert-plus-outline","tags":["alert / error"]},{"name":"mdi:alert-remove","tags":["alert / error"]},{"name":"mdi:alert-remove-outline","tags":["alert / error"]},{"name":"mdi:alert-rhombus","tags":["alert / error"]},{"name":"mdi:alert-rhombus-outline","tags":["alert / error"]},{"name":"mdi:alien","tags":[]},{"name":"mdi:alien-outline","tags":[]},{"name":"mdi:all-inclusive-box","tags":["infinity box","forever box"]},{"name":"mdi:all-inclusive-box-outline","tags":["forever box outline","infinity box outline"]},{"name":"mdi:allergy","tags":["medical / hospital","hand","rash","germ"]},{"name":"mdi:alpha","tags":["alpha / numeric"]},{"name":"mdi:alpha-a","tags":["alpha / numeric","alphabet a","letter a"]},{"name":"mdi:alpha-a-box","tags":["alpha / numeric","alphabet a box","letter a box"]},{"name":"mdi:alpha-a-box-outline","tags":["alpha / numeric","alphabet a box outline","letter a box outline"]},{"name":"mdi:alpha-a-circle","tags":["alpha / numeric","alphabet a circle","letter a circle"]},{"name":"mdi:alpha-a-circle-outline","tags":["alpha / numeric","alphabet a circle outline","letter a circle outline"]},{"name":"mdi:alpha-b","tags":["alpha / numeric","alphabet b","letter b"]},{"name":"mdi:alpha-b-box","tags":["alpha / numeric","alphabet b box","letter b box"]},{"name":"mdi:alpha-b-box-outline","tags":["alpha / numeric","alphabet b box outline","letter b box outline"]},{"name":"mdi:alpha-b-circle","tags":["alpha / numeric","alphabet b circle","letter b circle"]},{"name":"mdi:alpha-b-circle-outline","tags":["alpha / numeric","alphabet b circle outline","letter b circle outline"]},{"name":"mdi:alpha-c","tags":["alpha / numeric","alphabet c","letter c"]},{"name":"mdi:alpha-c-box","tags":["alpha / numeric","alphabet c box","letter c box"]},{"name":"mdi:alpha-c-box-outline","tags":["alpha / numeric","alphabet c box outline","letter c box outline"]},{"name":"mdi:alpha-c-circle","tags":["alpha / numeric","alphabet c circle","letter c circle"]},{"name":"mdi:alpha-c-circle-outline","tags":["alpha / numeric","alphabet c circle outline","letter c circle outline"]},{"name":"mdi:alpha-d","tags":["automotive","alpha / numeric","alphabet d","letter d","drive"]},{"name":"mdi:alpha-d-box","tags":["alpha / numeric","alphabet d box","letter d box"]},{"name":"mdi:alpha-d-box-outline","tags":["alpha / numeric","alphabet d box outline","letter d box outline"]},{"name":"mdi:alpha-d-circle","tags":["alpha / numeric","alphabet d circle","letter d circle"]},{"name":"mdi:alpha-d-circle-outline","tags":["alpha / numeric","alphabet d circle outline","letter d circle outline"]},{"name":"mdi:alpha-e","tags":["alpha / numeric","alphabet e","letter e"]},{"name":"mdi:alpha-e-box","tags":["alpha / numeric","alphabet e box","letter e box"]},{"name":"mdi:alpha-e-box-outline","tags":["alpha / numeric","alphabet e box outline","letter e box outline"]},{"name":"mdi:alpha-e-circle","tags":["alpha / numeric","alphabet e circle","letter e circle"]},{"name":"mdi:alpha-e-circle-outline","tags":["alpha / numeric","alphabet e circle outline","letter e circle outline"]},{"name":"mdi:alpha-f","tags":["alpha / numeric","alphabet f","letter f"]},{"name":"mdi:alpha-f-box","tags":["alpha / numeric","alphabet f box","letter f box"]},{"name":"mdi:alpha-f-box-outline","tags":["alpha / numeric","alphabet f box outline","letter f box outline"]},{"name":"mdi:alpha-f-circle","tags":["alpha / numeric","alphabet f circle","letter f circle"]},{"name":"mdi:alpha-f-circle-outline","tags":["alpha / numeric","alphabet f circle outline","letter f circle outline"]},{"name":"mdi:alpha-g","tags":["alpha / numeric","alphabet g","letter g"]},{"name":"mdi:alpha-g-box","tags":["alpha / numeric","alphabet g box","letter g box"]},{"name":"mdi:alpha-g-box-outline","tags":["alpha / numeric","alphabet g box outline","letter g box outline"]},{"name":"mdi:alpha-g-circle","tags":["alpha / numeric","alphabet g circle","letter g circle"]},{"name":"mdi:alpha-g-circle-outline","tags":["alpha / numeric","alphabet g circle outline","letter g circle outline"]},{"name":"mdi:alpha-h","tags":["alpha / numeric","alphabet h","letter h"]},{"name":"mdi:alpha-h-box","tags":["alpha / numeric","alphabet h box","letter h box"]},{"name":"mdi:alpha-h-box-outline","tags":["alpha / numeric","alphabet h box outline","letter h box outline"]},{"name":"mdi:alpha-h-circle","tags":["alpha / numeric","alphabet h circle","letter h circle"]},{"name":"mdi:alpha-h-circle-outline","tags":["alpha / numeric","alphabet h circle outline","letter h circle outline","helipad"]},{"name":"mdi:alpha-i","tags":["alpha / numeric","alphabet i","letter i","roman numeral 1"]},{"name":"mdi:alpha-i-box","tags":["alpha / numeric","alphabet i box","letter i box"]},{"name":"mdi:alpha-i-box-outline","tags":["alpha / numeric","alphabet i box outline","letter i box outline"]},{"name":"mdi:alpha-i-circle","tags":["alpha / numeric","alphabet i circle","letter i circle"]},{"name":"mdi:alpha-i-circle-outline","tags":["alpha / numeric","alphabet i circle outline","letter i circle outline"]},{"name":"mdi:alpha-j","tags":["alpha / numeric","alphabet j","letter j"]},{"name":"mdi:alpha-j-box","tags":["alpha / numeric","alphabet j box","letter j box"]},{"name":"mdi:alpha-j-box-outline","tags":["alpha / numeric","alphabet j box outline","letter j box outline"]},{"name":"mdi:alpha-j-circle","tags":["alpha / numeric","alphabet j circle","letter j circle"]},{"name":"mdi:alpha-j-circle-outline","tags":["alpha / numeric","alphabet j circle outline","letter j circle outline"]},{"name":"mdi:alpha-k","tags":["alpha / numeric","alphabet k","letter k"]},{"name":"mdi:alpha-k-box","tags":["alpha / numeric","alphabet k box","letter k box"]},{"name":"mdi:alpha-k-box-outline","tags":["alpha / numeric","alphabet k box outline","letter k box outline"]},{"name":"mdi:alpha-k-circle","tags":["alpha / numeric","alphabet k circle","letter k circle"]},{"name":"mdi:alpha-k-circle-outline","tags":["alpha / numeric","alphabet k circle outline","letter k circle outline"]},{"name":"mdi:alpha-l","tags":["alpha / numeric","alphabet l","letter l"]},{"name":"mdi:alpha-l-box","tags":["alpha / numeric","alphabet l box","letter l box"]},{"name":"mdi:alpha-l-box-outline","tags":["alpha / numeric","alphabet l box outline","letter l box outline"]},{"name":"mdi:alpha-l-circle","tags":["alpha / numeric","alphabet l circle","letter l circle"]},{"name":"mdi:alpha-l-circle-outline","tags":["alpha / numeric","alphabet l circle outline","letter l circle outline"]},{"name":"mdi:alpha-m","tags":["alpha / numeric","alphabet m","letter m"]},{"name":"mdi:alpha-m-box","tags":["alpha / numeric","alphabet m box","letter m box"]},{"name":"mdi:alpha-m-box-outline","tags":["alpha / numeric","alphabet m box outline","letter m box outline"]},{"name":"mdi:alpha-m-circle","tags":["alpha / numeric","alphabet m circle","letter m circle"]},{"name":"mdi:alpha-m-circle-outline","tags":["alpha / numeric","alphabet m circle outline","letter m circle outline"]},{"name":"mdi:alpha-n","tags":["automotive","alpha / numeric","alphabet n","letter n","neutral"]},{"name":"mdi:alpha-n-box","tags":["alpha / numeric","alphabet n box","letter n box"]},{"name":"mdi:alpha-n-box-outline","tags":["alpha / numeric","alphabet n box outline","letter n box outline"]},{"name":"mdi:alpha-n-circle","tags":["alpha / numeric","alphabet n circle","letter n circle"]},{"name":"mdi:alpha-n-circle-outline","tags":["alpha / numeric","alphabet n circle outline","letter n circle outline"]},{"name":"mdi:alpha-o","tags":["alpha / numeric","alphabet o","letter o"]},{"name":"mdi:alpha-o-box","tags":["alpha / numeric","alphabet o box","letter o box"]},{"name":"mdi:alpha-o-box-outline","tags":["alpha / numeric","alphabet o box outline","letter o box outline"]},{"name":"mdi:alpha-o-circle","tags":["alpha / numeric","alphabet o circle","letter o circle"]},{"name":"mdi:alpha-o-circle-outline","tags":["alpha / numeric","alphabet o circle outline","letter o circle outline"]},{"name":"mdi:alpha-p","tags":["automotive","alpha / numeric","alphabet p","letter p","park"]},{"name":"mdi:alpha-p-box","tags":["alpha / numeric","alphabet p box","letter p box"]},{"name":"mdi:alpha-p-box-outline","tags":["alpha / numeric","alphabet p box outline","letter p box outline"]},{"name":"mdi:alpha-p-circle","tags":["alpha / numeric","alphabet p circle","letter p circle"]},{"name":"mdi:alpha-p-circle-outline","tags":["alpha / numeric","alphabet p circle outline","letter p circle outline"]},{"name":"mdi:alpha-q","tags":["alpha / numeric","alphabet q","letter q"]},{"name":"mdi:alpha-q-box","tags":["alpha / numeric","alphabet q box","letter q box"]},{"name":"mdi:alpha-q-box-outline","tags":["alpha / numeric","alphabet q box outline","letter q box outline"]},{"name":"mdi:alpha-q-circle","tags":["alpha / numeric","alphabet q circle","letter q circle"]},{"name":"mdi:alpha-q-circle-outline","tags":["alpha / numeric","alphabet q circle outline","letter q circle outline"]},{"name":"mdi:alpha-r","tags":["automotive","alpha / numeric","alphabet r","letter r","reverse"]},{"name":"mdi:alpha-r-box","tags":["alpha / numeric","alphabet r box","letter r box"]},{"name":"mdi:alpha-r-box-outline","tags":["alpha / numeric","alphabet r box outline","letter r box outline"]},{"name":"mdi:alpha-r-circle","tags":["alpha / numeric","alphabet r circle","letter r circle"]},{"name":"mdi:alpha-r-circle-outline","tags":["alpha / numeric","alphabet r circle outline","letter r circle outline"]},{"name":"mdi:alpha-s","tags":["alpha / numeric","alphabet s","letter s"]},{"name":"mdi:alpha-s-box","tags":["alpha / numeric","alphabet s box","letter s box"]},{"name":"mdi:alpha-s-box-outline","tags":["alpha / numeric","alphabet s box outline","letter s box outline"]},{"name":"mdi:alpha-s-circle","tags":["alpha / numeric","alphabet s circle","letter s circle"]},{"name":"mdi:alpha-s-circle-outline","tags":["alpha / numeric","alphabet s circle outline","letter s circle outline"]},{"name":"mdi:alpha-t","tags":["alpha / numeric","alphabet t","letter t"]},{"name":"mdi:alpha-t-box","tags":["alpha / numeric","alphabet t box","letter t box"]},{"name":"mdi:alpha-t-box-outline","tags":["alpha / numeric","alphabet t box outline","letter t box outline"]},{"name":"mdi:alpha-t-circle","tags":["alpha / numeric","alphabet t circle","letter t circle"]},{"name":"mdi:alpha-t-circle-outline","tags":["alpha / numeric","alphabet t circle outline","letter t circle outline"]},{"name":"mdi:alpha-u","tags":["alpha / numeric","alphabet u","letter u"]},{"name":"mdi:alpha-u-box","tags":["alpha / numeric","alphabet u box","letter u box"]},{"name":"mdi:alpha-u-box-outline","tags":["alpha / numeric","alphabet u box outline","letter u box outline"]},{"name":"mdi:alpha-u-circle","tags":["alpha / numeric","alphabet u circle","letter u circle"]},{"name":"mdi:alpha-u-circle-outline","tags":["alpha / numeric","alphabet u circle outline","letter u circle outline"]},{"name":"mdi:alpha-v","tags":["alpha / numeric","alphabet v","letter v","roman numeral 5"]},{"name":"mdi:alpha-v-box","tags":["alpha / numeric","alphabet v box","letter v box"]},{"name":"mdi:alpha-v-box-outline","tags":["alpha / numeric","alphabet v box outline","letter v box outline"]},{"name":"mdi:alpha-v-circle","tags":["alpha / numeric","alphabet v circle","letter v circle"]},{"name":"mdi:alpha-v-circle-outline","tags":["alpha / numeric","alphabet v circle outline","letter v circle outline"]},{"name":"mdi:alpha-w","tags":["alpha / numeric","alphabet w","letter w"]},{"name":"mdi:alpha-w-box","tags":["alpha / numeric","alphabet w box","letter w box"]},{"name":"mdi:alpha-w-box-outline","tags":["alpha / numeric","alphabet w box outline","letter w box outline"]},{"name":"mdi:alpha-w-circle","tags":["alpha / numeric","alphabet w circle","letter w circle"]},{"name":"mdi:alpha-w-circle-outline","tags":["alpha / numeric","alphabet w circle outline","letter w circle outline"]},{"name":"mdi:alpha-x","tags":["alpha / numeric","alphabet x","letter x","roman numeral 10"]},{"name":"mdi:alpha-x-box","tags":["alpha / numeric","alphabet x box","letter x box"]},{"name":"mdi:alpha-x-box-outline","tags":["alpha / numeric","alphabet x box outline","letter x box outline"]},{"name":"mdi:alpha-x-circle","tags":["alpha / numeric","alphabet x circle","letter x circle"]},{"name":"mdi:alpha-x-circle-outline","tags":["alpha / numeric","alphabet x circle outline","letter x circle outline"]},{"name":"mdi:alpha-y","tags":["alpha / numeric","alphabet y","letter y"]},{"name":"mdi:alpha-y-box","tags":["alpha / numeric","alphabet y box","letter y box"]},{"name":"mdi:alpha-y-box-outline","tags":["alpha / numeric","alphabet y box outline","letter y box outline"]},{"name":"mdi:alpha-y-circle","tags":["alpha / numeric","alphabet y circle","letter y circle"]},{"name":"mdi:alpha-y-circle-outline","tags":["alpha / numeric","alphabet y circle outline","letter y circle outline"]},{"name":"mdi:alpha-z","tags":["alpha / numeric","alphabet z","letter z"]},{"name":"mdi:alpha-z-box","tags":["alpha / numeric","alphabet z box","letter z box"]},{"name":"mdi:alpha-z-box-outline","tags":["alpha / numeric","alphabet z box outline","letter z box outline"]},{"name":"mdi:alpha-z-circle","tags":["alpha / numeric","alphabet z circle","letter z circle"]},{"name":"mdi:alpha-z-circle-outline","tags":["alpha / numeric","alphabet z circle outline","letter z circle outline"]},{"name":"mdi:alphabet-aurebesh","tags":["alpha / numeric","writing system aurebesh"]},{"name":"mdi:alphabet-cyrillic","tags":["alpha / numeric","writing system cyrillic"]},{"name":"mdi:alphabet-greek","tags":["alpha / numeric","writing system greek"]},{"name":"mdi:alphabet-latin","tags":["alpha / numeric","writing system latin"]},{"name":"mdi:alphabet-piqad","tags":["alpha / numeric","writing system piqad"]},{"name":"mdi:alphabet-tengwar","tags":["alpha / numeric","writing system tengwar"]},{"name":"mdi:alphabetical","tags":["alpha / numeric","letters","a b c","abc"]},{"name":"mdi:alphabetical-off","tags":["alpha / numeric","letters off","abc off","a b c off"]},{"name":"mdi:alphabetical-variant","tags":["alpha / numeric","letters","abc","a b c"]},{"name":"mdi:alphabetical-variant-off","tags":["alpha / numeric","letters off","abc off","a b c off"]},{"name":"mdi:altimeter","tags":[]},{"name":"mdi:ambulance","tags":["transportation + road","medical / hospital"]},{"name":"mdi:ammunition","tags":["bullets"]},{"name":"mdi:ampersand","tags":["and"]},{"name":"mdi:amplifier","tags":["home automation","music"]},{"name":"mdi:amplifier-off","tags":[]},{"name":"mdi:angle-acute","tags":["math"]},{"name":"mdi:angle-obtuse","tags":["math"]},{"name":"mdi:angle-right","tags":["math"]},{"name":"mdi:animation-outline","tags":[]},{"name":"mdi:animation-play-outline","tags":[]},{"name":"mdi:anvil","tags":[]},{"name":"mdi:api-off","tags":["developer / languages"]},{"name":"mdi:apple-keyboard-caps","tags":[]},{"name":"mdi:apple-keyboard-command","tags":[]},{"name":"mdi:apple-keyboard-control","tags":[]},{"name":"mdi:apple-keyboard-option","tags":[]},{"name":"mdi:apple-keyboard-shift","tags":[]},{"name":"mdi:application","tags":["iframe"]},{"name":"mdi:application-array","tags":["developer / languages","iframe array"]},{"name":"mdi:application-array-outline","tags":["developer / languages","iframe array outline"]},{"name":"mdi:application-braces","tags":["developer / languages","iframe braces"]},{"name":"mdi:application-braces-outline","tags":["developer / languages","iframe braces outline"]},{"name":"mdi:application-brackets","tags":["developer / languages","iframe brackets"]},{"name":"mdi:application-brackets-outline","tags":["developer / languages","iframe brackets outline"]},{"name":"mdi:application-cog","tags":["settings","iframe cog"]},{"name":"mdi:application-cog-outline","tags":["settings","application settings","iframe cog outline"]},{"name":"mdi:application-edit","tags":["edit / modify","iframe edit"]},{"name":"mdi:application-edit-outline","tags":["edit / modify","iframe edit outline"]},{"name":"mdi:application-export","tags":["iframe export outline"]},{"name":"mdi:application-import","tags":["iframe import outline"]},{"name":"mdi:application-outline","tags":["web asset","iframe outline"]},{"name":"mdi:application-parentheses","tags":["developer / languages","iframe parentheses"]},{"name":"mdi:application-parentheses-outline","tags":["developer / languages","iframe parentheses outline"]},{"name":"mdi:application-settings","tags":["settings","iframe settings"]},{"name":"mdi:application-settings-outline","tags":["settings","iframe settings outline"]},{"name":"mdi:application-variable","tags":["developer / languages","iframe variable"]},{"name":"mdi:application-variable-outline","tags":["developer / languages","iframe variable outline"]},{"name":"mdi:approximately-equal","tags":["math"]},{"name":"mdi:approximately-equal-box","tags":["math"]},{"name":"mdi:archive","tags":["box"]},{"name":"mdi:archive-alert","tags":["alert / error","box alert"]},{"name":"mdi:archive-alert-outline","tags":["alert / error","box alert outline"]},{"name":"mdi:archive-arrow-down","tags":["box arrow down","this side down"]},{"name":"mdi:archive-arrow-down-outline","tags":["box arrow down","this side down outline"]},{"name":"mdi:archive-arrow-up","tags":["box arrow up","this side up"]},{"name":"mdi:archive-arrow-up-outline","tags":["box arrow up outline","this side up outline"]},{"name":"mdi:archive-cancel","tags":["box cancel"]},{"name":"mdi:archive-cancel-outline","tags":["box cancel outline"]},{"name":"mdi:archive-check","tags":["box check","archive success","box success"]},{"name":"mdi:archive-check-outline","tags":["box check outline","archive success outline","box success outline"]},{"name":"mdi:archive-clock","tags":["date / time","box clock","box time","archive time"]},{"name":"mdi:archive-clock-outline","tags":["date / time","box clock outline","box time outline","archive time outline"]},{"name":"mdi:archive-cog","tags":["settings","box cog"]},{"name":"mdi:archive-cog-outline","tags":["settings","box cog outline"]},{"name":"mdi:archive-edit","tags":["edit / modify","box edit"]},{"name":"mdi:archive-edit-outline","tags":["edit / modify","box edit outline"]},{"name":"mdi:archive-eye","tags":["archive view","box eye","box view"]},{"name":"mdi:archive-eye-outline","tags":["archive view outline","box eye outline","box view outline"]},{"name":"mdi:archive-lock","tags":["lock","box lock"]},{"name":"mdi:archive-lock-open","tags":["lock","box lock open"]},{"name":"mdi:archive-lock-open-outline","tags":["lock","box lock open outline"]},{"name":"mdi:archive-lock-outline","tags":["lock","box lock outline"]},{"name":"mdi:archive-marker","tags":["navigation","archive location","box marker","box location"]},{"name":"mdi:archive-marker-outline","tags":["navigation","archive location outline","box marker outline","box location outline"]},{"name":"mdi:archive-minus","tags":["box minus"]},{"name":"mdi:archive-minus-outline","tags":["box minus outline"]},{"name":"mdi:archive-music","tags":["music","box music"]},{"name":"mdi:archive-music-outline","tags":["music","box music outline"]},{"name":"mdi:archive-off","tags":["box off"]},{"name":"mdi:archive-off-outline","tags":["box off outline"]},{"name":"mdi:archive-outline","tags":["box outline"]},{"name":"mdi:archive-plus","tags":["archive add","box plus","box add"]},{"name":"mdi:archive-plus-outline","tags":["archive add outline","box plus outline","box add outline"]},{"name":"mdi:archive-refresh","tags":["box refresh"]},{"name":"mdi:archive-refresh-outline","tags":["box refresh outline"]},{"name":"mdi:archive-remove","tags":["box remove"]},{"name":"mdi:archive-remove-outline","tags":["box remove outline"]},{"name":"mdi:archive-search","tags":["box search"]},{"name":"mdi:archive-search-outline","tags":["box search outline"]},{"name":"mdi:archive-settings","tags":["settings","box settings"]},{"name":"mdi:archive-settings-outline","tags":["settings","box settings outline"]},{"name":"mdi:archive-star","tags":["archive favorite","box star","box favorite"]},{"name":"mdi:archive-star-outline","tags":["archive favorite outline","box star outline","box favorite outline"]},{"name":"mdi:archive-sync","tags":["box sync"]},{"name":"mdi:archive-sync-outline","tags":["box sync outline"]},{"name":"mdi:arm-flex","tags":[]},{"name":"mdi:arm-flex-outline","tags":[]},{"name":"mdi:arrange-bring-forward","tags":["arrange","geographic information system"]},{"name":"mdi:arrange-bring-to-front","tags":["arrange","geographic information system"]},{"name":"mdi:arrange-send-backward","tags":["arrange","geographic information system"]},{"name":"mdi:arrange-send-to-back","tags":["arrange","geographic information system"]},{"name":"mdi:arrow-all","tags":["arrow"]},{"name":"mdi:arrow-bottom-left","tags":["arrow","arrow down left"]},{"name":"mdi:arrow-bottom-left-bold-box","tags":["arrow"]},{"name":"mdi:arrow-bottom-left-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-bottom-left-bold-outline","tags":["arrow","arrow down left bold outline"]},{"name":"mdi:arrow-bottom-left-thick","tags":["arrow","arrow down left thick","arrow bottom left bold","arrow down left bold"]},{"name":"mdi:arrow-bottom-left-thin","tags":["arrow"]},{"name":"mdi:arrow-bottom-right","tags":["arrow","arrow down right"]},{"name":"mdi:arrow-bottom-right-bold-box","tags":["arrow"]},{"name":"mdi:arrow-bottom-right-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-bottom-right-bold-outline","tags":["arrow","arrow down right bold outline"]},{"name":"mdi:arrow-bottom-right-thick","tags":["arrow","arrow down right thick","arrow bottom right bold","arrow down right bold"]},{"name":"mdi:arrow-bottom-right-thin","tags":["arrow"]},{"name":"mdi:arrow-collapse","tags":["arrow","arrow compress"]},{"name":"mdi:arrow-collapse-all","tags":["arrow","arrow compress all"]},{"name":"mdi:arrow-collapse-down","tags":["arrow","arrow compress down"]},{"name":"mdi:arrow-collapse-left","tags":["arrow","arrow compress left"]},{"name":"mdi:arrow-collapse-right","tags":["arrow","arrow compress right"]},{"name":"mdi:arrow-collapse-up","tags":["arrow","arrow compress up"]},{"name":"mdi:arrow-decision","tags":["arrow","proxy"]},{"name":"mdi:arrow-decision-auto","tags":["proxy auto"]},{"name":"mdi:arrow-decision-auto-outline","tags":["proxy auto outline"]},{"name":"mdi:arrow-decision-outline","tags":["arrow","proxy outline"]},{"name":"mdi:arrow-down","tags":["arrow","arrow downward","arrow bottom"]},{"name":"mdi:arrow-down-bold","tags":["arrow","arrow bottom bold"]},{"name":"mdi:arrow-down-bold-box","tags":["arrow","arrow bottom bold box"]},{"name":"mdi:arrow-down-bold-box-outline","tags":["arrow","arrow bottom bold box outline"]},{"name":"mdi:arrow-down-bold-circle","tags":["arrow","arrow bottom bold circle"]},{"name":"mdi:arrow-down-bold-circle-outline","tags":["arrow","arrow bottom bold circle outline"]},{"name":"mdi:arrow-down-bold-hexagon-outline","tags":["arrow","arrow bottom bold hexagon outline"]},{"name":"mdi:arrow-down-bold-outline","tags":["arrow","arrow bottom bold outline"]},{"name":"mdi:arrow-down-box","tags":["arrow","arrow bottom box"]},{"name":"mdi:arrow-down-circle","tags":["arrow","arrow bottom circle"]},{"name":"mdi:arrow-down-circle-outline","tags":["arrow","arrow bottom circle outline"]},{"name":"mdi:arrow-down-drop-circle-outline","tags":["arrow","arrow bottom drop circle outline"]},{"name":"mdi:arrow-down-left","tags":["arrow"]},{"name":"mdi:arrow-down-left-bold","tags":["arrow"]},{"name":"mdi:arrow-down-right","tags":["arrow"]},{"name":"mdi:arrow-down-right-bold","tags":["arrow"]},{"name":"mdi:arrow-down-thick","tags":["arrow","arrow bottom thick","arrow down bold","arrow bottom bold"]},{"name":"mdi:arrow-down-thin","tags":["arrow"]},{"name":"mdi:arrow-expand","tags":["arrow"]},{"name":"mdi:arrow-expand-all","tags":["arrow","geographic information system"]},{"name":"mdi:arrow-expand-down","tags":["arrow"]},{"name":"mdi:arrow-expand-left","tags":["arrow"]},{"name":"mdi:arrow-expand-right","tags":["arrow"]},{"name":"mdi:arrow-expand-up","tags":["arrow"]},{"name":"mdi:arrow-horizontal-lock","tags":["lock","arrow","scroll horizontal lock"]},{"name":"mdi:arrow-left-bold","tags":["arrow","automotive"]},{"name":"mdi:arrow-left-bold-box","tags":["arrow"]},{"name":"mdi:arrow-left-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-left-bold-circle","tags":["arrow"]},{"name":"mdi:arrow-left-bold-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-left-bold-hexagon-outline","tags":["arrow"]},{"name":"mdi:arrow-left-bold-outline","tags":["arrow","automotive"]},{"name":"mdi:arrow-left-bottom","tags":[]},{"name":"mdi:arrow-left-bottom-bold","tags":[]},{"name":"mdi:arrow-left-box","tags":["arrow"]},{"name":"mdi:arrow-left-circle","tags":["arrow","arrow back circle"]},{"name":"mdi:arrow-left-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-left-drop-circle","tags":["arrow"]},{"name":"mdi:arrow-left-drop-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-left-right","tags":["arrow"]},{"name":"mdi:arrow-left-right-bold","tags":["arrow"]},{"name":"mdi:arrow-left-right-bold-outline","tags":["arrow"]},{"name":"mdi:arrow-left-thick","tags":["arrow","arrow left bold"]},{"name":"mdi:arrow-left-thin","tags":["arrow"]},{"name":"mdi:arrow-left-top","tags":["turn left"]},{"name":"mdi:arrow-left-top-bold","tags":["turn left bold"]},{"name":"mdi:arrow-projectile","tags":["gaming / rpg","sport"]},{"name":"mdi:arrow-projectile-multiple","tags":["gaming / rpg","sport"]},{"name":"mdi:arrow-right-bold","tags":["arrow","automotive"]},{"name":"mdi:arrow-right-bold-box","tags":["arrow"]},{"name":"mdi:arrow-right-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-right-bold-circle","tags":["arrow"]},{"name":"mdi:arrow-right-bold-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-right-bold-hexagon-outline","tags":["arrow"]},{"name":"mdi:arrow-right-bold-outline","tags":["arrow","automotive"]},{"name":"mdi:arrow-right-bottom","tags":[]},{"name":"mdi:arrow-right-bottom-bold","tags":[]},{"name":"mdi:arrow-right-box","tags":["arrow"]},{"name":"mdi:arrow-right-circle","tags":["arrow","arrow forward circle"]},{"name":"mdi:arrow-right-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-right-drop-circle","tags":["arrow"]},{"name":"mdi:arrow-right-drop-circle-outline","tags":["arrow"]},{"name":"mdi:arrow-right-thick","tags":["arrow","arrow right bold"]},{"name":"mdi:arrow-right-thin","tags":["arrow"]},{"name":"mdi:arrow-right-top","tags":["turn right"]},{"name":"mdi:arrow-right-top-bold","tags":["turn right bold"]},{"name":"mdi:arrow-split-horizontal","tags":["arrow","resize vertical","resize"]},{"name":"mdi:arrow-split-vertical","tags":["arrow","resize horizontal","resize"]},{"name":"mdi:arrow-top-left","tags":["arrow","arrow up left"]},{"name":"mdi:arrow-top-left-bold-box","tags":["arrow"]},{"name":"mdi:arrow-top-left-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-top-left-bold-outline","tags":["arrow","arrow up left bold outline"]},{"name":"mdi:arrow-top-left-bottom-right","tags":["arrow"]},{"name":"mdi:arrow-top-left-bottom-right-bold","tags":["arrow"]},{"name":"mdi:arrow-top-left-thick","tags":["arrow","arrow up left thick","arrow top left bold","arrow up left bold"]},{"name":"mdi:arrow-top-left-thin","tags":["arrow"]},{"name":"mdi:arrow-top-right","tags":["arrow","arrow up right"]},{"name":"mdi:arrow-top-right-bold-box","tags":["arrow"]},{"name":"mdi:arrow-top-right-bold-box-outline","tags":["arrow"]},{"name":"mdi:arrow-top-right-bold-outline","tags":["arrow","arrow up right bold outline"]},{"name":"mdi:arrow-top-right-bottom-left","tags":["arrow"]},{"name":"mdi:arrow-top-right-bottom-left-bold","tags":["arrow"]},{"name":"mdi:arrow-top-right-thick","tags":["arrow","arrow up right thick","arrow top right bold","arrow up right bold"]},{"name":"mdi:arrow-top-right-thin","tags":["arrow"]},{"name":"mdi:arrow-u-down-left","tags":["u turn left"]},{"name":"mdi:arrow-u-down-left-bold","tags":["u turn left bold"]},{"name":"mdi:arrow-u-down-right","tags":["u turn right"]},{"name":"mdi:arrow-u-down-right-bold","tags":["u turn right bold"]},{"name":"mdi:arrow-u-left-bottom","tags":["undo"]},{"name":"mdi:arrow-u-left-bottom-bold","tags":["undo"]},{"name":"mdi:arrow-u-left-top","tags":["undo"]},{"name":"mdi:arrow-u-left-top-bold","tags":["undo"]},{"name":"mdi:arrow-u-right-bottom","tags":["redo"]},{"name":"mdi:arrow-u-right-bottom-bold","tags":["redo"]},{"name":"mdi:arrow-u-right-top","tags":["redo"]},{"name":"mdi:arrow-u-right-top-bold","tags":["redo"]},{"name":"mdi:arrow-u-up-left","tags":[]},{"name":"mdi:arrow-u-up-left-bold","tags":[]},{"name":"mdi:arrow-u-up-right","tags":[]},{"name":"mdi:arrow-u-up-right-bold","tags":[]},{"name":"mdi:arrow-up","tags":["arrow","arrow upward","arrow top"]},{"name":"mdi:arrow-up-bold","tags":["arrow","arrow top bold"]},{"name":"mdi:arrow-up-bold-box","tags":["arrow","arrow top bold box"]},{"name":"mdi:arrow-up-bold-box-outline","tags":["arrow","arrow top bold box outline"]},{"name":"mdi:arrow-up-bold-circle","tags":["arrow","arrow top bold circle"]},{"name":"mdi:arrow-up-bold-circle-outline","tags":["arrow","arrow top bold circle outline"]},{"name":"mdi:arrow-up-bold-hexagon-outline","tags":["arrow","arrow top bold hexagon outline"]},{"name":"mdi:arrow-up-bold-outline","tags":["arrow","arrow top bold outline"]},{"name":"mdi:arrow-up-box","tags":["arrow"]},{"name":"mdi:arrow-up-circle","tags":["arrow","arrow top circle"]},{"name":"mdi:arrow-up-circle-outline","tags":["arrow","arrow top circle outline"]},{"name":"mdi:arrow-up-down","tags":["arrow"]},{"name":"mdi:arrow-up-down-bold","tags":["arrow"]},{"name":"mdi:arrow-up-down-bold-outline","tags":["arrow"]},{"name":"mdi:arrow-up-drop-circle","tags":["arrow","arrow top drop circle"]},{"name":"mdi:arrow-up-drop-circle-outline","tags":["arrow","arrow top drop circle outline"]},{"name":"mdi:arrow-up-left","tags":[]},{"name":"mdi:arrow-up-left-bold","tags":[]},{"name":"mdi:arrow-up-right","tags":[]},{"name":"mdi:arrow-up-right-bold","tags":[]},{"name":"mdi:arrow-up-thick","tags":["arrow","arrow top thick","arrow up bold","arrow top bold"]},{"name":"mdi:arrow-up-thin","tags":["arrow"]},{"name":"mdi:arrow-vertical-lock","tags":["lock","arrow","scroll vertical lock"]},{"name":"mdi:artboard","tags":["drawing / art","canvas","frame"]},{"name":"mdi:asterisk","tags":["required"]},{"name":"mdi:asterisk-circle-outline","tags":["required circle"]},{"name":"mdi:atom","tags":["science"]},{"name":"mdi:atom-variant","tags":["science","orbit"]},{"name":"mdi:attachment-check","tags":["attachment tick","paperclip check","paperclip tick"]},{"name":"mdi:attachment-lock","tags":["lock","paperclip lock"]},{"name":"mdi:attachment-minus","tags":["paperclip minus","paperclip subtract","attachment subtract"]},{"name":"mdi:attachment-off","tags":["paperclip off"]},{"name":"mdi:attachment-plus","tags":["paperclip plus","paperclip add","attachment add"]},{"name":"mdi:attachment-remove","tags":["paperclip remove"]},{"name":"mdi:audio-input-rca","tags":["audio"]},{"name":"mdi:audio-input-stereo-minijack","tags":["audio"]},{"name":"mdi:audio-input-xlr","tags":["audio"]},{"name":"mdi:audio-video","tags":["home automation","audio","av receiver"]},{"name":"mdi:audio-video-off","tags":["home automation","audio","av receiver off"]},{"name":"mdi:augmented-reality","tags":[]},{"name":"mdi:aurora","tags":["science","weather","aurora borealis","aurora australis","northern lights","southern lights","polar lights"]},{"name":"mdi:auto-download","tags":[]},{"name":"mdi:auto-mode","tags":[]},{"name":"mdi:autorenew-off","tags":["arrow","clockwise arrows off","circular arrows off","circle arrows off","sync off"]},{"name":"mdi:awning","tags":["home automation","marquise","sun shade"]},{"name":"mdi:awning-outline","tags":["home automation","marquise outline","sun shade outline"]},{"name":"mdi:axe","tags":["hardware / tools"]},{"name":"mdi:axe-battle","tags":["gaming / rpg"]},{"name":"mdi:axis","tags":[]},{"name":"mdi:axis-arrow","tags":["arrow","accelerometer","gyro"]},{"name":"mdi:axis-arrow-info","tags":["arrow"]},{"name":"mdi:axis-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-lock","tags":["lock"]},{"name":"mdi:axis-x-arrow","tags":["arrow"]},{"name":"mdi:axis-x-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-x-rotate-clockwise","tags":[]},{"name":"mdi:axis-x-rotate-counterclockwise","tags":[]},{"name":"mdi:axis-x-y-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-y-arrow","tags":["arrow"]},{"name":"mdi:axis-y-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-y-rotate-clockwise","tags":[]},{"name":"mdi:axis-y-rotate-counterclockwise","tags":[]},{"name":"mdi:axis-z-arrow","tags":["arrow"]},{"name":"mdi:axis-z-arrow-lock","tags":["lock","arrow"]},{"name":"mdi:axis-z-rotate-clockwise","tags":["vertical rotate clockwise"]},{"name":"mdi:axis-z-rotate-counterclockwise","tags":["vertical rotate counterclockwise"]},{"name":"mdi:baby-bottle","tags":["people / family"]},{"name":"mdi:baby-bottle-outline","tags":["people / family"]},{"name":"mdi:baby-buggy","tags":["people / family","stroller","pram","carriage"]},{"name":"mdi:baby-buggy-off","tags":["people / family"]},{"name":"mdi:baby-carriage-off","tags":["people / family","child friendly off","stroller off","pram off","buggy off"]},{"name":"mdi:backburger","tags":["hamburger menu back"]},{"name":"mdi:backspace-reverse","tags":["clear reverse","erase reverse"]},{"name":"mdi:backspace-reverse-outline","tags":["clear reverse outline","erase reverse outline"]},{"name":"mdi:bacteria","tags":["science","medical / hospital"]},{"name":"mdi:bacteria-outline","tags":["science","medical / hospital"]},{"name":"mdi:badge-account","tags":["account / user","user badge","person badge"]},{"name":"mdi:badge-account-alert","tags":["account / user","alert / error","user badge alert","person badge alert","account badge warning","user badge warning","person badge warning"]},{"name":"mdi:badge-account-alert-outline","tags":["account / user","alert / error","user badge alert outline","person badge alert outline","account badge warning outline","user badge warning outline","person badge warning outline"]},{"name":"mdi:badge-account-outline","tags":["account / user","user badge outline","person badge outline"]},{"name":"mdi:badminton","tags":["sport","shuttlecock"]},{"name":"mdi:bag-personal","tags":["transportation + flying","backpack"]},{"name":"mdi:bag-personal-off","tags":["transportation + flying","backpack off"]},{"name":"mdi:bag-personal-off-outline","tags":["transportation + flying","backpack off outline"]},{"name":"mdi:bag-personal-outline","tags":["transportation + flying","backpack outline"]},{"name":"mdi:bag-personal-tag","tags":["property tag"]},{"name":"mdi:bag-personal-tag-outline","tags":["property tag outline"]},{"name":"mdi:baguette","tags":["food / drink","bread","bakery","french baguette","loaf"]},{"name":"mdi:balloon","tags":["holiday","party balloon"]},{"name":"mdi:ballot-recount","tags":["vote recount"]},{"name":"mdi:ballot-recount-outline","tags":["vote recount outline"]},{"name":"mdi:bank-check","tags":["banking"]},{"name":"mdi:bank-circle","tags":["banking"]},{"name":"mdi:bank-circle-outline","tags":["banking"]},{"name":"mdi:bank-minus","tags":["banking"]},{"name":"mdi:bank-off","tags":["banking"]},{"name":"mdi:bank-off-outline","tags":["banking"]},{"name":"mdi:bank-plus","tags":["banking","bank add"]},{"name":"mdi:bank-remove","tags":["banking"]},{"name":"mdi:bank-transfer","tags":["banking"]},{"name":"mdi:bank-transfer-in","tags":["banking"]},{"name":"mdi:bank-transfer-out","tags":["banking"]},{"name":"mdi:barcode","tags":[]},{"name":"mdi:barcode-off","tags":[]},{"name":"mdi:barcode-scan","tags":["barcode scanner"]},{"name":"mdi:barley","tags":["agriculture","food / drink","grain","wheat","gluten"]},{"name":"mdi:barley-off","tags":["agriculture","gluten free","grain off","wheat off"]},{"name":"mdi:barn","tags":["agriculture","farm"]},{"name":"mdi:baseball","tags":["sport"]},{"name":"mdi:baseball-bat","tags":["sport"]},{"name":"mdi:baseball-diamond","tags":["sport"]},{"name":"mdi:baseball-diamond-outline","tags":["sport"]},{"name":"mdi:baseball-outline","tags":["sport"]},{"name":"mdi:bash","tags":["developer / languages"]},{"name":"mdi:basket-check","tags":["shopping"]},{"name":"mdi:basket-check-outline","tags":["shopping"]},{"name":"mdi:basket-fill","tags":["shopping","skip fill"]},{"name":"mdi:basket-minus","tags":["shopping","shopping basket minus","skip minus"]},{"name":"mdi:basket-minus-outline","tags":["shopping","shopping basket minus outline","skip minus outline"]},{"name":"mdi:basket-off","tags":["shopping","shopping basket off","skip off"]},{"name":"mdi:basket-off-outline","tags":["shopping","shopping basket off outline","skip off outline"]},{"name":"mdi:basket-plus","tags":["shopping","shopping basket plus","skip plus"]},{"name":"mdi:basket-plus-outline","tags":["shopping","shopping basket plus outline","skip plus outline"]},{"name":"mdi:basket-remove","tags":["shopping","shopping basket remove","skip remove"]},{"name":"mdi:basket-remove-outline","tags":["shopping","shopping basket remove outline","skip remove outline"]},{"name":"mdi:basket-unfill","tags":["shopping"]},{"name":"mdi:basketball-hoop","tags":["sport"]},{"name":"mdi:basketball-hoop-outline","tags":["sport"]},{"name":"mdi:bat","tags":["holiday","animal"]},{"name":"mdi:battery-10-bluetooth","tags":["battery"]},{"name":"mdi:battery-20-bluetooth","tags":["battery"]},{"name":"mdi:battery-30-bluetooth","tags":["battery"]},{"name":"mdi:battery-40-bluetooth","tags":["battery"]},{"name":"mdi:battery-50-bluetooth","tags":["battery"]},{"name":"mdi:battery-60-bluetooth","tags":["battery"]},{"name":"mdi:battery-70-bluetooth","tags":["battery"]},{"name":"mdi:battery-80-bluetooth","tags":["battery"]},{"name":"mdi:battery-90-bluetooth","tags":["battery"]},{"name":"mdi:battery-alert-bluetooth","tags":["alert / error","battery","battery warning bluetooth"]},{"name":"mdi:battery-alert-variant","tags":["battery","alert / error"]},{"name":"mdi:battery-alert-variant-outline","tags":["battery","alert / error"]},{"name":"mdi:battery-arrow-down","tags":["battery"]},{"name":"mdi:battery-arrow-down-outline","tags":["battery"]},{"name":"mdi:battery-arrow-up","tags":["battery"]},{"name":"mdi:battery-arrow-up-outline","tags":["battery"]},{"name":"mdi:battery-bluetooth","tags":["battery","battery bluetooth 100","battery bluetooth full"]},{"name":"mdi:battery-bluetooth-variant","tags":["battery"]},{"name":"mdi:battery-charging-high","tags":["battery"]},{"name":"mdi:battery-charging-low","tags":["battery"]},{"name":"mdi:battery-charging-medium","tags":["battery"]},{"name":"mdi:battery-charging-wireless","tags":["battery","home automation","battery charging wireless full","battery charging wireless 100"]},{"name":"mdi:battery-charging-wireless-10","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-20","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-30","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-40","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-50","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-60","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-70","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-80","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-90","tags":["battery","home automation"]},{"name":"mdi:battery-charging-wireless-alert","tags":["battery","home automation","alert / error","battery charging wireless warning"]},{"name":"mdi:battery-charging-wireless-outline","tags":["battery","home automation","battery charging wireless empty","battery charging wireless 0"]},{"name":"mdi:battery-check","tags":["battery"]},{"name":"mdi:battery-check-outline","tags":["battery"]},{"name":"mdi:battery-clock","tags":["battery","home automation","date / time","battery full clock","battery 100 clock"]},{"name":"mdi:battery-clock-outline","tags":["battery","home automation","date / time","batter 0 clock","battery empty clock"]},{"name":"mdi:battery-heart","tags":["battery"]},{"name":"mdi:battery-heart-outline","tags":["battery"]},{"name":"mdi:battery-heart-variant","tags":["battery"]},{"name":"mdi:battery-high","tags":["battery"]},{"name":"mdi:battery-lock","tags":["battery","lock"]},{"name":"mdi:battery-lock-open","tags":["battery","lock"]},{"name":"mdi:battery-low","tags":["battery"]},{"name":"mdi:battery-medium","tags":["battery"]},{"name":"mdi:battery-minus","tags":["battery"]},{"name":"mdi:battery-minus-outline","tags":["battery"]},{"name":"mdi:battery-minus-variant","tags":["battery","home automation"]},{"name":"mdi:battery-negative","tags":["battery","home automation"]},{"name":"mdi:battery-off","tags":["battery"]},{"name":"mdi:battery-off-outline","tags":["battery"]},{"name":"mdi:battery-plus","tags":["battery"]},{"name":"mdi:battery-plus-outline","tags":["battery"]},{"name":"mdi:battery-plus-variant","tags":["battery","home automation","battery saver","battery add"]},{"name":"mdi:battery-positive","tags":["battery","home automation"]},{"name":"mdi:battery-remove","tags":["battery"]},{"name":"mdi:battery-remove-outline","tags":["battery"]},{"name":"mdi:battery-sync","tags":["battery","battery saver","battery recycle","battery eco"]},{"name":"mdi:battery-sync-outline","tags":["battery","battery saver outline","battery eco outline","battery recycle outline"]},{"name":"mdi:battery-unknown-bluetooth","tags":["battery"]},{"name":"mdi:beach","tags":["places","parasol"]},{"name":"mdi:beaker","tags":["science"]},{"name":"mdi:beaker-alert","tags":["alert / error","science"]},{"name":"mdi:beaker-alert-outline","tags":["alert / error","science"]},{"name":"mdi:beaker-check","tags":["science"]},{"name":"mdi:beaker-check-outline","tags":["science"]},{"name":"mdi:beaker-minus","tags":["science"]},{"name":"mdi:beaker-minus-outline","tags":["science"]},{"name":"mdi:beaker-outline","tags":["science"]},{"name":"mdi:beaker-plus","tags":["science"]},{"name":"mdi:beaker-plus-outline","tags":["science"]},{"name":"mdi:beaker-question","tags":["science"]},{"name":"mdi:beaker-question-outline","tags":["science"]},{"name":"mdi:beaker-remove","tags":["science"]},{"name":"mdi:beaker-remove-outline","tags":["science"]},{"name":"mdi:bed-clock","tags":["date / time","bed schedule","bed time","sleep schedule","sleep time"]},{"name":"mdi:bed-double","tags":["home automation","holiday","bedroom"]},{"name":"mdi:bed-empty","tags":["home automation","holiday"]},{"name":"mdi:bed-king-outline","tags":["home automation","holiday","bedroom outline"]},{"name":"mdi:bed-queen","tags":["home automation","holiday","bedroom"]},{"name":"mdi:bed-queen-outline","tags":["home automation","holiday","bedroom outline"]},{"name":"mdi:bed-single","tags":["home automation","holiday","bedroom"]},{"name":"mdi:bed-single-outline","tags":["home automation","holiday","bedroom outline"]},{"name":"mdi:beehive-off-outline","tags":["nature","agriculture"]},{"name":"mdi:beehive-outline","tags":["nature","agriculture","honey outline"]},{"name":"mdi:beekeeper","tags":["nature","agriculture","apiarists","apiculturists","honey farmer"]},{"name":"mdi:beer","tags":["food / drink","pint","pub","bar","drink","cup full"]},{"name":"mdi:beer-outline","tags":["food / drink","drink outline","cup full outline","pint outline","pub outline","bar outline"]},{"name":"mdi:bell-alert","tags":["alert / error","notification","bell warning"]},{"name":"mdi:bell-alert-outline","tags":["alert / error","notification"]},{"name":"mdi:bell-badge","tags":["notification","bell notification"]},{"name":"mdi:bell-badge-outline","tags":["notification","bell notification outline"]},{"name":"mdi:bell-cancel","tags":["notification"]},{"name":"mdi:bell-cancel-outline","tags":["notification"]},{"name":"mdi:bell-check","tags":["notification"]},{"name":"mdi:bell-check-outline","tags":["notification"]},{"name":"mdi:bell-cog","tags":["notification","settings","bell settings","notification settings"]},{"name":"mdi:bell-cog-outline","tags":["notification","settings","bell settings outline","notification settings outline"]},{"name":"mdi:bell-minus","tags":["notification"]},{"name":"mdi:bell-minus-outline","tags":["notification"]},{"name":"mdi:bell-plus","tags":["notification","add alert","bell add"]},{"name":"mdi:bell-plus-outline","tags":["notification","bell add outline","add alert outline"]},{"name":"mdi:bell-remove","tags":["notification"]},{"name":"mdi:bell-remove-outline","tags":["notification"]},{"name":"mdi:bench","tags":[]},{"name":"mdi:bench-back","tags":[]},{"name":"mdi:beta","tags":["alpha / numeric"]},{"name":"mdi:betamax","tags":[]},{"name":"mdi:bicycle","tags":["transportation + other","sport","bike","cycling"]},{"name":"mdi:bicycle-basket","tags":["transportation + other","sport","bike basket"]},{"name":"mdi:bicycle-cargo","tags":["transportation + other","sport","bike cargo"]},{"name":"mdi:bicycle-electric","tags":["transportation + other","bike electric"]},{"name":"mdi:bicycle-penny-farthing","tags":["transportation + other","sport","bicycle high wheel","bicycle antique"]},{"name":"mdi:bike-fast","tags":["transportation + other","sport","velocity"]},{"name":"mdi:bike-pedal","tags":["transportation + other","sport","bike pedal flat"]},{"name":"mdi:bike-pedal-clipless","tags":["transportation + other","sport"]},{"name":"mdi:bike-pedal-mountain","tags":["transportation + other","sport"]},{"name":"mdi:billboard","tags":[]},{"name":"mdi:billiards","tags":["sport","pool","eight ball"]},{"name":"mdi:billiards-rack","tags":["sport","pool table","pool rack","snooker rack","pool triangle","billiards triangle","snooker triangle"]},{"name":"mdi:binoculars","tags":[]},{"name":"mdi:bio","tags":[]},{"name":"mdi:biohazard","tags":["science"]},{"name":"mdi:bird","tags":["animal"]},{"name":"mdi:blinds","tags":["home automation","roller shade closed","window closed"]},{"name":"mdi:blinds-open","tags":["home automation","roller shade open","window open"]},{"name":"mdi:block-helper","tags":[]},{"name":"mdi:blood-bag","tags":["medical / hospital"]},{"name":"mdi:bluetooth","tags":[]},{"name":"mdi:bolt","tags":["hardware / tools"]},{"name":"mdi:bomb","tags":["gaming / rpg"]},{"name":"mdi:bomb-off","tags":["gaming / rpg"]},{"name":"mdi:bone","tags":["animal","holiday"]},{"name":"mdi:bone-off","tags":["animal","holiday"]},{"name":"mdi:book-account","tags":["account / user"]},{"name":"mdi:book-account-outline","tags":["account / user"]},{"name":"mdi:book-alert","tags":["alert / error"]},{"name":"mdi:book-alert-outline","tags":["alert / error"]},{"name":"mdi:book-alphabet","tags":["dictionary"]},{"name":"mdi:book-arrow-down","tags":[]},{"name":"mdi:book-arrow-down-outline","tags":[]},{"name":"mdi:book-arrow-left","tags":[]},{"name":"mdi:book-arrow-left-outline","tags":[]},{"name":"mdi:book-arrow-right","tags":[]},{"name":"mdi:book-arrow-right-outline","tags":[]},{"name":"mdi:book-arrow-up","tags":[]},{"name":"mdi:book-arrow-up-outline","tags":[]},{"name":"mdi:book-cancel","tags":[]},{"name":"mdi:book-cancel-outline","tags":[]},{"name":"mdi:book-check","tags":[]},{"name":"mdi:book-check-outline","tags":[]},{"name":"mdi:book-clock","tags":["date / time","book schedule","book time"]},{"name":"mdi:book-clock-outline","tags":["date / time","book schedule","book time"]},{"name":"mdi:book-cog","tags":["settings","book settings"]},{"name":"mdi:book-cog-outline","tags":["settings","book settings outline"]},{"name":"mdi:book-cross","tags":["religion","bible"]},{"name":"mdi:book-edit","tags":["edit / modify"]},{"name":"mdi:book-edit-outline","tags":["edit / modify"]},{"name":"mdi:book-education","tags":[]},{"name":"mdi:book-education-outline","tags":[]},{"name":"mdi:book-heart","tags":["book favorite","book love"]},{"name":"mdi:book-heart-outline","tags":["book favorite outline","book love outline"]},{"name":"mdi:book-information-variant","tags":["encyclopedia"]},{"name":"mdi:book-lock","tags":["lock","book secure"]},{"name":"mdi:book-lock-open","tags":["lock","book unsecure"]},{"name":"mdi:book-lock-open-outline","tags":["lock"]},{"name":"mdi:book-lock-outline","tags":["lock","book secure outline"]},{"name":"mdi:book-marker","tags":["navigation","book location"]},{"name":"mdi:book-marker-outline","tags":["navigation","book location outline"]},{"name":"mdi:book-minus","tags":[]},{"name":"mdi:book-minus-multiple","tags":["books minus"]},{"name":"mdi:book-minus-multiple-outline","tags":[]},{"name":"mdi:book-minus-outline","tags":[]},{"name":"mdi:book-multiple","tags":["books"]},{"name":"mdi:book-multiple-outline","tags":[]},{"name":"mdi:book-music","tags":["audio","music","audio book"]},{"name":"mdi:book-music-outline","tags":["music"]},{"name":"mdi:book-off","tags":[]},{"name":"mdi:book-off-outline","tags":[]},{"name":"mdi:book-play","tags":[]},{"name":"mdi:book-play-outline","tags":[]},{"name":"mdi:book-plus","tags":["book add"]},{"name":"mdi:book-plus-multiple","tags":["books plus","book multiple add","books add"]},{"name":"mdi:book-plus-multiple-outline","tags":[]},{"name":"mdi:book-plus-outline","tags":[]},{"name":"mdi:book-refresh","tags":[]},{"name":"mdi:book-refresh-outline","tags":[]},{"name":"mdi:book-remove","tags":[]},{"name":"mdi:book-remove-multiple","tags":["books remove"]},{"name":"mdi:book-remove-multiple-outline","tags":[]},{"name":"mdi:book-remove-outline","tags":[]},{"name":"mdi:book-search","tags":[]},{"name":"mdi:book-search-outline","tags":[]},{"name":"mdi:book-settings","tags":["settings"]},{"name":"mdi:book-settings-outline","tags":["settings"]},{"name":"mdi:book-sync","tags":[]},{"name":"mdi:book-sync-outline","tags":[]},{"name":"mdi:bookmark-box","tags":[]},{"name":"mdi:bookmark-box-multiple-outline","tags":["collections bookmark outline","library bookmark outline"]},{"name":"mdi:bookmark-box-outline","tags":[]},{"name":"mdi:bookmark-check-outline","tags":["bookmark success outline"]},{"name":"mdi:bookmark-minus","tags":[]},{"name":"mdi:bookmark-minus-outline","tags":[]},{"name":"mdi:bookmark-music","tags":["music"]},{"name":"mdi:bookmark-music-outline","tags":["music"]},{"name":"mdi:bookmark-off","tags":[]},{"name":"mdi:bookmark-off-outline","tags":[]},{"name":"mdi:bookmark-plus","tags":["bookmark add"]},{"name":"mdi:bookmark-remove","tags":[]},{"name":"mdi:bookmark-remove-outline","tags":[]},{"name":"mdi:bookshelf","tags":[]},{"name":"mdi:boom-gate","tags":["transportation + road","home automation","boom arm","boom barrier","arm barrier","barrier","automatic gate"]},{"name":"mdi:boom-gate-alert","tags":["alert / error","transportation + road","boom arm alert","boom barrier alert","arm barrier alert","barrier alert","automatic gate alert"]},{"name":"mdi:boom-gate-alert-outline","tags":["alert / error","transportation + road","boom arm alert outline","boom barrier alert outline","arm barrier alert outline","barrier alert outline","automatic gate alert outline"]},{"name":"mdi:boom-gate-arrow-down","tags":["transportation + road","boom arm down","boom barrier down","arm barrier down","barrier down","automatic gate down"]},{"name":"mdi:boom-gate-arrow-down-outline","tags":["transportation + road","boom arm down outline","boom barrier down outline","arm barrier down outline","barrier down outline","automatic gate down outline"]},{"name":"mdi:boom-gate-arrow-up","tags":["transportation + road","boom arm up","boom barrier up","arm barrier up","barrier up","automatic gate up"]},{"name":"mdi:boom-gate-arrow-up-outline","tags":["transportation + road","boom arm up outline","boom barrier up outline","arm barrier up outline","barrier up outline","automatic gate up outline"]},{"name":"mdi:boom-gate-outline","tags":["transportation + road","home automation","boom arm outline","boom barrier outline","arm barrier outline","barrier outline","automatic gate outline"]},{"name":"mdi:boom-gate-up","tags":["transportation + road","home automation","boom arm up","boom barrier up","arm barrier up","barrier up","automatic gate up"]},{"name":"mdi:boom-gate-up-outline","tags":["transportation + road","home automation","boom arm up outline","boom barrier up outline","arm barrier up outline","barrier up outline","automatic gate up outline"]},{"name":"mdi:boomerang","tags":["gaming / rpg"]},{"name":"mdi:border-all-variant","tags":["text / content / format"]},{"name":"mdi:border-bottom-variant","tags":["text / content / format"]},{"name":"mdi:border-left-variant","tags":["text / content / format"]},{"name":"mdi:border-none-variant","tags":["text / content / format"]},{"name":"mdi:border-radius","tags":["text / content / format","border round corners"]},{"name":"mdi:border-right-variant","tags":["text / content / format"]},{"name":"mdi:border-top-variant","tags":["text / content / format"]},{"name":"mdi:bottle-soda","tags":["food / drink","bottle coke","bottle pop"]},{"name":"mdi:bottle-soda-classic","tags":["food / drink","bottle coke classic","bottle pop classic"]},{"name":"mdi:bottle-soda-classic-outline","tags":[]},{"name":"mdi:bottle-soda-outline","tags":["food / drink","bottle coke outline","bottle pop outline"]},{"name":"mdi:bottle-tonic","tags":["science","flask"]},{"name":"mdi:bottle-tonic-outline","tags":["science","flask outline"]},{"name":"mdi:bottle-tonic-plus","tags":["gaming / rpg","health potion"]},{"name":"mdi:bottle-tonic-plus-outline","tags":["gaming / rpg","health potion outline"]},{"name":"mdi:bottle-tonic-skull","tags":["gaming / rpg","holiday","poison","moonshine"]},{"name":"mdi:bottle-tonic-skull-outline","tags":["gaming / rpg","holiday","poison outline","moonshine outline"]},{"name":"mdi:bottle-wine","tags":["food / drink"]},{"name":"mdi:bottle-wine-outline","tags":["food / drink"]},{"name":"mdi:bow-arrow","tags":["gaming / rpg","sport"]},{"name":"mdi:bow-tie","tags":["clothing"]},{"name":"mdi:bowl","tags":["food / drink"]},{"name":"mdi:bowl-mix","tags":["food / drink","mixing bowl"]},{"name":"mdi:bowl-mix-outline","tags":["food / drink","mixing bowl outline"]},{"name":"mdi:bowl-outline","tags":["food / drink"]},{"name":"mdi:bowling","tags":["sport"]},{"name":"mdi:box-cutter","tags":["hardware / tools","stanley knife"]},{"name":"mdi:box-cutter-off","tags":[]},{"name":"mdi:box-shadow","tags":[]},{"name":"mdi:boxing-glove","tags":["sport"]},{"name":"mdi:braille","tags":["touch reading","hand reading"]},{"name":"mdi:brain","tags":["medical / hospital"]},{"name":"mdi:bread-slice","tags":["food / drink"]},{"name":"mdi:bread-slice-outline","tags":["food / drink"]},{"name":"mdi:bridge","tags":["places"]},{"name":"mdi:briefcase-account","tags":["account / user","briefcase person","briefcase user"]},{"name":"mdi:briefcase-account-outline","tags":["account / user","briefcase person outline","briefcase user outline"]},{"name":"mdi:briefcase-arrow-left-right","tags":["briefcase transfer","briefcase exchange","briefcase swap"]},{"name":"mdi:briefcase-arrow-left-right-outline","tags":["briefcase exchange outline","briefcase transfer outline","briefcase swap outline"]},{"name":"mdi:briefcase-arrow-up-down","tags":["briefcase exchange","briefcase transfer","briefcase swap"]},{"name":"mdi:briefcase-arrow-up-down-outline","tags":["briefcase exchange outline","briefcase transfer outline","briefcase swap outline"]},{"name":"mdi:briefcase-check-outline","tags":[]},{"name":"mdi:briefcase-clock","tags":["date / time"]},{"name":"mdi:briefcase-clock-outline","tags":["date / time"]},{"name":"mdi:briefcase-download-outline","tags":[]},{"name":"mdi:briefcase-edit","tags":["edit / modify"]},{"name":"mdi:briefcase-edit-outline","tags":["edit / modify"]},{"name":"mdi:briefcase-eye","tags":["briefcase view"]},{"name":"mdi:briefcase-eye-outline","tags":["briefcase view outline"]},{"name":"mdi:briefcase-minus","tags":[]},{"name":"mdi:briefcase-minus-outline","tags":[]},{"name":"mdi:briefcase-off","tags":[]},{"name":"mdi:briefcase-off-outline","tags":[]},{"name":"mdi:briefcase-plus","tags":["briefcase add"]},{"name":"mdi:briefcase-plus-outline","tags":["briefcase add outline"]},{"name":"mdi:briefcase-remove","tags":[]},{"name":"mdi:briefcase-remove-outline","tags":[]},{"name":"mdi:briefcase-search","tags":[]},{"name":"mdi:briefcase-search-outline","tags":[]},{"name":"mdi:briefcase-upload","tags":[]},{"name":"mdi:briefcase-upload-outline","tags":[]},{"name":"mdi:briefcase-variant-off","tags":[]},{"name":"mdi:briefcase-variant-off-outline","tags":[]},{"name":"mdi:brightness-percent","tags":["shopping","discount","sale"]},{"name":"mdi:broom","tags":[]},{"name":"mdi:brush-off","tags":[]},{"name":"mdi:bucket","tags":[]},{"name":"mdi:bucket-outline","tags":[]},{"name":"mdi:buffet","tags":["home automation","sideboard"]},{"name":"mdi:bug-check","tags":["animal","bug tick"]},{"name":"mdi:bug-check-outline","tags":["animal","bug tick outline"]},{"name":"mdi:bug-pause","tags":[]},{"name":"mdi:bug-pause-outline","tags":[]},{"name":"mdi:bug-play","tags":["bug start"]},{"name":"mdi:bug-play-outline","tags":[]},{"name":"mdi:bug-stop","tags":[]},{"name":"mdi:bug-stop-outline","tags":[]},{"name":"mdi:bugle","tags":["automotive","music","car horn"]},{"name":"mdi:bulkhead-light","tags":["home automation"]},{"name":"mdi:bulldozer","tags":["hardware / tools"]},{"name":"mdi:bullet","tags":[]},{"name":"mdi:bulletin-board","tags":["notice board"]},{"name":"mdi:bullhorn-variant","tags":["announcement","megaphone","loudspeaker"]},{"name":"mdi:bullhorn-variant-outline","tags":["announcement outline","megaphone outline","loudspeaker outline"]},{"name":"mdi:bullseye","tags":["sport","target"]},{"name":"mdi:bullseye-arrow","tags":["sport","target arrow"]},{"name":"mdi:bunk-bed","tags":["home automation"]},{"name":"mdi:bunk-bed-outline","tags":["home automation"]},{"name":"mdi:bus-articulated-end","tags":["transportation + road"]},{"name":"mdi:bus-articulated-front","tags":["transportation + road"]},{"name":"mdi:bus-double-decker","tags":["transportation + road"]},{"name":"mdi:bus-electric","tags":["transportation + road"]},{"name":"mdi:bus-marker","tags":["navigation","bus location","bus stop"]},{"name":"mdi:bus-multiple","tags":["transportation + road","fleet"]},{"name":"mdi:bus-school","tags":["transportation + road","education"]},{"name":"mdi:bus-side","tags":["transportation + road"]},{"name":"mdi:bus-stop","tags":["transportation + road","navigation"]},{"name":"mdi:bus-stop-covered","tags":["transportation + road","navigation"]},{"name":"mdi:bus-stop-uncovered","tags":["transportation + road","navigation"]},{"name":"mdi:butterfly","tags":["nature","animal"]},{"name":"mdi:butterfly-outline","tags":["nature","animal"]},{"name":"mdi:button-cursor","tags":["form"]},{"name":"mdi:button-pointer","tags":["form"]},{"name":"mdi:cabin-a-frame","tags":["home automation"]},{"name":"mdi:cable-data","tags":[]},{"name":"mdi:cactus","tags":["nature"]},{"name":"mdi:calculator","tags":["math"]},{"name":"mdi:calendar-account","tags":["date / time","account / user","calendar user"]},{"name":"mdi:calendar-account-outline","tags":["date / time","account / user","calendar user outline"]},{"name":"mdi:calendar-alert","tags":["date / time","alert / error","event alert","calendar warning"]},{"name":"mdi:calendar-alert-outline","tags":["date / time","alert / error"]},{"name":"mdi:calendar-arrow-left","tags":["date / time","reschedule"]},{"name":"mdi:calendar-arrow-right","tags":["date / time","reschedule"]},{"name":"mdi:calendar-badge","tags":["date / time"]},{"name":"mdi:calendar-badge-outline","tags":["date / time"]},{"name":"mdi:calendar-blank","tags":["date / time","calendar today"]},{"name":"mdi:calendar-blank-multiple","tags":["date / time"]},{"name":"mdi:calendar-clock","tags":["date / time","event clock","event time","calendar time"]},{"name":"mdi:calendar-clock-outline","tags":["date / time"]},{"name":"mdi:calendar-collapse-horizontal","tags":["date / time"]},{"name":"mdi:calendar-collapse-horizontal-outline","tags":["date / time"]},{"name":"mdi:calendar-cursor","tags":["date / time"]},{"name":"mdi:calendar-cursor-outline","tags":["date / time"]},{"name":"mdi:calendar-edit","tags":["date / time","edit / modify","event edit"]},{"name":"mdi:calendar-edit-outline","tags":["date / time","edit / modify"]},{"name":"mdi:calendar-end","tags":["date / time"]},{"name":"mdi:calendar-end-outline","tags":["date / time"]},{"name":"mdi:calendar-expand-horizontal","tags":["date / time"]},{"name":"mdi:calendar-expand-horizontal-outline","tags":["date / time"]},{"name":"mdi:calendar-export","tags":["date / time"]},{"name":"mdi:calendar-export-outline","tags":["date / time"]},{"name":"mdi:calendar-filter","tags":["date / time"]},{"name":"mdi:calendar-filter-outline","tags":["date / time","event week end outline"]},{"name":"mdi:calendar-heart","tags":["date / time","event heart"]},{"name":"mdi:calendar-heart-outline","tags":["date / time"]},{"name":"mdi:calendar-import","tags":["date / time"]},{"name":"mdi:calendar-import-outline","tags":["date / time"]},{"name":"mdi:calendar-lock","tags":["date / time","lock"]},{"name":"mdi:calendar-lock-open","tags":["lock","date / time"]},{"name":"mdi:calendar-lock-open-outline","tags":["lock","date / time"]},{"name":"mdi:calendar-lock-outline","tags":["date / time","lock"]},{"name":"mdi:calendar-minus","tags":["date / time","event minus"]},{"name":"mdi:calendar-minus-outline","tags":["date / time"]},{"name":"mdi:calendar-month","tags":["date / time"]},{"name":"mdi:calendar-month-outline","tags":["date / time"]},{"name":"mdi:calendar-multiple","tags":["date / time","event multiple","calendars","events"]},{"name":"mdi:calendar-multiple-check","tags":["date / time","event multiple check","calendar multiple tick","calendars check","calendars tick","event multiple tick","events check","events tick"]},{"name":"mdi:calendar-multiselect","tags":["date / time"]},{"name":"mdi:calendar-multiselect-outline","tags":["date / time"]},{"name":"mdi:calendar-plus","tags":["date / time","event plus","calendar add","event add"]},{"name":"mdi:calendar-plus-outline","tags":["date / time"]},{"name":"mdi:calendar-question","tags":["date / time","calendar rsvp","event question","calendar help"]},{"name":"mdi:calendar-question-outline","tags":["date / time","calendar help outline"]},{"name":"mdi:calendar-refresh","tags":["date / time","calendar repeat"]},{"name":"mdi:calendar-refresh-outline","tags":["date / time","calendar repeat outline"]},{"name":"mdi:calendar-search","tags":["date / time","event search"]},{"name":"mdi:calendar-search-outline","tags":["date / time"]},{"name":"mdi:calendar-star","tags":["date / time","event star","calendar favorite"]},{"name":"mdi:calendar-star-four-points","tags":["date / time","calendar auto","event star four points","event auto"]},{"name":"mdi:calendar-star-outline","tags":["date / time"]},{"name":"mdi:calendar-start","tags":["date / time"]},{"name":"mdi:calendar-start-outline","tags":["date / time"]},{"name":"mdi:calendar-sync","tags":["date / time","calendar repeat"]},{"name":"mdi:calendar-sync-outline","tags":["date / time","calendar repeat outline"]},{"name":"mdi:calendar-today-outline","tags":["date / time","calendar day outline"]},{"name":"mdi:calendar-week","tags":["date / time","event week"]},{"name":"mdi:calendar-week-begin","tags":["date / time","event week begin"]},{"name":"mdi:calendar-week-begin-outline","tags":["date / time","event week begin outline"]},{"name":"mdi:calendar-week-outline","tags":["date / time","event week outline"]},{"name":"mdi:calendar-weekend","tags":["date / time"]},{"name":"mdi:calendar-weekend-outline","tags":["date / time"]},{"name":"mdi:camcorder","tags":["video / movie"]},{"name":"mdi:camcorder-off","tags":["video / movie"]},{"name":"mdi:camera-document","tags":["photography","overhead projector"]},{"name":"mdi:camera-document-off","tags":["photography","overhead projector off"]},{"name":"mdi:camera-flip","tags":["photography","camera sync","camera refresh"]},{"name":"mdi:camera-flip-outline","tags":["photography","camera sync outline","camera refresh outline"]},{"name":"mdi:camera-gopro","tags":["photography","device / tech"]},{"name":"mdi:camera-lock","tags":["photography","lock"]},{"name":"mdi:camera-lock-open","tags":["photography"]},{"name":"mdi:camera-lock-open-outline","tags":["photography"]},{"name":"mdi:camera-lock-outline","tags":["photography","lock"]},{"name":"mdi:camera-marker","tags":["photography","navigation","camera location"]},{"name":"mdi:camera-marker-outline","tags":["photography","navigation","camera location outline"]},{"name":"mdi:camera-metering-center","tags":["photography","camera metering centre"]},{"name":"mdi:camera-metering-matrix","tags":["photography"]},{"name":"mdi:camera-metering-partial","tags":["photography"]},{"name":"mdi:camera-metering-spot","tags":["photography"]},{"name":"mdi:camera-off","tags":["photography"]},{"name":"mdi:camera-off-outline","tags":["photography"]},{"name":"mdi:camera-retake","tags":["photography"]},{"name":"mdi:camera-retake-outline","tags":["photography"]},{"name":"mdi:camera-timer","tags":["date / time","photography"]},{"name":"mdi:campfire","tags":[]},{"name":"mdi:candelabra","tags":["home automation","holiday","candle","candelabrum"]},{"name":"mdi:candelabra-fire","tags":["home automation","holiday","candelabrum fire","candelabrum flame","candelabra flame","candle fire","candle flame"]},{"name":"mdi:candy","tags":["food / drink","treat","chocolate"]},{"name":"mdi:candy-off","tags":["food / drink","chocolate off","treat off"]},{"name":"mdi:candy-off-outline","tags":["food / drink","gaming / rpg","chocolate off outline","treat off outline","navi off"]},{"name":"mdi:candy-outline","tags":["food / drink","gaming / rpg","chocolate outline","treat outline","navi","hey listen","fairy"]},{"name":"mdi:candycane","tags":["holiday","food / drink"]},{"name":"mdi:cannabis","tags":["nature","medical / hospital","weed","pot","marijuana"]},{"name":"mdi:cannabis-off","tags":[]},{"name":"mdi:caps-lock","tags":["text / content / format"]},{"name":"mdi:car-2-plus","tags":["transportation + road","automotive","hov lane","high occupancy vehicle lane","carpool lane"]},{"name":"mdi:car-3-plus","tags":["transportation + road","automotive","hov lane","high occupancy vehicle lane","carpool lane"]},{"name":"mdi:car-arrow-left","tags":["automotive","transportation + road"]},{"name":"mdi:car-arrow-right","tags":["automotive","transportation + road"]},{"name":"mdi:car-back","tags":["automotive","transportation + road"]},{"name":"mdi:car-battery","tags":["battery","automotive"]},{"name":"mdi:car-brake-abs","tags":["automotive","anti lock brake system","anti lock braking system"]},{"name":"mdi:car-brake-alert","tags":["automotive","alert / error","car parking brake","car handbrake","car hand brake","car emergency brake","car brake warning"]},{"name":"mdi:car-brake-fluid-level","tags":["automotive"]},{"name":"mdi:car-brake-hold","tags":["automotive"]},{"name":"mdi:car-brake-low-pressure","tags":["automotive"]},{"name":"mdi:car-brake-parking","tags":["automotive"]},{"name":"mdi:car-brake-retarder","tags":["automotive"]},{"name":"mdi:car-brake-temperature","tags":["automotive"]},{"name":"mdi:car-brake-worn-linings","tags":["automotive"]},{"name":"mdi:car-child-seat","tags":["automotive","people / family"]},{"name":"mdi:car-clock","tags":["date / time","automotive"]},{"name":"mdi:car-clutch","tags":["automotive"]},{"name":"mdi:car-cog","tags":["automotive","settings","transportation + road","car settings"]},{"name":"mdi:car-connected","tags":["transportation + road","automotive"]},{"name":"mdi:car-convertible","tags":["transportation + road","automotive"]},{"name":"mdi:car-coolant-level","tags":["automotive"]},{"name":"mdi:car-cruise-control","tags":["automotive"]},{"name":"mdi:car-defrost-front","tags":["automotive"]},{"name":"mdi:car-defrost-rear","tags":["automotive"]},{"name":"mdi:car-door","tags":["automotive"]},{"name":"mdi:car-door-lock","tags":["automotive","lock"]},{"name":"mdi:car-emergency","tags":["transportation + road","automotive","car police"]},{"name":"mdi:car-esp","tags":["automotive","electronic stability program"]},{"name":"mdi:car-estate","tags":["transportation + road","automotive","car suv","car sports utility vehicle"]},{"name":"mdi:car-hatchback","tags":["transportation + road","automotive"]},{"name":"mdi:car-info","tags":["automotive"]},{"name":"mdi:car-key","tags":["transportation + road","automotive","car rental","rent a car"]},{"name":"mdi:car-lifted-pickup","tags":["automotive","agriculture"]},{"name":"mdi:car-light-alert","tags":["alert / error","automotive"]},{"name":"mdi:car-light-dimmed","tags":["automotive","head light dimmed","low beam"]},{"name":"mdi:car-light-fog","tags":["automotive","head light fog"]},{"name":"mdi:car-light-high","tags":["automotive","head light high","high beam"]},{"name":"mdi:car-limousine","tags":["transportation + road","automotive"]},{"name":"mdi:car-multiple","tags":["transportation + road","automotive"]},{"name":"mdi:car-off","tags":["automotive"]},{"name":"mdi:car-parking-lights","tags":["automotive"]},{"name":"mdi:car-pickup","tags":["transportation + road","automotive","agriculture"]},{"name":"mdi:car-search","tags":["automotive","car find"]},{"name":"mdi:car-search-outline","tags":["automotive","car find outline"]},{"name":"mdi:car-seat","tags":["automotive"]},{"name":"mdi:car-seat-cooler","tags":["automotive"]},{"name":"mdi:car-seat-heater","tags":["automotive"]},{"name":"mdi:car-select","tags":["automotive","car location"]},{"name":"mdi:car-settings","tags":["automotive","settings"]},{"name":"mdi:car-shift-pattern","tags":["automotive","car transmission","car manual transmission"]},{"name":"mdi:car-side","tags":["transportation + road","automotive","car saloon"]},{"name":"mdi:car-speed-limiter","tags":["automotive"]},{"name":"mdi:car-sports","tags":["transportation + road","sport","automotive"]},{"name":"mdi:car-tire-alert","tags":["automotive","alert / error","car tyre alert","car tyre warning","car tire warning"]},{"name":"mdi:car-traction-control","tags":["automotive"]},{"name":"mdi:car-turbocharger","tags":["automotive"]},{"name":"mdi:car-windshield","tags":["automotive","car front glass"]},{"name":"mdi:car-windshield-outline","tags":["automotive","car front glass outline"]},{"name":"mdi:car-wireless","tags":["automotive","car autonomous","car self driving","car smart"]},{"name":"mdi:car-wrench","tags":["automotive","hardware / tools","car repair","mechanic"]},{"name":"mdi:caravan","tags":["transportation + road","home automation","automotive"]},{"name":"mdi:card","tags":["form","button"]},{"name":"mdi:card-account-details","tags":["account / user","identification card","user card details","id card","person card details","drivers license","business card"]},{"name":"mdi:card-account-details-outline","tags":["account / user","identification card outline","user card details outline","id card outline","person card details outline","drivers license outline","business card outline"]},{"name":"mdi:card-account-details-star","tags":["account / user","card account details favorite"]},{"name":"mdi:card-account-details-star-outline","tags":["account / user","card account details favorite outline"]},{"name":"mdi:card-bulleted","tags":[]},{"name":"mdi:card-bulleted-off","tags":[]},{"name":"mdi:card-bulleted-off-outline","tags":[]},{"name":"mdi:card-bulleted-outline","tags":[]},{"name":"mdi:card-bulleted-settings","tags":["settings"]},{"name":"mdi:card-bulleted-settings-outline","tags":["settings"]},{"name":"mdi:card-minus","tags":[]},{"name":"mdi:card-minus-outline","tags":[]},{"name":"mdi:card-multiple","tags":[]},{"name":"mdi:card-multiple-outline","tags":[]},{"name":"mdi:card-off","tags":[]},{"name":"mdi:card-off-outline","tags":[]},{"name":"mdi:card-outline","tags":["form","button outline"]},{"name":"mdi:card-plus","tags":[]},{"name":"mdi:card-plus-outline","tags":[]},{"name":"mdi:card-remove","tags":[]},{"name":"mdi:card-remove-outline","tags":[]},{"name":"mdi:card-text","tags":[]},{"name":"mdi:card-text-outline","tags":[]},{"name":"mdi:cards","tags":["gaming / rpg"]},{"name":"mdi:cards-club","tags":["gaming / rpg","suit clubs","poker club"]},{"name":"mdi:cards-club-outline","tags":[]},{"name":"mdi:cards-diamond","tags":["gaming / rpg","transportation + road","suit diamonds","hov lane","high occupancy vehicle lane","carpool lane","poker diamond"]},{"name":"mdi:cards-diamond-outline","tags":["transportation + road","hov lane outline","high occupancy vehicle lane outline","carpool lane outline","poker diamond outline"]},{"name":"mdi:cards-heart","tags":["gaming / rpg","suit hearts","poker heart"]},{"name":"mdi:cards-heart-outline","tags":[]},{"name":"mdi:cards-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-club","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-club-multiple","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-club-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-club-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-diamond","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-diamond-multiple","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-diamond-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-diamond-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-heart","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-heart-multiple","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-heart-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-heart-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-spade","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-spade-multiple","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-spade-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-playing-spade-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-spade","tags":["gaming / rpg","suit spades","poker spade"]},{"name":"mdi:cards-spade-outline","tags":["gaming / rpg"]},{"name":"mdi:cards-variant","tags":["gaming / rpg"]},{"name":"mdi:carrot","tags":["agriculture","food / drink"]},{"name":"mdi:cart-arrow-down","tags":["shopping","shopping cart arrow down","trolley arrow down"]},{"name":"mdi:cart-arrow-right","tags":["shopping","trolley arrow right","shopping cart arrow right"]},{"name":"mdi:cart-arrow-up","tags":["shopping","shopping cart arrow up","trolley arrow up"]},{"name":"mdi:cart-check","tags":["shopping"]},{"name":"mdi:cart-heart","tags":["shopping","cart favorite","shopping favorite"]},{"name":"mdi:cart-minus","tags":["shopping","shopping cart minus","trolley minus"]},{"name":"mdi:cart-percent","tags":["shopping","cart discount","cart sale","trolley percent"]},{"name":"mdi:cart-remove","tags":["shopping","trolley remove","shopping cart remove"]},{"name":"mdi:cart-variant","tags":["shopping"]},{"name":"mdi:case-sensitive-alt","tags":[]},{"name":"mdi:cash","tags":["currency","banking","shopping","money"]},{"name":"mdi:cash-check","tags":["currency","banking"]},{"name":"mdi:cash-clock","tags":["banking","currency","date / time","cash schedule","payment schedule","payment clock","auto pay"]},{"name":"mdi:cash-fast","tags":["currency","banking","instant deposit","instant transfer","instant cash"]},{"name":"mdi:cash-lock","tags":["lock","currency","banking"]},{"name":"mdi:cash-lock-open","tags":["lock","currency","banking"]},{"name":"mdi:cash-marker","tags":["banking","currency","navigation","cod","cash on delivery","cash location"]},{"name":"mdi:cash-minus","tags":["currency","banking"]},{"name":"mdi:cash-multiple","tags":["currency","banking","money"]},{"name":"mdi:cash-off","tags":["currency","banking"]},{"name":"mdi:cash-plus","tags":["currency","banking"]},{"name":"mdi:cash-refund","tags":["banking","currency","cash return","cash chargeback"]},{"name":"mdi:cash-register","tags":["shopping","banking","till"]},{"name":"mdi:cash-remove","tags":["currency","banking"]},{"name":"mdi:cash-sync","tags":["banking","currency","auto pay","recurring payment","scheduled payment","cash cycle"]},{"name":"mdi:cassette","tags":["music","tape"]},{"name":"mdi:cast-audio","tags":["audio","cast speaker"]},{"name":"mdi:cast-audio-variant","tags":["apple airplay"]},{"name":"mdi:cast-off","tags":["home automation"]},{"name":"mdi:castle","tags":["places"]},{"name":"mdi:cat","tags":["animal","holiday","emoji cat","emoticon cat"]},{"name":"mdi:cctv","tags":["home automation","closed circuit television","security camera"]},{"name":"mdi:cctv-off","tags":["home automation","closed circuit television off","security camera off"]},{"name":"mdi:ceiling-fan","tags":["home automation"]},{"name":"mdi:ceiling-fan-light","tags":["home automation","ceiling fan on"]},{"name":"mdi:ceiling-light","tags":["home automation","ceiling lamp"]},{"name":"mdi:ceiling-light-multiple","tags":["home automation","ceiling lamp multiple"]},{"name":"mdi:ceiling-light-multiple-outline","tags":["home automation","ceiling lamp multiple outline"]},{"name":"mdi:ceiling-light-outline","tags":["home automation"]},{"name":"mdi:cellphone-arrow-down-variant","tags":["cellphone / phone","cellphone download"]},{"name":"mdi:cellphone-basic","tags":["cellphone / phone","device / tech","mobile phone basic"]},{"name":"mdi:cellphone-charging","tags":["cellphone / phone"]},{"name":"mdi:cellphone-check","tags":["cellphone / phone"]},{"name":"mdi:cellphone-key","tags":["cellphone / phone","device / tech","mobile phone key","smartphone key"]},{"name":"mdi:cellphone-marker","tags":["cellphone / phone","navigation","cellphone location","cellphone map","find my phone","cellphone gps"]},{"name":"mdi:cellphone-message","tags":["cellphone / phone","device / tech","mobile phone message","smartphone message"]},{"name":"mdi:cellphone-message-off","tags":["cellphone / phone"]},{"name":"mdi:cellphone-nfc-off","tags":["cellphone / phone"]},{"name":"mdi:cellphone-remove","tags":["cellphone / phone","device / tech","phonelink erase","mobile phone erase","smartphone erase","cellphone erase"]},{"name":"mdi:cellphone-text","tags":["cellphone / phone","device / tech","mobile phone text","smartphone text"]},{"name":"mdi:cellphone-wireless","tags":["cellphone / phone","device / tech","mobile phone wireless","smartphone wireless"]},{"name":"mdi:certificate","tags":["diploma","seal"]},{"name":"mdi:certificate-outline","tags":["diploma outline","seal outline"]},{"name":"mdi:chair-rolling","tags":["home automation","office chair","study chair"]},{"name":"mdi:chair-school","tags":["desk","education","learn"]},{"name":"mdi:chandelier","tags":["home automation","ceiling light","girandole","candelabra lamp","suspended light"]},{"name":"mdi:chart-arc","tags":["math","report arc","widget arc"]},{"name":"mdi:chart-areaspline","tags":["math","report areaspline","widget areaspline","graph areaspline"]},{"name":"mdi:chart-areaspline-variant","tags":["math","report areaspline variant","widget areaspline variant","graph areaspline variant"]},{"name":"mdi:chart-bar","tags":["math","report bar","widget bar","graph bar"]},{"name":"mdi:chart-bar-stacked","tags":["math","report bar stacked","widget bar stacked","graph bar stacked"]},{"name":"mdi:chart-bell-curve","tags":["math","report bell curve","widget bell curve","graph bell curve"]},{"name":"mdi:chart-bell-curve-cumulative","tags":["math","report bell curve cumulative","widget bell curve cumulative","graph bell curve cumulative"]},{"name":"mdi:chart-donut-variant","tags":["math","chart doughnut variant","report donut variant","widget donut variant"]},{"name":"mdi:chart-gantt","tags":["math","report gantt","timeline","widget gantt","roadmap"]},{"name":"mdi:chart-histogram","tags":["math","report histogram","widget histogram","graph histogram"]},{"name":"mdi:chart-line","tags":["math","report line","widget line","graph line"]},{"name":"mdi:chart-line-stacked","tags":["math","report line stacked","widget line stacked","graph line stacked"]},{"name":"mdi:chart-multiple","tags":["math","report multiple","widget multiple","graph multiple"]},{"name":"mdi:chart-ppf","tags":["math","chart production possibility frontier","report ppf","widget ppf","graph ppf"]},{"name":"mdi:chart-sankey","tags":["math","chart snakey","report sankey","widget sankey","graph sankey"]},{"name":"mdi:chart-sankey-variant","tags":["math","chart snakey variant","report sankey variant","widget sankey variant","graph sankey variant"]},{"name":"mdi:chart-scatter-plot","tags":["math","report scatter plot","widget scatter plot","graph scatter plot"]},{"name":"mdi:chart-scatter-plot-hexbin","tags":["math","chart scatterplot hexbin","report scatter plot hexbin","widget scatter plot hexbin","graph scatter plot hexbin"]},{"name":"mdi:chart-timeline","tags":["math","report timeline","widget timeline","graph timeline","roadmap"]},{"name":"mdi:chart-waterfall","tags":["math"]},{"name":"mdi:chat","tags":[]},{"name":"mdi:chat-alert","tags":["alert / error","chat warning"]},{"name":"mdi:chat-alert-outline","tags":["alert / error"]},{"name":"mdi:chat-minus","tags":[]},{"name":"mdi:chat-minus-outline","tags":[]},{"name":"mdi:chat-outline","tags":[]},{"name":"mdi:chat-plus","tags":[]},{"name":"mdi:chat-plus-outline","tags":[]},{"name":"mdi:chat-processing","tags":["chat typing"]},{"name":"mdi:chat-processing-outline","tags":["chat typing outline"]},{"name":"mdi:chat-question","tags":["chat help"]},{"name":"mdi:chat-question-outline","tags":["chat help outline"]},{"name":"mdi:chat-remove","tags":[]},{"name":"mdi:chat-remove-outline","tags":[]},{"name":"mdi:chat-sleep","tags":[]},{"name":"mdi:chat-sleep-outline","tags":[]},{"name":"mdi:check-bold","tags":["check thick","success thick","success bold"]},{"name":"mdi:check-decagram","tags":["verified","decagram check","approve","approval","tick decagram"]},{"name":"mdi:check-decagram-outline","tags":["approve","approval","verified"]},{"name":"mdi:check-network","tags":["tick network"]},{"name":"mdi:check-network-outline","tags":["tick network outline"]},{"name":"mdi:check-underline","tags":[]},{"name":"mdi:check-underline-circle","tags":[]},{"name":"mdi:check-underline-circle-outline","tags":[]},{"name":"mdi:checkbook-arrow-left","tags":["banking","chequebook arrow left"]},{"name":"mdi:checkbook-arrow-right","tags":["banking","chequebook arrow right"]},{"name":"mdi:checkbox-blank-badge","tags":["notification","form","checkbox blank notification","app notification","app badge"]},{"name":"mdi:checkbox-blank-badge-outline","tags":["notification","form","checkbox blank notification outline","app notification outline","app badge outline"]},{"name":"mdi:checkbox-blank-off","tags":["form"]},{"name":"mdi:checkbox-blank-off-outline","tags":["form"]},{"name":"mdi:checkbox-intermediate","tags":["form","checkbox indeterminate"]},{"name":"mdi:checkbox-intermediate-variant","tags":["form","checkbox indeterminate variant"]},{"name":"mdi:checkbox-marked-circle-auto-outline","tags":["form","task auto","todo auto"]},{"name":"mdi:checkbox-marked-circle-minus-outline","tags":["form","todo minus","task minus"]},{"name":"mdi:checkbox-marked-circle-plus-outline","tags":["form","task plus","task add","todo plus","todo add"]},{"name":"mdi:checkbox-multiple-blank","tags":["form","checkboxes blank"]},{"name":"mdi:checkbox-multiple-blank-circle","tags":["form","checkboxes blank circle"]},{"name":"mdi:checkbox-multiple-blank-circle-outline","tags":["form","checkboxes blank circle outline"]},{"name":"mdi:checkbox-multiple-blank-outline","tags":["form","checkboxes blank outline"]},{"name":"mdi:checkbox-multiple-marked","tags":["form","checkboxes marked"]},{"name":"mdi:checkbox-multiple-marked-circle","tags":["form","checkboxes marked circle"]},{"name":"mdi:checkbox-multiple-marked-circle-outline","tags":["form","checkboxes marked circle outline"]},{"name":"mdi:checkbox-multiple-marked-outline","tags":["form","checkboxes marked outline"]},{"name":"mdi:checkbox-multiple-outline","tags":["form","check boxes outline","tick box multiple outline"]},{"name":"mdi:checkbox-outline","tags":["form"]},{"name":"mdi:checkerboard","tags":["gaming / rpg","geographic information system","raster"]},{"name":"mdi:checkerboard-minus","tags":["geographic information system","raster minus"]},{"name":"mdi:checkerboard-plus","tags":["geographic information system","raster plus"]},{"name":"mdi:checkerboard-remove","tags":["geographic information system","raster remove"]},{"name":"mdi:cheese","tags":["food / drink","swiss cheese"]},{"name":"mdi:cheese-off","tags":["food / drink"]},{"name":"mdi:chef-hat","tags":["clothing","toque","cook"]},{"name":"mdi:chemical-weapon","tags":[]},{"name":"mdi:chess-bishop","tags":["gaming / rpg"]},{"name":"mdi:chess-king","tags":["gaming / rpg","crown","royalty"]},{"name":"mdi:chess-knight","tags":["gaming / rpg","chess horse"]},{"name":"mdi:chess-pawn","tags":["gaming / rpg"]},{"name":"mdi:chess-queen","tags":["gaming / rpg","crown","royalty"]},{"name":"mdi:chess-rook","tags":["gaming / rpg","chess castle","chess tower"]},{"name":"mdi:chevron-double-down","tags":["arrow"]},{"name":"mdi:chevron-double-left","tags":["arrow"]},{"name":"mdi:chevron-double-right","tags":["arrow"]},{"name":"mdi:chevron-double-up","tags":["arrow"]},{"name":"mdi:chevron-down-box","tags":["form","arrow"]},{"name":"mdi:chevron-down-box-outline","tags":["form","arrow"]},{"name":"mdi:chevron-down-circle","tags":["arrow"]},{"name":"mdi:chevron-down-circle-outline","tags":["arrow"]},{"name":"mdi:chevron-left-box","tags":["arrow"]},{"name":"mdi:chevron-left-box-outline","tags":["arrow"]},{"name":"mdi:chevron-left-circle","tags":["arrow"]},{"name":"mdi:chevron-left-circle-outline","tags":["arrow"]},{"name":"mdi:chevron-right-box","tags":["arrow"]},{"name":"mdi:chevron-right-box-outline","tags":["arrow"]},{"name":"mdi:chevron-right-circle","tags":["arrow"]},{"name":"mdi:chevron-right-circle-outline","tags":["arrow"]},{"name":"mdi:chevron-up-box","tags":["arrow"]},{"name":"mdi:chevron-up-box-outline","tags":["arrow"]},{"name":"mdi:chevron-up-circle","tags":["arrow"]},{"name":"mdi:chevron-up-circle-outline","tags":["arrow"]},{"name":"mdi:chili-alert","tags":["alert / error"]},{"name":"mdi:chili-alert-outline","tags":["alert / error"]},{"name":"mdi:chili-hot","tags":["food / drink","chilli hot","pepper","spicy"]},{"name":"mdi:chili-hot-outline","tags":[]},{"name":"mdi:chili-medium","tags":["food / drink","chilli medium","pepper","spicy"]},{"name":"mdi:chili-medium-outline","tags":[]},{"name":"mdi:chili-mild","tags":["food / drink","agriculture","chilli mild","pepper","spicy"]},{"name":"mdi:chili-mild-outline","tags":[]},{"name":"mdi:chili-off","tags":["food / drink","chilli off","pepper off","spicy off"]},{"name":"mdi:chili-off-outline","tags":[]},{"name":"mdi:chip","tags":["integrated circuit"]},{"name":"mdi:cigar","tags":[]},{"name":"mdi:cigar-off","tags":[]},{"name":"mdi:circle","tags":["shape","lens"]},{"name":"mdi:circle-box","tags":[]},{"name":"mdi:circle-box-outline","tags":[]},{"name":"mdi:circle-double","tags":["shape"]},{"name":"mdi:circle-half","tags":["shape","brightness half"]},{"name":"mdi:circle-half-full","tags":["shape"]},{"name":"mdi:circle-medium","tags":[]},{"name":"mdi:circle-multiple","tags":["currency","banking","coins"]},{"name":"mdi:circle-off-outline","tags":["null off"]},{"name":"mdi:circle-opacity","tags":["shape","drawing / art","circle transparent"]},{"name":"mdi:circle-outline","tags":["shape","null"]},{"name":"mdi:circle-slice-1","tags":[]},{"name":"mdi:circle-slice-2","tags":[]},{"name":"mdi:circle-slice-3","tags":[]},{"name":"mdi:circle-slice-4","tags":[]},{"name":"mdi:circle-slice-5","tags":[]},{"name":"mdi:circle-slice-6","tags":[]},{"name":"mdi:circle-slice-7","tags":[]},{"name":"mdi:circle-slice-8","tags":[]},{"name":"mdi:circle-small","tags":["math","bullet","multiplication","dot"]},{"name":"mdi:circular-saw","tags":["hardware / tools"]},{"name":"mdi:city-switch","tags":["places","city swap"]},{"name":"mdi:city-variant","tags":["places"]},{"name":"mdi:city-variant-outline","tags":["places"]},{"name":"mdi:clipboard","tags":[]},{"name":"mdi:clipboard-account-outline","tags":["account / user","clipboard user outline","clipboard person outline","assignment ind outline"]},{"name":"mdi:clipboard-alert-outline","tags":["alert / error","clipboard warning outline"]},{"name":"mdi:clipboard-arrow-left-outline","tags":[]},{"name":"mdi:clipboard-arrow-right","tags":[]},{"name":"mdi:clipboard-arrow-right-outline","tags":[]},{"name":"mdi:clipboard-arrow-up","tags":["clipboard arrow top"]},{"name":"mdi:clipboard-arrow-up-outline","tags":["clipboard arrow top outline"]},{"name":"mdi:clipboard-check-multiple","tags":[]},{"name":"mdi:clipboard-check-multiple-outline","tags":[]},{"name":"mdi:clipboard-check-outline","tags":["clipboard tick outline"]},{"name":"mdi:clipboard-clock","tags":["date / time"]},{"name":"mdi:clipboard-clock-outline","tags":["date / time"]},{"name":"mdi:clipboard-edit","tags":["edit / modify"]},{"name":"mdi:clipboard-edit-outline","tags":["edit / modify"]},{"name":"mdi:clipboard-file","tags":["files / folders"]},{"name":"mdi:clipboard-file-outline","tags":["files / folders"]},{"name":"mdi:clipboard-flow","tags":[]},{"name":"mdi:clipboard-flow-outline","tags":[]},{"name":"mdi:clipboard-list","tags":[]},{"name":"mdi:clipboard-list-outline","tags":[]},{"name":"mdi:clipboard-minus","tags":[]},{"name":"mdi:clipboard-minus-outline","tags":[]},{"name":"mdi:clipboard-multiple","tags":[]},{"name":"mdi:clipboard-multiple-outline","tags":[]},{"name":"mdi:clipboard-off","tags":[]},{"name":"mdi:clipboard-off-outline","tags":[]},{"name":"mdi:clipboard-outline","tags":[]},{"name":"mdi:clipboard-play","tags":[]},{"name":"mdi:clipboard-play-multiple","tags":[]},{"name":"mdi:clipboard-play-multiple-outline","tags":[]},{"name":"mdi:clipboard-play-outline","tags":[]},{"name":"mdi:clipboard-plus","tags":["clipboard add"]},{"name":"mdi:clipboard-plus-outline","tags":[]},{"name":"mdi:clipboard-pulse","tags":["medical / hospital","clipboard vitals"]},{"name":"mdi:clipboard-pulse-outline","tags":["medical / hospital","clipboard vitals outline"]},{"name":"mdi:clipboard-remove","tags":[]},{"name":"mdi:clipboard-remove-outline","tags":[]},{"name":"mdi:clipboard-search","tags":[]},{"name":"mdi:clipboard-search-outline","tags":[]},{"name":"mdi:clipboard-text-clock","tags":["date / time","clipboard text date","clipboard text time","clipboard text history"]},{"name":"mdi:clipboard-text-clock-outline","tags":["date / time","clipboard text date outline","clipboard text time outline","clipboard text history outline"]},{"name":"mdi:clipboard-text-multiple","tags":[]},{"name":"mdi:clipboard-text-multiple-outline","tags":[]},{"name":"mdi:clipboard-text-off","tags":[]},{"name":"mdi:clipboard-text-off-outline","tags":[]},{"name":"mdi:clipboard-text-outline","tags":[]},{"name":"mdi:clipboard-text-play","tags":[]},{"name":"mdi:clipboard-text-play-outline","tags":[]},{"name":"mdi:clipboard-text-search","tags":[]},{"name":"mdi:clipboard-text-search-outline","tags":[]},{"name":"mdi:clippy","tags":[]},{"name":"mdi:clock-alert","tags":["date / time","alert / error","clock warning"]},{"name":"mdi:clock-alert-outline","tags":["date / time","alert / error","clock warning"]},{"name":"mdi:clock-check","tags":["date / time"]},{"name":"mdi:clock-check-outline","tags":["date / time"]},{"name":"mdi:clock-digital","tags":["date / time","home automation"]},{"name":"mdi:clock-edit","tags":["date / time","edit / modify"]},{"name":"mdi:clock-edit-outline","tags":["date / time","edit / modify"]},{"name":"mdi:clock-end","tags":["date / time"]},{"name":"mdi:clock-fast","tags":["date / time","velocity"]},{"name":"mdi:clock-in","tags":["date / time"]},{"name":"mdi:clock-minus","tags":["date / time"]},{"name":"mdi:clock-minus-outline","tags":["date / time"]},{"name":"mdi:clock-out","tags":["date / time"]},{"name":"mdi:clock-plus","tags":["date / time"]},{"name":"mdi:clock-plus-outline","tags":["date / time"]},{"name":"mdi:clock-remove","tags":["date / time"]},{"name":"mdi:clock-remove-outline","tags":["date / time"]},{"name":"mdi:clock-star-four-points","tags":["date / time","clock auto"]},{"name":"mdi:clock-star-four-points-outline","tags":["date / time","clock auto outline"]},{"name":"mdi:clock-start","tags":["date / time"]},{"name":"mdi:clock-time-eight","tags":["date / time"]},{"name":"mdi:clock-time-eight-outline","tags":["date / time"]},{"name":"mdi:clock-time-eleven","tags":["date / time"]},{"name":"mdi:clock-time-eleven-outline","tags":["date / time"]},{"name":"mdi:clock-time-five","tags":["date / time"]},{"name":"mdi:clock-time-five-outline","tags":["date / time"]},{"name":"mdi:clock-time-four","tags":["date / time"]},{"name":"mdi:clock-time-four-outline","tags":["date / time"]},{"name":"mdi:clock-time-nine","tags":["date / time"]},{"name":"mdi:clock-time-nine-outline","tags":["date / time"]},{"name":"mdi:clock-time-one","tags":["date / time"]},{"name":"mdi:clock-time-one-outline","tags":["date / time"]},{"name":"mdi:clock-time-seven","tags":["date / time"]},{"name":"mdi:clock-time-seven-outline","tags":["date / time"]},{"name":"mdi:clock-time-six","tags":["date / time"]},{"name":"mdi:clock-time-six-outline","tags":["date / time"]},{"name":"mdi:clock-time-ten","tags":["date / time"]},{"name":"mdi:clock-time-ten-outline","tags":["date / time"]},{"name":"mdi:clock-time-three","tags":["date / time"]},{"name":"mdi:clock-time-three-outline","tags":["date / time"]},{"name":"mdi:clock-time-twelve","tags":["date / time"]},{"name":"mdi:clock-time-twelve-outline","tags":["date / time"]},{"name":"mdi:clock-time-two","tags":["date / time"]},{"name":"mdi:clock-time-two-outline","tags":["date / time"]},{"name":"mdi:close-box","tags":["math","form","multiply box","clear box","cancel box","remove box"]},{"name":"mdi:close-box-multiple","tags":["form","close boxes","library remove","library close","multiply boxes","multiply box multiple","cancel box multiple","remove box multiple"]},{"name":"mdi:close-box-multiple-outline","tags":["form","close boxes outline","library remove outline","library close outline","multiply boxes outline","multiply box multiple outline","remove box multiple","cancel box multiple"]},{"name":"mdi:close-box-outline","tags":["math","form","multiply box outline","clear box outline","remove box outline","cancel box outline"]},{"name":"mdi:close-circle","tags":["form","remove circle","cancel circle","multiply circle","clear circle"]},{"name":"mdi:close-circle-multiple","tags":["form","remove circle multiple","coins close","coins remove","clear circle multiple","multiply circle multiple"]},{"name":"mdi:close-circle-multiple-outline","tags":["form","remove circle multiple outline","coins close outline","coins remove outline","cancel circle multiple outline","multiply circle multiple outline","clear circle multiple outline"]},{"name":"mdi:close-network","tags":["remove network","cancel network","multiply network","clear network"]},{"name":"mdi:close-network-outline","tags":["remove network outline","cancel network outline","multiply network outline","clear network outline"]},{"name":"mdi:close-octagon","tags":["dangerous","multiply octagon","remove octagon","cancel octagon","clear octagon","stop remove"]},{"name":"mdi:close-octagon-outline","tags":["remove octagon outline","multiply octagon outline","clear octagon outline","cancel octagon outline","stop remove outline"]},{"name":"mdi:close-outline","tags":["remove outline","cancel outline","multiply outline","clear outline"]},{"name":"mdi:close-thick","tags":["close bold","remove thick","remove bold","multiply thick","multiply bold","clear thick","clear bold","cancel thick","cancel bold"]},{"name":"mdi:cloud-alert","tags":["alert / error","cloud","weather","cloud warning"]},{"name":"mdi:cloud-alert-outline","tags":["alert / error","weather","cloud"]},{"name":"mdi:cloud-arrow-down","tags":["cloud","weather"]},{"name":"mdi:cloud-arrow-down-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-arrow-left","tags":["weather","cloud"]},{"name":"mdi:cloud-arrow-left-outline","tags":["weather","cloud"]},{"name":"mdi:cloud-arrow-right","tags":["weather","cloud"]},{"name":"mdi:cloud-arrow-right-outline","tags":["weather","cloud"]},{"name":"mdi:cloud-arrow-up","tags":["cloud","weather"]},{"name":"mdi:cloud-arrow-up-outline","tags":["weather","cloud"]},{"name":"mdi:cloud-braces","tags":["cloud","developer / languages","cloud json"]},{"name":"mdi:cloud-cancel","tags":["cloud","weather"]},{"name":"mdi:cloud-cancel-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-check","tags":["cloud","weather"]},{"name":"mdi:cloud-check-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-check-variant-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-clock","tags":["weather","cloud"]},{"name":"mdi:cloud-clock-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-cog","tags":["cloud","weather"]},{"name":"mdi:cloud-cog-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-lock","tags":["cloud","lock"]},{"name":"mdi:cloud-lock-open","tags":["cloud"]},{"name":"mdi:cloud-lock-open-outline","tags":["cloud"]},{"name":"mdi:cloud-lock-outline","tags":["cloud","lock"]},{"name":"mdi:cloud-minus","tags":["cloud"]},{"name":"mdi:cloud-minus-outline","tags":["cloud"]},{"name":"mdi:cloud-percent","tags":["weather","cloud","nature","humidity","rain chance","cloud discount"]},{"name":"mdi:cloud-percent-outline","tags":["weather","cloud","nature","cloud discount outline","humidity outline","rain chance outline"]},{"name":"mdi:cloud-plus","tags":["cloud"]},{"name":"mdi:cloud-plus-outline","tags":["cloud"]},{"name":"mdi:cloud-print","tags":["cloud","printer","home automation"]},{"name":"mdi:cloud-print-outline","tags":["cloud","printer","home automation"]},{"name":"mdi:cloud-question","tags":["cloud","weather"]},{"name":"mdi:cloud-question-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-refresh","tags":["cloud","weather"]},{"name":"mdi:cloud-refresh-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-refresh-variant","tags":["cloud","weather"]},{"name":"mdi:cloud-refresh-variant-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-remove","tags":["cloud"]},{"name":"mdi:cloud-remove-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-search","tags":["cloud","weather"]},{"name":"mdi:cloud-search-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-sync","tags":["cloud","weather"]},{"name":"mdi:cloud-sync-outline","tags":["cloud","weather"]},{"name":"mdi:cloud-tags","tags":["cloud","cloud xml"]},{"name":"mdi:clouds","tags":["weather","cloud"]},{"name":"mdi:clover","tags":["nature","luck"]},{"name":"mdi:clover-outline","tags":["nature","luck outline"]},{"name":"mdi:coach-lamp","tags":["home automation","coach light","carriage lamp","carriage light"]},{"name":"mdi:coach-lamp-variant","tags":["home automation","coach light","carriage light","carriage lamp"]},{"name":"mdi:coat-rack","tags":["home automation","clothing","foyer","hallway","entry room"]},{"name":"mdi:code-array","tags":["developer / languages"]},{"name":"mdi:code-braces","tags":["developer / languages","math","set"]},{"name":"mdi:code-braces-box","tags":["developer / languages"]},{"name":"mdi:code-brackets","tags":["developer / languages","math","square brackets"]},{"name":"mdi:code-equal","tags":["developer / languages"]},{"name":"mdi:code-greater-than","tags":["developer / languages","math"]},{"name":"mdi:code-greater-than-or-equal","tags":["developer / languages","math"]},{"name":"mdi:code-json","tags":["developer / languages"]},{"name":"mdi:code-less-than","tags":["developer / languages","math"]},{"name":"mdi:code-less-than-or-equal","tags":["developer / languages","math"]},{"name":"mdi:code-not-equal","tags":["developer / languages"]},{"name":"mdi:code-not-equal-variant","tags":["developer / languages"]},{"name":"mdi:code-parentheses","tags":["developer / languages"]},{"name":"mdi:code-parentheses-box","tags":["developer / languages"]},{"name":"mdi:code-string","tags":["developer / languages"]},{"name":"mdi:code-tags-check","tags":["developer / languages","code tags tick"]},{"name":"mdi:coffee-maker-check","tags":["home automation","food / drink","coffee maker done","coffee maker complete"]},{"name":"mdi:coffee-maker-check-outline","tags":["home automation","food / drink","coffee maker complete outline","coffee maker done outline"]},{"name":"mdi:coffee-off","tags":["food / drink","drink off","tea off","cup off","free breakfast off","local cafe off"]},{"name":"mdi:coffee-off-outline","tags":["food / drink","drink off outline","cup off outline","tea off outline","free breakfast off outline","local cafe off outline"]},{"name":"mdi:coffee-to-go","tags":["food / drink","tea to go","drink to go","cup to go","free breakfast to go","local cafe to go"]},{"name":"mdi:coffee-to-go-outline","tags":["food / drink","tea to go outline","cup to go outline","drink to go outline","free breakfast to go outline","local cafe to go outline"]},{"name":"mdi:coffin","tags":["holiday","death","dead"]},{"name":"mdi:cog-clockwise","tags":["settings"]},{"name":"mdi:cog-counterclockwise","tags":["settings"]},{"name":"mdi:cog-off","tags":["settings","settings off"]},{"name":"mdi:cog-off-outline","tags":["settings","settings off outline"]},{"name":"mdi:cog-pause","tags":["settings","settings pause","gear pause"]},{"name":"mdi:cog-pause-outline","tags":["settings","settings pause outline","gear pause outline"]},{"name":"mdi:cog-play","tags":["settings","settings play","gear play"]},{"name":"mdi:cog-play-outline","tags":["settings","settings play outline","gear play outline"]},{"name":"mdi:cog-refresh","tags":["settings","settings refresh"]},{"name":"mdi:cog-refresh-outline","tags":["settings","settings refresh outline"]},{"name":"mdi:cog-stop","tags":["settings","settings stop","gear stop"]},{"name":"mdi:cog-stop-outline","tags":["settings","settings stop outline","gear stop outline"]},{"name":"mdi:cog-sync","tags":["settings","settings sync"]},{"name":"mdi:cog-sync-outline","tags":["settings","settings sync outline"]},{"name":"mdi:cog-transfer","tags":["settings","settings transfer"]},{"name":"mdi:cog-transfer-outline","tags":["settings","settings transfer outline"]},{"name":"mdi:collapse-all","tags":["animation minus"]},{"name":"mdi:collapse-all-outline","tags":["animation minus outline"]},{"name":"mdi:comma","tags":[]},{"name":"mdi:comma-box","tags":[]},{"name":"mdi:comma-box-outline","tags":[]},{"name":"mdi:comma-circle","tags":[]},{"name":"mdi:comma-circle-outline","tags":[]},{"name":"mdi:comment","tags":[]},{"name":"mdi:comment-account","tags":["account / user","comment user","comment person"]},{"name":"mdi:comment-account-outline","tags":["account / user","comment user outline","comment person outline"]},{"name":"mdi:comment-alert","tags":["alert / error","comment warning"]},{"name":"mdi:comment-alert-outline","tags":["alert / error","comment warning outline"]},{"name":"mdi:comment-arrow-left","tags":["comment previous"]},{"name":"mdi:comment-arrow-left-outline","tags":["comment previous outline"]},{"name":"mdi:comment-arrow-right","tags":["comment next"]},{"name":"mdi:comment-arrow-right-outline","tags":["comment next outline"]},{"name":"mdi:comment-bookmark","tags":[]},{"name":"mdi:comment-bookmark-outline","tags":[]},{"name":"mdi:comment-check","tags":["comment tick"]},{"name":"mdi:comment-check-outline","tags":["comment tick outline"]},{"name":"mdi:comment-edit","tags":["edit / modify"]},{"name":"mdi:comment-edit-outline","tags":["edit / modify"]},{"name":"mdi:comment-eye","tags":[]},{"name":"mdi:comment-eye-outline","tags":[]},{"name":"mdi:comment-flash","tags":["comment quick"]},{"name":"mdi:comment-flash-outline","tags":["comment quick outline"]},{"name":"mdi:comment-minus","tags":[]},{"name":"mdi:comment-minus-outline","tags":[]},{"name":"mdi:comment-multiple","tags":["comments"]},{"name":"mdi:comment-multiple-outline","tags":["comments outline"]},{"name":"mdi:comment-off","tags":[]},{"name":"mdi:comment-off-outline","tags":[]},{"name":"mdi:comment-outline","tags":[]},{"name":"mdi:comment-plus","tags":["comment add"]},{"name":"mdi:comment-plus-outline","tags":["comment add outline"]},{"name":"mdi:comment-processing","tags":[]},{"name":"mdi:comment-processing-outline","tags":[]},{"name":"mdi:comment-question","tags":["comment help"]},{"name":"mdi:comment-question-outline","tags":["comment help outline"]},{"name":"mdi:comment-quote","tags":["feedback"]},{"name":"mdi:comment-quote-outline","tags":["feedback outline"]},{"name":"mdi:comment-remove","tags":[]},{"name":"mdi:comment-remove-outline","tags":[]},{"name":"mdi:comment-search","tags":[]},{"name":"mdi:comment-search-outline","tags":[]},{"name":"mdi:comment-text","tags":[]},{"name":"mdi:comment-text-multiple","tags":["comments text"]},{"name":"mdi:comment-text-multiple-outline","tags":["comments text outline"]},{"name":"mdi:comment-text-outline","tags":[]},{"name":"mdi:compare-remove","tags":[]},{"name":"mdi:compass-outline","tags":["navigation","geographic information system"]},{"name":"mdi:compass-rose","tags":["navigation"]},{"name":"mdi:cone","tags":["shape"]},{"name":"mdi:cone-off","tags":["shape"]},{"name":"mdi:connection","tags":["home automation","plug"]},{"name":"mdi:console","tags":["terminal"]},{"name":"mdi:console-line","tags":["terminal line"]},{"name":"mdi:console-network","tags":["terminal network"]},{"name":"mdi:console-network-outline","tags":["terminal network outline"]},{"name":"mdi:consolidate","tags":[]},{"name":"mdi:contactless-payment","tags":["currency"]},{"name":"mdi:contactless-payment-circle-outline","tags":["currency"]},{"name":"mdi:contain","tags":[]},{"name":"mdi:contain-end","tags":[]},{"name":"mdi:contain-start","tags":[]},{"name":"mdi:content-duplicate","tags":[]},{"name":"mdi:content-save-alert","tags":["alert / error","floppy disc alert"]},{"name":"mdi:content-save-alert-outline","tags":["alert / error","floppy disc alert outline"]},{"name":"mdi:content-save-all","tags":["floppy disc multiple"]},{"name":"mdi:content-save-all-outline","tags":["floppy disc multiple outline"]},{"name":"mdi:content-save-check","tags":[]},{"name":"mdi:content-save-check-outline","tags":[]},{"name":"mdi:content-save-cog","tags":["settings","floppy disc cog"]},{"name":"mdi:content-save-cog-outline","tags":["settings","floppy disc cog outline"]},{"name":"mdi:content-save-edit","tags":["edit / modify","floppy disc edit"]},{"name":"mdi:content-save-edit-outline","tags":["edit / modify","floppy disc edit outline"]},{"name":"mdi:content-save-minus","tags":[]},{"name":"mdi:content-save-minus-outline","tags":[]},{"name":"mdi:content-save-move","tags":["floppy disc move"]},{"name":"mdi:content-save-move-outline","tags":["floppy disc move outline"]},{"name":"mdi:content-save-off","tags":[]},{"name":"mdi:content-save-off-outline","tags":[]},{"name":"mdi:content-save-plus","tags":["content save add"]},{"name":"mdi:content-save-plus-outline","tags":["content save add outline"]},{"name":"mdi:content-save-settings","tags":["settings","floppy disc settings"]},{"name":"mdi:content-save-settings-outline","tags":["settings","floppy disc settings outline"]},{"name":"mdi:contrast","tags":[]},{"name":"mdi:controller-classic","tags":["gaming / rpg","gamepad classic"]},{"name":"mdi:controller-classic-outline","tags":["gaming / rpg","gamepad classic outline"]},{"name":"mdi:cookie-alert","tags":["food / drink","alert / error","biscuit alert"]},{"name":"mdi:cookie-alert-outline","tags":["food / drink","alert / error","biscuit alert outline"]},{"name":"mdi:cookie-check","tags":["food / drink","biscuit check"]},{"name":"mdi:cookie-check-outline","tags":["food / drink","biscuit check outline"]},{"name":"mdi:cookie-clock","tags":["food / drink","date / time","biscuit clock"]},{"name":"mdi:cookie-clock-outline","tags":["food / drink","date / time","biscuit clock outline"]},{"name":"mdi:cookie-cog","tags":["food / drink","settings","biscuit cog"]},{"name":"mdi:cookie-cog-outline","tags":["food / drink","settings","biscuit cog outline"]},{"name":"mdi:cookie-edit","tags":["food / drink","edit / modify","biscuit edit"]},{"name":"mdi:cookie-edit-outline","tags":["food / drink","edit / modify","biscuit edit outline"]},{"name":"mdi:cookie-lock","tags":["food / drink","lock","biscuit lock"]},{"name":"mdi:cookie-lock-outline","tags":["food / drink","lock","biscuit lock outline"]},{"name":"mdi:cookie-minus","tags":["food / drink","biscuit minus"]},{"name":"mdi:cookie-minus-outline","tags":["food / drink","biscuit minus outline"]},{"name":"mdi:cookie-off","tags":["food / drink","biscuit off"]},{"name":"mdi:cookie-off-outline","tags":["food / drink","biscuit off outline"]},{"name":"mdi:cookie-outline","tags":["food / drink","biscuit outline"]},{"name":"mdi:cookie-plus","tags":["food / drink","biscuit plus"]},{"name":"mdi:cookie-plus-outline","tags":["food / drink","biscuit plus outline"]},{"name":"mdi:cookie-refresh","tags":["food / drink","biscuit refresh"]},{"name":"mdi:cookie-refresh-outline","tags":["food / drink","biscuit refresh outline"]},{"name":"mdi:cookie-remove","tags":["food / drink","biscuit remove"]},{"name":"mdi:cookie-remove-outline","tags":["food / drink","biscuit remove outline"]},{"name":"mdi:cookie-settings","tags":["food / drink","settings","biscuit settings","cookie crumbs","biscuit crumbs"]},{"name":"mdi:cookie-settings-outline","tags":["food / drink","settings","biscuit settings outline","cookie crumbs outline","biscuit crumbs outline"]},{"name":"mdi:coolant-temperature","tags":["automotive"]},{"name":"mdi:copyleft","tags":[]},{"name":"mdi:corn","tags":["agriculture","food / drink"]},{"name":"mdi:corn-off","tags":["food / drink","agriculture"]},{"name":"mdi:cosine-wave","tags":["audio","frequency","amplitude"]},{"name":"mdi:counter","tags":["automotive","score","numbers","odometer"]},{"name":"mdi:cow","tags":["animal","agriculture","emoji cow","emoticon cow"]},{"name":"mdi:cow-off","tags":["food / drink","agriculture","animal","dairy off","dairy free"]},{"name":"mdi:cpu-32-bit","tags":["chip 32 bit"]},{"name":"mdi:cpu-64-bit","tags":["chip 64 bit"]},{"name":"mdi:crane","tags":[]},{"name":"mdi:creation-outline","tags":["auto awesome outline"]},{"name":"mdi:credit-card","tags":["banking","currency"]},{"name":"mdi:credit-card-check","tags":["banking"]},{"name":"mdi:credit-card-check-outline","tags":["banking"]},{"name":"mdi:credit-card-chip","tags":["banking","credit card icc chip"]},{"name":"mdi:credit-card-chip-outline","tags":["banking","credit card icc chip outline"]},{"name":"mdi:credit-card-clock","tags":["banking","date / time"]},{"name":"mdi:credit-card-clock-outline","tags":["banking","date / time"]},{"name":"mdi:credit-card-edit","tags":["edit / modify","banking"]},{"name":"mdi:credit-card-edit-outline","tags":["edit / modify","banking"]},{"name":"mdi:credit-card-fast","tags":["banking","credit card swipe"]},{"name":"mdi:credit-card-fast-outline","tags":["banking","credit card swipe outline"]},{"name":"mdi:credit-card-lock","tags":["banking","lock"]},{"name":"mdi:credit-card-lock-outline","tags":["banking","lock"]},{"name":"mdi:credit-card-marker","tags":["banking","navigation","credit card location","payment on delivery"]},{"name":"mdi:credit-card-marker-outline","tags":["banking","navigation","cod","payment on delivery outline","credit card location outline"]},{"name":"mdi:credit-card-minus","tags":["banking"]},{"name":"mdi:credit-card-minus-outline","tags":["banking"]},{"name":"mdi:credit-card-multiple","tags":["banking"]},{"name":"mdi:credit-card-multiple-outline","tags":["banking","credit cards"]},{"name":"mdi:credit-card-off","tags":["banking"]},{"name":"mdi:credit-card-off-outline","tags":["banking"]},{"name":"mdi:credit-card-plus","tags":["banking"]},{"name":"mdi:credit-card-plus-outline","tags":["banking","credit card add"]},{"name":"mdi:credit-card-refresh","tags":["banking"]},{"name":"mdi:credit-card-refresh-outline","tags":["banking"]},{"name":"mdi:credit-card-refund","tags":["banking"]},{"name":"mdi:credit-card-refund-outline","tags":["banking"]},{"name":"mdi:credit-card-remove","tags":["banking"]},{"name":"mdi:credit-card-remove-outline","tags":["banking"]},{"name":"mdi:credit-card-scan","tags":["banking"]},{"name":"mdi:credit-card-scan-outline","tags":["banking"]},{"name":"mdi:credit-card-search","tags":["banking"]},{"name":"mdi:credit-card-search-outline","tags":["banking"]},{"name":"mdi:credit-card-settings","tags":["banking","settings"]},{"name":"mdi:credit-card-settings-outline","tags":["banking","settings","payment settings"]},{"name":"mdi:credit-card-sync","tags":["banking"]},{"name":"mdi:credit-card-sync-outline","tags":["banking"]},{"name":"mdi:credit-card-wireless","tags":["currency","banking"]},{"name":"mdi:credit-card-wireless-off","tags":["banking"]},{"name":"mdi:credit-card-wireless-off-outline","tags":["banking"]},{"name":"mdi:credit-card-wireless-outline","tags":["currency","banking","credit card contactless"]},{"name":"mdi:cross","tags":["religion","holiday","christianity","religion christian"]},{"name":"mdi:cross-bolnisi","tags":["religion"]},{"name":"mdi:cross-celtic","tags":["religion","holiday"]},{"name":"mdi:cross-outline","tags":["religion","religion christian outline","christianity outline"]},{"name":"mdi:crown","tags":[]},{"name":"mdi:crown-circle","tags":["gaming / rpg","checkers"]},{"name":"mdi:crown-circle-outline","tags":["gaming / rpg","checkers outline"]},{"name":"mdi:crown-outline","tags":[]},{"name":"mdi:crystal-ball","tags":["gaming / rpg"]},{"name":"mdi:cube","tags":["shape"]},{"name":"mdi:cube-off","tags":[]},{"name":"mdi:cube-off-outline","tags":["food / drink","sugar off","sugar cube off","sugar free"]},{"name":"mdi:cube-outline","tags":["shape","food / drink","sugar","sugar cube"]},{"name":"mdi:cube-send","tags":[]},{"name":"mdi:cube-unfolded","tags":[]},{"name":"mdi:cup","tags":["food / drink","glass","drink"]},{"name":"mdi:cup-off","tags":["food / drink","glass off","drink off"]},{"name":"mdi:cup-off-outline","tags":["food / drink","glass off outline","drink off outline"]},{"name":"mdi:cup-outline","tags":["food / drink","glass outline","drink outline","cup empty"]},{"name":"mdi:cupboard","tags":["home automation"]},{"name":"mdi:cupboard-outline","tags":["home automation"]},{"name":"mdi:cupcake","tags":["food / drink"]},{"name":"mdi:curling","tags":["sport"]},{"name":"mdi:currency-bdt","tags":["banking","currency","taka","bangladeshi taka"]},{"name":"mdi:currency-brl","tags":["banking","currency","brazilian real"]},{"name":"mdi:currency-eth","tags":["currency","banking","ethereum","xi"]},{"name":"mdi:currency-eur-off","tags":["currency","banking"]},{"name":"mdi:currency-ils","tags":["banking","currency"]},{"name":"mdi:currency-inr","tags":["currency","banking","rupee"]},{"name":"mdi:currency-krw","tags":["currency","banking","won"]},{"name":"mdi:currency-kzt","tags":["banking","currency","kazakhstani tenge"]},{"name":"mdi:currency-mnt","tags":["currency","banking","currency mongolian tugrug"]},{"name":"mdi:currency-ngn","tags":["currency","banking","naira"]},{"name":"mdi:currency-php","tags":["banking","currency","philippine peso"]},{"name":"mdi:currency-rial","tags":["currency","banking","currency riyal","currency irr","currency omr","currency yer","currency sar"]},{"name":"mdi:currency-sign","tags":["currency","banking","currency scarab"]},{"name":"mdi:currency-thb","tags":["banking","currency thai baht"]},{"name":"mdi:currency-twd","tags":["currency","banking","new taiwan dollar"]},{"name":"mdi:currency-uah","tags":["banking","currency hryvnia","currency ukraine"]},{"name":"mdi:current-ac","tags":["alternating current"]},{"name":"mdi:current-dc","tags":["battery","direct current"]},{"name":"mdi:cursor-default","tags":[]},{"name":"mdi:cursor-default-click","tags":[]},{"name":"mdi:cursor-default-click-outline","tags":[]},{"name":"mdi:cursor-default-gesture","tags":[]},{"name":"mdi:cursor-default-gesture-outline","tags":[]},{"name":"mdi:cursor-default-outline","tags":[]},{"name":"mdi:cursor-move","tags":[]},{"name":"mdi:cursor-pointer","tags":["cursor hand"]},{"name":"mdi:cursor-text","tags":[]},{"name":"mdi:curtains","tags":["home automation","drapes","window"]},{"name":"mdi:curtains-closed","tags":["home automation","drapes closed","window closed"]},{"name":"mdi:cylinder","tags":["shape"]},{"name":"mdi:cylinder-off","tags":["shape"]},{"name":"mdi:dance-ballroom","tags":["people / family","human dance ballroom"]},{"name":"mdi:dance-pole","tags":["sport","people / family","kho kho","human dance pole"]},{"name":"mdi:data-matrix","tags":[]},{"name":"mdi:data-matrix-edit","tags":["edit / modify"]},{"name":"mdi:data-matrix-minus","tags":[]},{"name":"mdi:data-matrix-plus","tags":[]},{"name":"mdi:data-matrix-remove","tags":[]},{"name":"mdi:data-matrix-scan","tags":[]},{"name":"mdi:database","tags":["geographic information system","database","storage"]},{"name":"mdi:database-alert","tags":["database","alert / error"]},{"name":"mdi:database-alert-outline","tags":["database","alert / error"]},{"name":"mdi:database-arrow-down","tags":["database"]},{"name":"mdi:database-arrow-down-outline","tags":["database"]},{"name":"mdi:database-arrow-left","tags":["database"]},{"name":"mdi:database-arrow-left-outline","tags":["database"]},{"name":"mdi:database-arrow-right","tags":["database"]},{"name":"mdi:database-arrow-right-outline","tags":["database"]},{"name":"mdi:database-arrow-up","tags":["database"]},{"name":"mdi:database-arrow-up-outline","tags":["database"]},{"name":"mdi:database-check","tags":["geographic information system","database","database tick"]},{"name":"mdi:database-check-outline","tags":["database"]},{"name":"mdi:database-clock","tags":["database","date / time"]},{"name":"mdi:database-clock-outline","tags":["database","date / time"]},{"name":"mdi:database-cog","tags":["database","settings"]},{"name":"mdi:database-cog-outline","tags":["database","settings"]},{"name":"mdi:database-edit","tags":["edit / modify","geographic information system","database"]},{"name":"mdi:database-edit-outline","tags":["database","edit / modify"]},{"name":"mdi:database-export","tags":["geographic information system","database"]},{"name":"mdi:database-export-outline","tags":["database"]},{"name":"mdi:database-eye","tags":["database","database view"]},{"name":"mdi:database-eye-off","tags":["database","database view off"]},{"name":"mdi:database-eye-off-outline","tags":["database","database view off outline"]},{"name":"mdi:database-eye-outline","tags":["database","database view outline"]},{"name":"mdi:database-import","tags":["geographic information system","database"]},{"name":"mdi:database-import-outline","tags":["database"]},{"name":"mdi:database-lock","tags":["lock","geographic information system","database"]},{"name":"mdi:database-lock-outline","tags":["database","lock"]},{"name":"mdi:database-marker","tags":["geographic information system","database","navigation","database location"]},{"name":"mdi:database-marker-outline","tags":["database","navigation","database location outline"]},{"name":"mdi:database-minus","tags":["geographic information system","database"]},{"name":"mdi:database-minus-outline","tags":["database"]},{"name":"mdi:database-off","tags":["database"]},{"name":"mdi:database-off-outline","tags":["database"]},{"name":"mdi:database-outline","tags":["database"]},{"name":"mdi:database-plus","tags":["geographic information system","database","database add"]},{"name":"mdi:database-plus-outline","tags":["database"]},{"name":"mdi:database-refresh","tags":["database"]},{"name":"mdi:database-refresh-outline","tags":["database"]},{"name":"mdi:database-remove","tags":["geographic information system","database"]},{"name":"mdi:database-remove-outline","tags":["database"]},{"name":"mdi:database-search","tags":["geographic information system","database","sql query"]},{"name":"mdi:database-search-outline","tags":["database"]},{"name":"mdi:database-settings","tags":["settings","geographic information system","database"]},{"name":"mdi:database-settings-outline","tags":["database","settings"]},{"name":"mdi:database-sync","tags":["geographic information system","database"]},{"name":"mdi:database-sync-outline","tags":["database"]},{"name":"mdi:death-star","tags":[]},{"name":"mdi:death-star-variant","tags":[]},{"name":"mdi:deathly-hallows","tags":["harry potter"]},{"name":"mdi:debug-step-into","tags":[]},{"name":"mdi:debug-step-out","tags":[]},{"name":"mdi:debug-step-over","tags":["skip","jump"]},{"name":"mdi:decagram","tags":["shape","starburst"]},{"name":"mdi:decagram-outline","tags":["shape","starburst outline"]},{"name":"mdi:decimal","tags":["math"]},{"name":"mdi:decimal-comma","tags":["math"]},{"name":"mdi:decimal-comma-decrease","tags":["math"]},{"name":"mdi:decimal-comma-increase","tags":["math"]},{"name":"mdi:decimal-decrease","tags":["math"]},{"name":"mdi:decimal-increase","tags":["math"]},{"name":"mdi:delete-alert","tags":["alert / error"]},{"name":"mdi:delete-alert-outline","tags":["alert / error"]},{"name":"mdi:delete-circle","tags":["trash circle","bin circle","garbage can circle","garbage circle","rubbish bin circle","rubbish circle","trash can circle"]},{"name":"mdi:delete-circle-outline","tags":["bin circle outline","garbage can circle outline","garbage circle outline","rubbish bin circle outline","rubbish circle outline","trash can circle outline","trash circle outline"]},{"name":"mdi:delete-clock","tags":["date / time"]},{"name":"mdi:delete-clock-outline","tags":["date / time"]},{"name":"mdi:delete-empty","tags":["trash empty","bin empty","rubbish empty","rubbish bin empty","trash can empty","garbage empty","garbage can empty"]},{"name":"mdi:delete-empty-outline","tags":[]},{"name":"mdi:delete-off","tags":[]},{"name":"mdi:delete-off-outline","tags":[]},{"name":"mdi:delete-variant","tags":["trash variant","bin variant","cup ice","drink ice"]},{"name":"mdi:desk","tags":[]},{"name":"mdi:desk-lamp","tags":["home automation"]},{"name":"mdi:desk-lamp-off","tags":["home automation"]},{"name":"mdi:desk-lamp-on","tags":["home automation"]},{"name":"mdi:deskphone","tags":["cellphone / phone","device / tech"]},{"name":"mdi:desktop-classic","tags":["device / tech","home automation","computer classic"]},{"name":"mdi:desktop-tower","tags":["device / tech","home automation"]},{"name":"mdi:desktop-tower-monitor","tags":["device / tech"]},{"name":"mdi:dharmachakra","tags":["religion","dharma wheel","religion buddhist","buddhism"]},{"name":"mdi:diabetes","tags":["medical / hospital","hand blood"]},{"name":"mdi:diameter","tags":["math","circle diameter","sphere diameter"]},{"name":"mdi:diameter-outline","tags":["math","circle diameter outline","sphere diameter outline"]},{"name":"mdi:diameter-variant","tags":["math","circle diameter variant","sphere diameter variant"]},{"name":"mdi:diamond","tags":[]},{"name":"mdi:diamond-outline","tags":[]},{"name":"mdi:diamond-stone","tags":["jewel"]},{"name":"mdi:dice-1","tags":["gaming / rpg","die 1","dice one"]},{"name":"mdi:dice-1-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-2","tags":["gaming / rpg","die 2","dice two"]},{"name":"mdi:dice-2-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-3","tags":["gaming / rpg","die 3","dice three"]},{"name":"mdi:dice-3-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-4","tags":["gaming / rpg","die 4","dice four"]},{"name":"mdi:dice-4-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-5","tags":["gaming / rpg","die 5","dice five"]},{"name":"mdi:dice-5-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-6","tags":["gaming / rpg","die 6","dice six"]},{"name":"mdi:dice-6-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-d10","tags":["gaming / rpg"]},{"name":"mdi:dice-d10-outline","tags":["gaming / rpg","die d10"]},{"name":"mdi:dice-d12","tags":["gaming / rpg"]},{"name":"mdi:dice-d12-outline","tags":["gaming / rpg"]},{"name":"mdi:dice-d20","tags":["gaming / rpg"]},{"name":"mdi:dice-d20-outline","tags":["gaming / rpg","die d20"]},{"name":"mdi:dice-d4","tags":["gaming / rpg"]},{"name":"mdi:dice-d4-outline","tags":["gaming / rpg","die d4"]},{"name":"mdi:dice-d6","tags":["gaming / rpg"]},{"name":"mdi:dice-d6-outline","tags":["gaming / rpg","die d6"]},{"name":"mdi:dice-d8","tags":["gaming / rpg"]},{"name":"mdi:dice-d8-outline","tags":["gaming / rpg","die d8"]},{"name":"mdi:dice-multiple","tags":["gaming / rpg","die multiple"]},{"name":"mdi:dice-multiple-outline","tags":["gaming / rpg"]},{"name":"mdi:dip-switch","tags":[]},{"name":"mdi:disc","tags":["music","cd rom","dvd"]},{"name":"mdi:disc-player","tags":["home automation","device / tech"]},{"name":"mdi:dishwasher-alert","tags":["home automation","alert / error"]},{"name":"mdi:dishwasher-off","tags":["home automation"]},{"name":"mdi:distribute-horizontal-center","tags":[]},{"name":"mdi:distribute-horizontal-left","tags":[]},{"name":"mdi:distribute-horizontal-right","tags":[]},{"name":"mdi:distribute-vertical-bottom","tags":[]},{"name":"mdi:distribute-vertical-center","tags":[]},{"name":"mdi:distribute-vertical-top","tags":[]},{"name":"mdi:diversify","tags":[]},{"name":"mdi:diving-flippers","tags":["sport"]},{"name":"mdi:diving-helmet","tags":[]},{"name":"mdi:diving-scuba-flag","tags":[]},{"name":"mdi:diving-scuba-mask","tags":["sport"]},{"name":"mdi:diving-scuba-tank","tags":[]},{"name":"mdi:diving-scuba-tank-multiple","tags":[]},{"name":"mdi:diving-snorkel","tags":["sport"]},{"name":"mdi:division","tags":["math","obelus"]},{"name":"mdi:division-box","tags":["math"]},{"name":"mdi:dna","tags":["science","helix"]},{"name":"mdi:dock-bottom","tags":[]},{"name":"mdi:dock-left","tags":[]},{"name":"mdi:dock-right","tags":[]},{"name":"mdi:dock-top","tags":[]},{"name":"mdi:dock-window","tags":[]},{"name":"mdi:doctor","tags":["medical / hospital"]},{"name":"mdi:dog","tags":["animal","emoji dog","emoticon dog"]},{"name":"mdi:dog-service","tags":["animal","guide dog","k9","canine"]},{"name":"mdi:dog-side","tags":["animal","k9","canine"]},{"name":"mdi:dog-side-off","tags":["animal"]},{"name":"mdi:dolly","tags":["hand truck","trolley"]},{"name":"mdi:dolphin","tags":["animal","porpoise"]},{"name":"mdi:domain-plus","tags":[]},{"name":"mdi:domain-remove","tags":[]},{"name":"mdi:domain-switch","tags":[]},{"name":"mdi:dome-light","tags":[]},{"name":"mdi:domino-mask","tags":["robber mask","zorro mask"]},{"name":"mdi:donkey","tags":["animal"]},{"name":"mdi:door","tags":["home automation"]},{"name":"mdi:door-closed","tags":["home automation"]},{"name":"mdi:door-closed-lock","tags":["home automation","lock"]},{"name":"mdi:door-open","tags":["home automation"]},{"name":"mdi:door-sliding-lock","tags":["home automation","lock","patio door lock","french door lock"]},{"name":"mdi:door-sliding-open","tags":["home automation","patio door open","french door open"]},{"name":"mdi:doorbell","tags":["home automation"]},{"name":"mdi:doorbell-video","tags":["home automation"]},{"name":"mdi:dots-circle","tags":["perimeter"]},{"name":"mdi:dots-grid","tags":[]},{"name":"mdi:dots-hexagon","tags":[]},{"name":"mdi:dots-horizontal-circle-outline","tags":["ellipsis horizontal circle outline","more circle outline","menu"]},{"name":"mdi:dots-square","tags":["perimeter"]},{"name":"mdi:dots-triangle","tags":[]},{"name":"mdi:dots-vertical-circle","tags":["ellipsis vertical circle","menu"]},{"name":"mdi:dots-vertical-circle-outline","tags":["ellipsis vertical circle outline","menu"]},{"name":"mdi:download-box","tags":[]},{"name":"mdi:download-box-outline","tags":[]},{"name":"mdi:download-circle","tags":[]},{"name":"mdi:download-circle-outline","tags":[]},{"name":"mdi:download-lock","tags":["lock"]},{"name":"mdi:download-lock-outline","tags":["lock"]},{"name":"mdi:download-multiple","tags":["downloads"]},{"name":"mdi:download-network","tags":[]},{"name":"mdi:download-network-outline","tags":[]},{"name":"mdi:download-off","tags":[]},{"name":"mdi:download-off-outline","tags":[]},{"name":"mdi:drag","tags":[]},{"name":"mdi:drag-horizontal","tags":[]},{"name":"mdi:drag-variant","tags":[]},{"name":"mdi:drag-vertical","tags":[]},{"name":"mdi:drag-vertical-variant","tags":[]},{"name":"mdi:drama-masks","tags":["comedy","tragedy","theatre"]},{"name":"mdi:draw","tags":["drawing / art","form","sign","signature"]},{"name":"mdi:draw-pen","tags":["form","drawing / art","sign","signature"]},{"name":"mdi:drawing","tags":["drawing / art","shape"]},{"name":"mdi:dresser","tags":["home automation"]},{"name":"mdi:dresser-outline","tags":["home automation"]},{"name":"mdi:drone","tags":["transportation + flying"]},{"name":"mdi:duck","tags":["animal"]},{"name":"mdi:dump-truck","tags":["transportation + road","hardware / tools","tipper lorry"]},{"name":"mdi:ear-hearing-loop","tags":["medical / hospital","audio induction loop","telecoil"]},{"name":"mdi:ear-hearing-off","tags":["medical / hospital","hearing impaired"]},{"name":"mdi:earbuds","tags":["audio","music","headphones"]},{"name":"mdi:earbuds-off","tags":["audio","music","headphones off"]},{"name":"mdi:earbuds-off-outline","tags":["audio","music","headphones off outline"]},{"name":"mdi:earbuds-outline","tags":["audio","music","headphones outline"]},{"name":"mdi:earth-arrow-right","tags":["navigation","globe arrow right","world arrow right","planet arrow right"]},{"name":"mdi:earth-box","tags":["navigation","globe box","world box","planet box"]},{"name":"mdi:earth-box-minus","tags":["navigation","globe box minus","world box minus","planet box minus"]},{"name":"mdi:earth-box-off","tags":["navigation","globe box off","world box off","planet box off"]},{"name":"mdi:earth-box-plus","tags":["navigation","globe box plus","world box plus","planet box plus"]},{"name":"mdi:earth-box-remove","tags":["navigation","globe box remove","world box remove","planet box remove"]},{"name":"mdi:earth-minus","tags":["navigation","globe minus","world minus","planet minus"]},{"name":"mdi:earth-off","tags":["geographic information system","navigation","globe off","world off","planet off"]},{"name":"mdi:earth-plus","tags":["navigation","globe plus","world plus","planet plus"]},{"name":"mdi:earth-remove","tags":["navigation","globe remove","world remove","planet remove"]},{"name":"mdi:egg","tags":["food / drink","agriculture"]},{"name":"mdi:egg-easter","tags":["holiday"]},{"name":"mdi:egg-fried","tags":["food / drink"]},{"name":"mdi:egg-off","tags":["food / drink","agriculture"]},{"name":"mdi:egg-off-outline","tags":["food / drink","agriculture"]},{"name":"mdi:egg-outline","tags":["food / drink","agriculture"]},{"name":"mdi:eiffel-tower","tags":["places","paris","france"]},{"name":"mdi:eight-track","tags":["music","8 track"]},{"name":"mdi:eject-circle","tags":[]},{"name":"mdi:eject-circle-outline","tags":[]},{"name":"mdi:electric-switch","tags":[]},{"name":"mdi:electric-switch-closed","tags":[]},{"name":"mdi:elephant","tags":["animal"]},{"name":"mdi:elevation-decline","tags":[]},{"name":"mdi:elevation-rise","tags":[]},{"name":"mdi:elevator","tags":["transportation + other"]},{"name":"mdi:elevator-down","tags":["transportation + other"]},{"name":"mdi:elevator-passenger-off","tags":["transportation + other"]},{"name":"mdi:elevator-passenger-off-outline","tags":["transportation + other"]},{"name":"mdi:elevator-up","tags":["transportation + other"]},{"name":"mdi:ellipse","tags":["shape"]},{"name":"mdi:ellipse-outline","tags":["shape"]},{"name":"mdi:email-alert","tags":["alert / error","email warning","envelope alert","envelope warning"]},{"name":"mdi:email-alert-outline","tags":["alert / error"]},{"name":"mdi:email-arrow-left","tags":["email receive"]},{"name":"mdi:email-arrow-left-outline","tags":["email receive outline"]},{"name":"mdi:email-arrow-right","tags":["email send"]},{"name":"mdi:email-arrow-right-outline","tags":["email arrow right outline"]},{"name":"mdi:email-box","tags":["envelope box"]},{"name":"mdi:email-check","tags":["email tick"]},{"name":"mdi:email-check-outline","tags":["email tick outline"]},{"name":"mdi:email-edit","tags":["edit / modify"]},{"name":"mdi:email-edit-outline","tags":["edit / modify"]},{"name":"mdi:email-fast","tags":["envelope fast","email quick","email sent","email send"]},{"name":"mdi:email-fast-outline","tags":["email send outline","email sent outline","envelope fast outline","email quick outline"]},{"name":"mdi:email-heart-outline","tags":["love letter","envelope heart outline","greeting card"]},{"name":"mdi:email-lock","tags":["lock","envelope secure","email secure","envelope lock"]},{"name":"mdi:email-lock-outline","tags":["lock","email secure outline"]},{"name":"mdi:email-minus","tags":[]},{"name":"mdi:email-minus-outline","tags":[]},{"name":"mdi:email-multiple","tags":[]},{"name":"mdi:email-multiple-outline","tags":[]},{"name":"mdi:email-newsletter","tags":[]},{"name":"mdi:email-off","tags":[]},{"name":"mdi:email-off-outline","tags":[]},{"name":"mdi:email-open","tags":["drafts","envelope open"]},{"name":"mdi:email-open-heart-outline","tags":["love letter open","greeting card open","envelope open heart outline"]},{"name":"mdi:email-open-multiple","tags":[]},{"name":"mdi:email-open-multiple-outline","tags":[]},{"name":"mdi:email-open-outline","tags":["envelope open outline"]},{"name":"mdi:email-plus","tags":["email add","envelope add","envelope plus"]},{"name":"mdi:email-plus-outline","tags":["email add outline","envelope add outline","envelope plus outline"]},{"name":"mdi:email-remove","tags":[]},{"name":"mdi:email-remove-outline","tags":[]},{"name":"mdi:email-seal","tags":["email certified","mail certified","mail seal","email verified","mail verified"]},{"name":"mdi:email-seal-outline","tags":["email verified outline","email certified outline","mail verified outline","mail certified outline","mail seal outline"]},{"name":"mdi:email-search","tags":[]},{"name":"mdi:email-search-outline","tags":[]},{"name":"mdi:email-sync","tags":["email refresh","email resend"]},{"name":"mdi:email-sync-outline","tags":["email refresh outline","email resend outline"]},{"name":"mdi:email-variant","tags":["envelope variant"]},{"name":"mdi:emoticon-angry","tags":["emoji","smiley angry","face angry","emoji angry"]},{"name":"mdi:emoticon-angry-outline","tags":["emoji","smiley angry outline","face angry outline","emoji angry outline"]},{"name":"mdi:emoticon-confused","tags":["emoji","face confused","emoji confused"]},{"name":"mdi:emoticon-confused-outline","tags":["emoji","face confused outline","emoji confused outline"]},{"name":"mdi:emoticon-cool","tags":["emoji","smiley cool","face cool","face sunglasses","emoji cool"]},{"name":"mdi:emoticon-cool-outline","tags":["emoji","smiley cool outline","face cool outline","face sunglasses outline","emoji cool outline"]},{"name":"mdi:emoticon-cry","tags":["emoji","smiley cry","face cry","emoji cry"]},{"name":"mdi:emoticon-cry-outline","tags":["emoji","smiley cry outline","face cry outline","emoji cry outline"]},{"name":"mdi:emoticon-devil","tags":["emoji","smiley devil","face devil","emoji devil"]},{"name":"mdi:emoticon-devil-outline","tags":["emoji","smiley devil outline","face devil outline","emoji devil outline"]},{"name":"mdi:emoticon-frown","tags":["emoji","face frown","emoji frown"]},{"name":"mdi:emoticon-happy","tags":["emoji","smiley happy","face happy","emoji happy"]},{"name":"mdi:emoticon-happy-outline","tags":["emoji","smiley happy outline","face happy outline","emoji happy outline"]},{"name":"mdi:emoticon-kiss","tags":["emoji","smiley kiss","face kiss","emoji kiss"]},{"name":"mdi:emoticon-kiss-outline","tags":["emoji","smiley kiss outline","face kiss outline","emoji kiss outline"]},{"name":"mdi:emoticon-lol","tags":["emoji","face lol","emoji lol"]},{"name":"mdi:emoticon-lol-outline","tags":["emoji","face lol outline","emoji lol outline"]},{"name":"mdi:emoticon-neutral","tags":["emoji","smiley neutral","face neutral","emoji neutral"]},{"name":"mdi:emoticon-neutral-outline","tags":["emoji","smiley neutral outline","face neutral outline","emoji neutral outline"]},{"name":"mdi:emoticon-poop","tags":["emoji","smiley poop","face poop","emoji poop"]},{"name":"mdi:emoticon-poop-outline","tags":["emoji","face poop outline","emoji poop outline"]},{"name":"mdi:emoticon-sad","tags":["emoji","smiley sad","face sad","emoji sad"]},{"name":"mdi:emoticon-sad-outline","tags":["emoji","smiley sad outline","face sad outline","emoji sad outline"]},{"name":"mdi:emoticon-tongue","tags":["emoji","smiley tongue","face tongue","emoji tongue"]},{"name":"mdi:emoticon-tongue-outline","tags":["emoji","smiley tongue outline","face tongue outline","emoji tongue outline"]},{"name":"mdi:emoticon-wink","tags":["emoji","smiley wink","face wink","emoji wink"]},{"name":"mdi:emoticon-wink-outline","tags":["emoji","smiley wink outline","face wink outline","emoji wink outline"]},{"name":"mdi:engine","tags":["automotive","motor"]},{"name":"mdi:engine-off","tags":["automotive","motor off"]},{"name":"mdi:engine-off-outline","tags":["automotive","motor off outline"]},{"name":"mdi:engine-outline","tags":["automotive","motor outline"]},{"name":"mdi:epsilon","tags":["alpha / numeric"]},{"name":"mdi:equal","tags":["math"]},{"name":"mdi:equal-box","tags":["math"]},{"name":"mdi:equalizer-outline","tags":["audio"]},{"name":"mdi:eraser","tags":[]},{"name":"mdi:escalator","tags":["transportation + other"]},{"name":"mdi:escalator-box","tags":[]},{"name":"mdi:escalator-down","tags":["transportation + other"]},{"name":"mdi:escalator-up","tags":["transportation + other"]},{"name":"mdi:et","tags":[]},{"name":"mdi:ethernet","tags":[]},{"name":"mdi:ethernet-cable","tags":[]},{"name":"mdi:ethernet-cable-off","tags":[]},{"name":"mdi:ev-plug-ccs1","tags":["automotive","ev plug ccs combo 1","ev charger ccs1"]},{"name":"mdi:ev-plug-ccs2","tags":["automotive","ev plug ccs combo 2","ev charger ccs2"]},{"name":"mdi:ev-plug-chademo","tags":["automotive","ev charger chademo"]},{"name":"mdi:ev-plug-tesla","tags":["automotive","ev charger tesla"]},{"name":"mdi:ev-plug-type1","tags":["automotive","ev plug j1772","ev charger type1"]},{"name":"mdi:ev-plug-type2","tags":["automotive","ev plug mennekes","ev charger type2"]},{"name":"mdi:excavator","tags":["hardware / tools"]},{"name":"mdi:exclamation","tags":["math","factorial"]},{"name":"mdi:exclamation-thick","tags":["exclamation bold"]},{"name":"mdi:exit-run","tags":["home automation","emergency exit"]},{"name":"mdi:expand-all","tags":["animation plus"]},{"name":"mdi:expand-all-outline","tags":["animation plus outline"]},{"name":"mdi:expansion-card","tags":["gaming / rpg","gpu","graphics processing unit","nic","network interface card"]},{"name":"mdi:expansion-card-variant","tags":["graphics processing unit","gpu","network interface card","nice"]},{"name":"mdi:exponent","tags":["math","power"]},{"name":"mdi:exponent-box","tags":["math","power box"]},{"name":"mdi:export","tags":["output"]},{"name":"mdi:eye-arrow-left","tags":["view arrow left"]},{"name":"mdi:eye-arrow-left-outline","tags":["view arrow left outline"]},{"name":"mdi:eye-arrow-right","tags":["view arrow right"]},{"name":"mdi:eye-arrow-right-outline","tags":["view arrow right outline"]},{"name":"mdi:eye-check","tags":["eye tick"]},{"name":"mdi:eye-check-outline","tags":["eye tick outline"]},{"name":"mdi:eye-circle","tags":[]},{"name":"mdi:eye-circle-outline","tags":[]},{"name":"mdi:eye-lock","tags":[]},{"name":"mdi:eye-lock-open","tags":[]},{"name":"mdi:eye-lock-open-outline","tags":[]},{"name":"mdi:eye-lock-outline","tags":[]},{"name":"mdi:eye-minus","tags":[]},{"name":"mdi:eye-minus-outline","tags":[]},{"name":"mdi:eye-off-outline","tags":["hide outline","visibility off outline"]},{"name":"mdi:eye-outline","tags":["show outline","visibility outline"]},{"name":"mdi:eye-plus","tags":["eye add"]},{"name":"mdi:eye-plus-outline","tags":["eye add outline"]},{"name":"mdi:eye-refresh","tags":["view refresh"]},{"name":"mdi:eye-refresh-outline","tags":["view refresh outline"]},{"name":"mdi:eye-remove","tags":[]},{"name":"mdi:eye-remove-outline","tags":[]},{"name":"mdi:eye-settings","tags":["settings"]},{"name":"mdi:eye-settings-outline","tags":["settings"]},{"name":"mdi:eyedropper","tags":["color","drawing / art","science","pipette"]},{"name":"mdi:eyedropper-minus","tags":["science"]},{"name":"mdi:eyedropper-off","tags":["science"]},{"name":"mdi:eyedropper-plus","tags":["science"]},{"name":"mdi:eyedropper-remove","tags":["science"]},{"name":"mdi:face-agent","tags":["customer service","support","emoji agent","emoticon agent"]},{"name":"mdi:face-man-shimmer-outline","tags":["people / family","photography","health / beauty","account / user","face retouching natural outline","face male shimmer outline","emoji man shimmer outline","emoticon man shimmer outline"]},{"name":"mdi:face-mask","tags":["medical / hospital","clothing"]},{"name":"mdi:face-mask-outline","tags":["medical / hospital","clothing"]},{"name":"mdi:face-recognition","tags":["photography","facial recognition","scan"]},{"name":"mdi:face-woman","tags":["people / family","face female","emoji woman","emoticon woman"]},{"name":"mdi:face-woman-outline","tags":["people / family","face female outline","emoji woman outline","emoticon woman outline"]},{"name":"mdi:face-woman-profile","tags":["people / family","face female profile","emoji woman profile","emoticon woman profile"]},{"name":"mdi:face-woman-shimmer","tags":["people / family","photography","health / beauty","account / user","face retouching natural woman","face female shimmer","emoji woman shimmer","emoticon woman shimmer"]},{"name":"mdi:face-woman-shimmer-outline","tags":["people / family","photography","health / beauty","account / user","face retouching natural woman outline","face female shimmer outline","emoji woman shimmer outline","emoticon woman shimmer outline"]},{"name":"mdi:factory","tags":["places","industrial"]},{"name":"mdi:family-tree","tags":["people / family"]},{"name":"mdi:fan","tags":["home automation","automotive"]},{"name":"mdi:fan-alert","tags":["home automation","alert / error"]},{"name":"mdi:fan-auto","tags":[]},{"name":"mdi:fan-chevron-down","tags":["home automation","fan speed down"]},{"name":"mdi:fan-chevron-up","tags":["home automation","fan speed up"]},{"name":"mdi:fan-clock","tags":["home automation","date / time","fan clock","fan schedule","fan timer"]},{"name":"mdi:fan-minus","tags":["home automation"]},{"name":"mdi:fan-off","tags":["home automation","automotive"]},{"name":"mdi:fan-plus","tags":["home automation"]},{"name":"mdi:fan-remove","tags":["home automation"]},{"name":"mdi:fan-speed-1","tags":["home automation","fan speed low"]},{"name":"mdi:fan-speed-2","tags":["home automation","fan speed medium"]},{"name":"mdi:fan-speed-3","tags":["home automation","fan speed high"]},{"name":"mdi:fast-forward-10","tags":[]},{"name":"mdi:fast-forward-15","tags":[]},{"name":"mdi:fast-forward-30","tags":[]},{"name":"mdi:fast-forward-45","tags":[]},{"name":"mdi:fast-forward-5","tags":[]},{"name":"mdi:fast-forward-60","tags":[]},{"name":"mdi:faucet","tags":["home automation","kitchen tap","bathroom tap","sink"]},{"name":"mdi:faucet-variant","tags":["home automation","bathroom tap","kitchen tap","sink"]},{"name":"mdi:feather","tags":["nature","quill"]},{"name":"mdi:feature-search","tags":["box","box search"]},{"name":"mdi:feature-search-outline","tags":["box","box outline","box search outline"]},{"name":"mdi:fence","tags":["home automation","agriculture","railway","train track"]},{"name":"mdi:fence-electric","tags":["home automation","agriculture","railway electric","train track electric"]},{"name":"mdi:file-account","tags":["account / user","files / folders","file user","resume"]},{"name":"mdi:file-account-outline","tags":["files / folders","account / user"]},{"name":"mdi:file-alert","tags":["files / folders","alert / error","file warning"]},{"name":"mdi:file-alert-outline","tags":["files / folders","alert / error","file warning outline"]},{"name":"mdi:file-arrow-left-right","tags":["files / folders","file exchange","file transfer","file swap"]},{"name":"mdi:file-arrow-left-right-outline","tags":["files / folders","file exchange outline","file swap outline","file transfer outline"]},{"name":"mdi:file-arrow-up-down","tags":["files / folders","file exchange","file swap","file transfer","file upload download"]},{"name":"mdi:file-arrow-up-down-outline","tags":["files / folders","file exchange outline","file swap outline","file transfer outline","file upload download outline"]},{"name":"mdi:file-cabinet","tags":["files / folders","filing cabinet"]},{"name":"mdi:file-cad","tags":["files / folders"]},{"name":"mdi:file-cad-box","tags":["files / folders"]},{"name":"mdi:file-cancel","tags":["files / folders","ban","forbid"]},{"name":"mdi:file-cancel-outline","tags":["files / folders","ban","forbid"]},{"name":"mdi:file-certificate","tags":["files / folders"]},{"name":"mdi:file-certificate-outline","tags":["files / folders"]},{"name":"mdi:file-chart","tags":["files / folders","file report","file graph"]},{"name":"mdi:file-chart-check","tags":["files / folders"]},{"name":"mdi:file-chart-check-outline","tags":["files / folders"]},{"name":"mdi:file-chart-outline","tags":["files / folders","file graph outline","file report outline"]},{"name":"mdi:file-check","tags":["files / folders","file tick"]},{"name":"mdi:file-check-outline","tags":["files / folders"]},{"name":"mdi:file-clock","tags":["files / folders","date / time"]},{"name":"mdi:file-clock-outline","tags":["files / folders","date / time"]},{"name":"mdi:file-cloud","tags":["cloud","files / folders"]},{"name":"mdi:file-cloud-outline","tags":["files / folders","cloud"]},{"name":"mdi:file-code","tags":["files / folders","developer / languages"]},{"name":"mdi:file-code-outline","tags":["files / folders","developer / languages"]},{"name":"mdi:file-cog","tags":["settings","files / folders","file settings cog"]},{"name":"mdi:file-cog-outline","tags":["settings","files / folders","file settings cog outline"]},{"name":"mdi:file-compare","tags":["files / folders"]},{"name":"mdi:file-delimited","tags":["files / folders","file csv"]},{"name":"mdi:file-delimited-outline","tags":["files / folders","file csv outline"]},{"name":"mdi:file-document","tags":["files / folders","file text"]},{"name":"mdi:file-document-alert","tags":["files / folders","alert / error","file document error","file text alert","file text error"]},{"name":"mdi:file-document-alert-outline","tags":["files / folders","alert / error","file document error outline","file text error outline","file text alert outline"]},{"name":"mdi:file-document-arrow-right","tags":["files / folders","file document move","file text move","file text arrow right"]},{"name":"mdi:file-document-arrow-right-outline","tags":["files / folders","file document move outline","file text move outline","file text arrow right outline"]},{"name":"mdi:file-document-check","tags":["files / folders","file document tick","file text tick","file text check"]},{"name":"mdi:file-document-check-outline","tags":["files / folders","file document tick outline","file text tick outline","file text check outline"]},{"name":"mdi:file-document-edit","tags":["edit / modify","files / folders","contract","file text edit"]},{"name":"mdi:file-document-edit-outline","tags":["edit / modify","files / folders","contract outline","file text edit outline"]},{"name":"mdi:file-document-minus","tags":["files / folders","file text minus"]},{"name":"mdi:file-document-minus-outline","tags":["files / folders","file text minus outline"]},{"name":"mdi:file-document-multiple","tags":["files / folders","file text multiple"]},{"name":"mdi:file-document-multiple-outline","tags":["files / folders","file text multiple outline"]},{"name":"mdi:file-document-plus","tags":["files / folders","file document add","file text add","file text plus"]},{"name":"mdi:file-document-plus-outline","tags":["files / folders","file document add outline","file text plus outline","file text add outline"]},{"name":"mdi:file-document-refresh","tags":["files / folders"]},{"name":"mdi:file-document-refresh-outline","tags":["files / folders"]},{"name":"mdi:file-document-remove","tags":["files / folders","file document delete","file text remove","file text delete"]},{"name":"mdi:file-document-remove-outline","tags":["files / folders","file document delete outline","file text remove outline","file text delete outline"]},{"name":"mdi:file-download","tags":["files / folders"]},{"name":"mdi:file-download-outline","tags":["files / folders"]},{"name":"mdi:file-edit","tags":["edit / modify","files / folders"]},{"name":"mdi:file-edit-outline","tags":["edit / modify","files / folders"]},{"name":"mdi:file-excel","tags":["files / folders"]},{"name":"mdi:file-excel-box-outline","tags":["files / folders"]},{"name":"mdi:file-excel-outline","tags":["files / folders"]},{"name":"mdi:file-export","tags":["files / folders"]},{"name":"mdi:file-export-outline","tags":["files / folders"]},{"name":"mdi:file-eye","tags":["files / folders"]},{"name":"mdi:file-eye-outline","tags":["files / folders"]},{"name":"mdi:file-gif-box","tags":["files / folders"]},{"name":"mdi:file-hidden","tags":["files / folders"]},{"name":"mdi:file-image","tags":["files / folders"]},{"name":"mdi:file-image-marker","tags":["files / folders","navigation","file image location"]},{"name":"mdi:file-image-marker-outline","tags":["files / folders","navigation","file image location outline"]},{"name":"mdi:file-image-minus","tags":["files / folders"]},{"name":"mdi:file-image-minus-outline","tags":["files / folders"]},{"name":"mdi:file-image-outline","tags":["files / folders"]},{"name":"mdi:file-image-plus","tags":["files / folders","file image add"]},{"name":"mdi:file-image-plus-outline","tags":["files / folders","file image add outline"]},{"name":"mdi:file-image-remove","tags":["files / folders"]},{"name":"mdi:file-image-remove-outline","tags":["files / folders"]},{"name":"mdi:file-import","tags":["files / folders"]},{"name":"mdi:file-import-outline","tags":["files / folders"]},{"name":"mdi:file-jpg-box","tags":["files / folders","file jpeg box","image jpg box","image jpeg box"]},{"name":"mdi:file-key","tags":["files / folders"]},{"name":"mdi:file-key-outline","tags":["files / folders"]},{"name":"mdi:file-link","tags":["files / folders"]},{"name":"mdi:file-link-outline","tags":["files / folders"]},{"name":"mdi:file-lock","tags":["lock","files / folders"]},{"name":"mdi:file-lock-open","tags":["lock","files / folders"]},{"name":"mdi:file-lock-open-outline","tags":["lock","files / folders"]},{"name":"mdi:file-lock-outline","tags":["files / folders","lock"]},{"name":"mdi:file-marker","tags":["files / folders","navigation","file location"]},{"name":"mdi:file-marker-outline","tags":["files / folders","navigation","file location outline"]},{"name":"mdi:file-minus","tags":["files / folders"]},{"name":"mdi:file-minus-outline","tags":["files / folders"]},{"name":"mdi:file-move","tags":["files / folders"]},{"name":"mdi:file-move-outline","tags":["files / folders"]},{"name":"mdi:file-multiple","tags":["files / folders","files"]},{"name":"mdi:file-multiple-outline","tags":["files / folders"]},{"name":"mdi:file-music","tags":["files / folders","music"]},{"name":"mdi:file-music-outline","tags":["files / folders","music"]},{"name":"mdi:file-pdf-box","tags":["files / folders","file acrobat box","adobe acrobat"]},{"name":"mdi:file-percent","tags":["files / folders"]},{"name":"mdi:file-percent-outline","tags":["files / folders"]},{"name":"mdi:file-phone","tags":["files / folders","cellphone / phone"]},{"name":"mdi:file-phone-outline","tags":["files / folders","cellphone / phone"]},{"name":"mdi:file-plus","tags":["files / folders","note add"]},{"name":"mdi:file-plus-outline","tags":["files / folders"]},{"name":"mdi:file-png-box","tags":["files / folders"]},{"name":"mdi:file-powerpoint","tags":["files / folders"]},{"name":"mdi:file-powerpoint-box-outline","tags":["files / folders"]},{"name":"mdi:file-powerpoint-outline","tags":["files / folders"]},{"name":"mdi:file-question","tags":["files / folders"]},{"name":"mdi:file-question-outline","tags":["files / folders"]},{"name":"mdi:file-refresh","tags":["files / folders"]},{"name":"mdi:file-refresh-outline","tags":["files / folders"]},{"name":"mdi:file-remove","tags":["files / folders"]},{"name":"mdi:file-remove-outline","tags":["files / folders"]},{"name":"mdi:file-replace","tags":["files / folders"]},{"name":"mdi:file-replace-outline","tags":["files / folders"]},{"name":"mdi:file-restore-outline","tags":["files / folders"]},{"name":"mdi:file-rotate-left","tags":["files / folders","file rotate counter clockwise","file rotate ccw"]},{"name":"mdi:file-rotate-left-outline","tags":["files / folders","file rotate counter clockwise outline","file rotate ccw outline"]},{"name":"mdi:file-rotate-right","tags":["files / folders","file rotate clockwise"]},{"name":"mdi:file-rotate-right-outline","tags":["files / folders","file rotate clockwise"]},{"name":"mdi:file-search","tags":["files / folders"]},{"name":"mdi:file-search-outline","tags":["files / folders"]},{"name":"mdi:file-send","tags":["files / folders","file move"]},{"name":"mdi:file-send-outline","tags":["files / folders"]},{"name":"mdi:file-settings","tags":["settings","files / folders"]},{"name":"mdi:file-settings-outline","tags":["settings","files / folders"]},{"name":"mdi:file-sign","tags":["banking","files / folders","contract sign","document sign"]},{"name":"mdi:file-star","tags":["files / folders","file favorite"]},{"name":"mdi:file-star-four-points","tags":["files / folders","file auto"]},{"name":"mdi:file-star-four-points-outline","tags":["files / folders","file auto outline"]},{"name":"mdi:file-star-outline","tags":["files / folders","file favorite outline"]},{"name":"mdi:file-swap","tags":["files / folders","file transfer"]},{"name":"mdi:file-swap-outline","tags":["files / folders","file transfer outline"]},{"name":"mdi:file-sync","tags":["files / folders"]},{"name":"mdi:file-sync-outline","tags":["files / folders"]},{"name":"mdi:file-table","tags":["files / folders"]},{"name":"mdi:file-table-box","tags":["files / folders"]},{"name":"mdi:file-table-box-multiple","tags":["files / folders"]},{"name":"mdi:file-table-box-multiple-outline","tags":["files / folders"]},{"name":"mdi:file-table-box-outline","tags":["files / folders"]},{"name":"mdi:file-table-outline","tags":["files / folders"]},{"name":"mdi:file-tree","tags":["files / folders","subtasks"]},{"name":"mdi:file-tree-outline","tags":["files / folders"]},{"name":"mdi:file-undo","tags":["files / folders","file revert","file discard"]},{"name":"mdi:file-undo-outline","tags":["files / folders"]},{"name":"mdi:file-upload","tags":["files / folders"]},{"name":"mdi:file-upload-outline","tags":["files / folders"]},{"name":"mdi:file-video","tags":["video / movie","files / folders"]},{"name":"mdi:file-video-outline","tags":["files / folders"]},{"name":"mdi:file-word","tags":["files / folders"]},{"name":"mdi:file-word-box-outline","tags":["files / folders"]},{"name":"mdi:file-word-outline","tags":["files / folders"]},{"name":"mdi:file-xml-box","tags":["files / folders"]},{"name":"mdi:filmstrip-box","tags":[]},{"name":"mdi:filmstrip-off","tags":["video / movie"]},{"name":"mdi:filter","tags":["funnel"]},{"name":"mdi:filter-check","tags":["funnel check"]},{"name":"mdi:filter-check-outline","tags":["funnel check outline"]},{"name":"mdi:filter-cog","tags":["settings","funnel settings","filter settings","funnel cog","filter gear","funnel gear"]},{"name":"mdi:filter-cog-outline","tags":["settings","filter settings outline","filter gear outline","funnel cog outline","funnel settings outline","funnel gear outline"]},{"name":"mdi:filter-menu","tags":[]},{"name":"mdi:filter-menu-outline","tags":[]},{"name":"mdi:filter-minus","tags":["funnel minus"]},{"name":"mdi:filter-minus-outline","tags":["funnel minus outline"]},{"name":"mdi:filter-multiple","tags":["funnel multiple"]},{"name":"mdi:filter-multiple-outline","tags":["funnel multiple outline"]},{"name":"mdi:filter-off","tags":[]},{"name":"mdi:filter-off-outline","tags":[]},{"name":"mdi:filter-outline","tags":["funnel outline"]},{"name":"mdi:filter-plus","tags":["funnel plus"]},{"name":"mdi:filter-plus-outline","tags":["funnel plus outline"]},{"name":"mdi:filter-remove","tags":["funnel remove"]},{"name":"mdi:filter-remove-outline","tags":["funnel remove outline"]},{"name":"mdi:filter-settings","tags":["settings","funnel settings"]},{"name":"mdi:filter-settings-outline","tags":["settings","funnel settings outline"]},{"name":"mdi:filter-variant-minus","tags":[]},{"name":"mdi:filter-variant-plus","tags":[]},{"name":"mdi:filter-variant-remove","tags":[]},{"name":"mdi:fingerprint-off","tags":[]},{"name":"mdi:fire-alert","tags":["alert / error","home automation","flame alert"]},{"name":"mdi:fire-circle","tags":["home automation","flame circle","hot circle","gas circle","natural gas circle"]},{"name":"mdi:fire-extinguisher","tags":["hardware / tools","home automation"]},{"name":"mdi:fire-hydrant","tags":[]},{"name":"mdi:fire-hydrant-alert","tags":["alert / error"]},{"name":"mdi:fire-hydrant-off","tags":[]},{"name":"mdi:fire-off","tags":["home automation","flame off"]},{"name":"mdi:fire-truck","tags":["transportation + road","fire engine"]},{"name":"mdi:fireplace","tags":["home automation"]},{"name":"mdi:fireplace-off","tags":["home automation"]},{"name":"mdi:firewire","tags":[]},{"name":"mdi:firework","tags":["holiday","bottle rocket"]},{"name":"mdi:firework-off","tags":[]},{"name":"mdi:fish","tags":["animal","food / drink"]},{"name":"mdi:fish-off","tags":["food / drink"]},{"name":"mdi:fishbowl","tags":["animal","aquarium"]},{"name":"mdi:fishbowl-outline","tags":["animal","aquarium outline"]},{"name":"mdi:fit-to-page","tags":["text / content / format","arrow"]},{"name":"mdi:fit-to-page-outline","tags":["text / content / format","arrow"]},{"name":"mdi:flag-checkered","tags":["sport","goal"]},{"name":"mdi:flag-minus","tags":[]},{"name":"mdi:flag-minus-outline","tags":[]},{"name":"mdi:flag-off","tags":[]},{"name":"mdi:flag-off-outline","tags":[]},{"name":"mdi:flag-plus","tags":["flag add"]},{"name":"mdi:flag-plus-outline","tags":[]},{"name":"mdi:flag-remove","tags":[]},{"name":"mdi:flag-remove-outline","tags":[]},{"name":"mdi:flag-triangle","tags":["milestone"]},{"name":"mdi:flag-variant","tags":[]},{"name":"mdi:flag-variant-minus","tags":[]},{"name":"mdi:flag-variant-minus-outline","tags":[]},{"name":"mdi:flag-variant-off","tags":[]},{"name":"mdi:flag-variant-off-outline","tags":[]},{"name":"mdi:flag-variant-outline","tags":[]},{"name":"mdi:flag-variant-plus","tags":[]},{"name":"mdi:flag-variant-plus-outline","tags":[]},{"name":"mdi:flag-variant-remove","tags":[]},{"name":"mdi:flag-variant-remove-outline","tags":[]},{"name":"mdi:flash-alert","tags":["weather","alert / error","lightning alert","storm advisory"]},{"name":"mdi:flash-alert-outline","tags":["weather","alert / error","lightning alert outline","storm advisory outline"]},{"name":"mdi:flash-off-outline","tags":[]},{"name":"mdi:flash-outline","tags":["weather","lightning bolt outline"]},{"name":"mdi:flash-red-eye","tags":[]},{"name":"mdi:flash-triangle","tags":["home automation","high voltage"]},{"name":"mdi:flash-triangle-outline","tags":["home automation","high voltage outline"]},{"name":"mdi:flashlight","tags":["torch"]},{"name":"mdi:flashlight-off","tags":["torch off"]},{"name":"mdi:flask","tags":["science","gaming / rpg"]},{"name":"mdi:flask-empty","tags":["science","gaming / rpg"]},{"name":"mdi:flask-empty-minus","tags":["science"]},{"name":"mdi:flask-empty-minus-outline","tags":["science"]},{"name":"mdi:flask-empty-off","tags":[]},{"name":"mdi:flask-empty-off-outline","tags":[]},{"name":"mdi:flask-empty-outline","tags":["science","gaming / rpg"]},{"name":"mdi:flask-empty-plus","tags":["science"]},{"name":"mdi:flask-empty-plus-outline","tags":["science"]},{"name":"mdi:flask-empty-remove","tags":["science"]},{"name":"mdi:flask-empty-remove-outline","tags":["science"]},{"name":"mdi:flask-minus","tags":["science"]},{"name":"mdi:flask-minus-outline","tags":["science"]},{"name":"mdi:flask-off","tags":[]},{"name":"mdi:flask-off-outline","tags":[]},{"name":"mdi:flask-outline","tags":["science","gaming / rpg"]},{"name":"mdi:flask-plus","tags":["science"]},{"name":"mdi:flask-plus-outline","tags":["science"]},{"name":"mdi:flask-remove","tags":["science"]},{"name":"mdi:flask-remove-outline","tags":["science"]},{"name":"mdi:flask-round-bottom","tags":["science"]},{"name":"mdi:flask-round-bottom-empty","tags":["science"]},{"name":"mdi:flask-round-bottom-empty-outline","tags":["science"]},{"name":"mdi:flask-round-bottom-outline","tags":["science"]},{"name":"mdi:fleur-de-lis","tags":[]},{"name":"mdi:floor-lamp","tags":["home automation","floor light"]},{"name":"mdi:floor-lamp-dual","tags":["home automation","floor light dual"]},{"name":"mdi:floor-lamp-dual-outline","tags":["home automation","floor light dual outline"]},{"name":"mdi:floor-lamp-outline","tags":["home automation","floor light outline"]},{"name":"mdi:floor-lamp-torchiere","tags":["home automation","floor light torchiere"]},{"name":"mdi:floor-lamp-torchiere-outline","tags":["home automation"]},{"name":"mdi:floor-lamp-torchiere-variant","tags":["home automation","floor light torchiere variant"]},{"name":"mdi:floor-lamp-torchiere-variant-outline","tags":["home automation","floor light torchiere variant outline"]},{"name":"mdi:floor-plan","tags":["home automation"]},{"name":"mdi:floppy","tags":[]},{"name":"mdi:floppy-variant","tags":[]},{"name":"mdi:flower-pollen","tags":["nature","agriculture","allergy"]},{"name":"mdi:flower-pollen-outline","tags":["nature","agriculture","allergy outline"]},{"name":"mdi:flower-poppy","tags":["nature","agriculture","plant"]},{"name":"mdi:flower-tulip","tags":["nature","agriculture","plant"]},{"name":"mdi:flower-tulip-outline","tags":["nature","agriculture","plant"]},{"name":"mdi:focus-auto","tags":["photography"]},{"name":"mdi:focus-field","tags":["photography"]},{"name":"mdi:focus-field-horizontal","tags":["photography"]},{"name":"mdi:focus-field-vertical","tags":["photography"]},{"name":"mdi:folder-alert","tags":["files / folders","alert / error","folder warning"]},{"name":"mdi:folder-alert-outline","tags":["files / folders","alert / error","folder warning outline"]},{"name":"mdi:folder-arrow-down","tags":["files / folders","folder download"]},{"name":"mdi:folder-arrow-down-outline","tags":["files / folders","folder download outline"]},{"name":"mdi:folder-arrow-left","tags":["files / folders"]},{"name":"mdi:folder-arrow-left-outline","tags":["files / folders"]},{"name":"mdi:folder-arrow-left-right","tags":["files / folders"]},{"name":"mdi:folder-arrow-left-right-outline","tags":["files / folders"]},{"name":"mdi:folder-arrow-right","tags":["files / folders"]},{"name":"mdi:folder-arrow-right-outline","tags":["files / folders"]},{"name":"mdi:folder-arrow-up","tags":["files / folders","folder upload"]},{"name":"mdi:folder-arrow-up-down","tags":["files / folders","folder transfer"]},{"name":"mdi:folder-arrow-up-down-outline","tags":["files / folders","folder transfer outline"]},{"name":"mdi:folder-arrow-up-outline","tags":["files / folders","folder upload outline"]},{"name":"mdi:folder-cancel","tags":["files / folders"]},{"name":"mdi:folder-cancel-outline","tags":["files / folders"]},{"name":"mdi:folder-check","tags":["files / folders"]},{"name":"mdi:folder-check-outline","tags":["files / folders"]},{"name":"mdi:folder-clock","tags":["files / folders","date / time"]},{"name":"mdi:folder-clock-outline","tags":["files / folders","date / time"]},{"name":"mdi:folder-cog","tags":["settings","files / folders","folder cog"]},{"name":"mdi:folder-cog-outline","tags":["settings","files / folders","folder cog outline"]},{"name":"mdi:folder-download","tags":["files / folders"]},{"name":"mdi:folder-download-outline","tags":["files / folders"]},{"name":"mdi:folder-edit","tags":["files / folders","edit / modify"]},{"name":"mdi:folder-edit-outline","tags":["edit / modify","files / folders"]},{"name":"mdi:folder-eye","tags":["files / folders"]},{"name":"mdi:folder-eye-outline","tags":["files / folders"]},{"name":"mdi:folder-file","tags":["files / folders"]},{"name":"mdi:folder-file-outline","tags":["files / folders"]},{"name":"mdi:folder-heart","tags":["files / folders"]},{"name":"mdi:folder-heart-outline","tags":["files / folders"]},{"name":"mdi:folder-hidden","tags":["files / folders"]},{"name":"mdi:folder-home","tags":["files / folders","home automation","folder house"]},{"name":"mdi:folder-home-outline","tags":["files / folders","home automation","folder house outline"]},{"name":"mdi:folder-image","tags":["files / folders"]},{"name":"mdi:folder-information","tags":["files / folders"]},{"name":"mdi:folder-information-outline","tags":["files / folders"]},{"name":"mdi:folder-key","tags":["files / folders"]},{"name":"mdi:folder-key-network","tags":["files / folders"]},{"name":"mdi:folder-key-network-outline","tags":["files / folders"]},{"name":"mdi:folder-key-outline","tags":["files / folders"]},{"name":"mdi:folder-lock","tags":["lock","files / folders"]},{"name":"mdi:folder-lock-open","tags":["lock","files / folders"]},{"name":"mdi:folder-lock-open-outline","tags":["files / folders","lock"]},{"name":"mdi:folder-lock-outline","tags":["files / folders","lock"]},{"name":"mdi:folder-marker","tags":["geographic information system","files / folders","navigation","folder location"]},{"name":"mdi:folder-marker-outline","tags":["geographic information system","files / folders","navigation","folder location outline"]},{"name":"mdi:folder-minus","tags":["files / folders"]},{"name":"mdi:folder-minus-outline","tags":["files / folders"]},{"name":"mdi:folder-move-outline","tags":["files / folders"]},{"name":"mdi:folder-multiple","tags":["files / folders","folders"]},{"name":"mdi:folder-multiple-outline","tags":["files / folders","folders outline"]},{"name":"mdi:folder-multiple-plus","tags":["files / folders"]},{"name":"mdi:folder-multiple-plus-outline","tags":["files / folders"]},{"name":"mdi:folder-music","tags":["files / folders","music"]},{"name":"mdi:folder-music-outline","tags":["files / folders","music"]},{"name":"mdi:folder-network","tags":["files / folders"]},{"name":"mdi:folder-network-outline","tags":["files / folders"]},{"name":"mdi:folder-off","tags":["files / folders"]},{"name":"mdi:folder-off-outline","tags":["files / folders"]},{"name":"mdi:folder-open","tags":["files / folders"]},{"name":"mdi:folder-open-outline","tags":["files / folders"]},{"name":"mdi:folder-play","tags":["files / folders","folder media","folder music","folder video"]},{"name":"mdi:folder-play-outline","tags":["files / folders","folder media outline","folder music outline","folder video outline"]},{"name":"mdi:folder-plus","tags":["files / folders","create new folder","folder add"]},{"name":"mdi:folder-pound","tags":["files / folders","developer / languages","folder hash"]},{"name":"mdi:folder-pound-outline","tags":["files / folders","developer / languages","folder hash outline"]},{"name":"mdi:folder-question","tags":["files / folders","folder help"]},{"name":"mdi:folder-question-outline","tags":["files / folders","folder help outline"]},{"name":"mdi:folder-refresh","tags":["files / folders"]},{"name":"mdi:folder-refresh-outline","tags":["files / folders"]},{"name":"mdi:folder-remove","tags":["files / folders"]},{"name":"mdi:folder-remove-outline","tags":["files / folders"]},{"name":"mdi:folder-search","tags":["files / folders"]},{"name":"mdi:folder-search-outline","tags":["files / folders"]},{"name":"mdi:folder-settings","tags":["settings","files / folders"]},{"name":"mdi:folder-settings-outline","tags":["settings","files / folders"]},{"name":"mdi:folder-star-multiple","tags":["files / folders","folder favorite multiple"]},{"name":"mdi:folder-star-multiple-outline","tags":["files / folders","folder favorite multiple outline"]},{"name":"mdi:folder-swap","tags":["files / folders","folder transfer"]},{"name":"mdi:folder-swap-outline","tags":["files / folders","folder transfer outline"]},{"name":"mdi:folder-sync","tags":["files / folders"]},{"name":"mdi:folder-sync-outline","tags":["files / folders"]},{"name":"mdi:folder-table","tags":["files / folders"]},{"name":"mdi:folder-table-outline","tags":["files / folders"]},{"name":"mdi:folder-text","tags":["files / folders"]},{"name":"mdi:folder-text-outline","tags":["files / folders"]},{"name":"mdi:folder-upload","tags":["files / folders"]},{"name":"mdi:folder-upload-outline","tags":["files / folders"]},{"name":"mdi:folder-wrench","tags":["files / folders","folder settings"]},{"name":"mdi:folder-wrench-outline","tags":["files / folders","folder settings outline"]},{"name":"mdi:folder-zip","tags":["files / folders","compressed folder"]},{"name":"mdi:folder-zip-outline","tags":["files / folders","compressed folder outline"]},{"name":"mdi:food-apple","tags":["food / drink","agriculture"]},{"name":"mdi:food-apple-outline","tags":["food / drink","agriculture"]},{"name":"mdi:food-croissant","tags":["food / drink"]},{"name":"mdi:food-drumstick","tags":["food / drink","chicken leg","turkey leg","meat"]},{"name":"mdi:food-drumstick-off","tags":["food / drink","chicken leg off","turkey leg off","meat off"]},{"name":"mdi:food-drumstick-off-outline","tags":["food / drink","chicken leg off outline","turkey leg off outline","meat off outline"]},{"name":"mdi:food-drumstick-outline","tags":["food / drink","chicken leg outline","turkey leg outline","meat outline"]},{"name":"mdi:food-halal","tags":["food / drink","food muslim","dietary restriction"]},{"name":"mdi:food-hot-dog","tags":["food / drink","food weiner","food frankfurter"]},{"name":"mdi:food-kosher","tags":["food / drink","food jewish","dietary restriction"]},{"name":"mdi:food-steak","tags":["food / drink","meat","beef"]},{"name":"mdi:food-steak-off","tags":["food / drink","meat off","beef off"]},{"name":"mdi:food-turkey","tags":["food / drink","holiday","dinner","thanksgiving"]},{"name":"mdi:food-variant","tags":["food / drink"]},{"name":"mdi:food-variant-off","tags":["food / drink"]},{"name":"mdi:foot-print","tags":[]},{"name":"mdi:football-australian","tags":["sport"]},{"name":"mdi:football-helmet","tags":["sport"]},{"name":"mdi:forest-outline","tags":["nature","agriculture","places","forestry outline","pine tree multiple outline"]},{"name":"mdi:forklift","tags":["transportation + road"]},{"name":"mdi:form-dropdown","tags":["form"]},{"name":"mdi:form-select","tags":["form"]},{"name":"mdi:form-textarea","tags":["form"]},{"name":"mdi:form-textbox","tags":["form","rename"]},{"name":"mdi:form-textbox-lock","tags":["form","lock"]},{"name":"mdi:form-textbox-password","tags":["form"]},{"name":"mdi:format-align-bottom","tags":["text / content / format"]},{"name":"mdi:format-align-middle","tags":["text / content / format"]},{"name":"mdi:format-align-top","tags":["text / content / format"]},{"name":"mdi:format-annotation-minus","tags":["text / content / format"]},{"name":"mdi:format-annotation-plus","tags":["text / content / format","format annotation add"]},{"name":"mdi:format-color-highlight","tags":["color","text / content / format","format colour highlight"]},{"name":"mdi:format-color-marker-cancel","tags":["text / content / format","color","format color redact"]},{"name":"mdi:format-columns","tags":["text / content / format"]},{"name":"mdi:format-float-center","tags":["text / content / format","format float centre"]},{"name":"mdi:format-float-left","tags":["text / content / format"]},{"name":"mdi:format-float-none","tags":["text / content / format"]},{"name":"mdi:format-float-right","tags":["text / content / format"]},{"name":"mdi:format-font","tags":["text / content / format"]},{"name":"mdi:format-font-size-decrease","tags":["text / content / format"]},{"name":"mdi:format-font-size-increase","tags":["text / content / format"]},{"name":"mdi:format-header-1","tags":["text / content / format","format heading 1"]},{"name":"mdi:format-header-2","tags":["text / content / format","format heading 2"]},{"name":"mdi:format-header-3","tags":["text / content / format","format heading 3"]},{"name":"mdi:format-header-4","tags":["text / content / format","format heading 4"]},{"name":"mdi:format-header-5","tags":["text / content / format","format heading 5"]},{"name":"mdi:format-header-6","tags":["text / content / format","format heading 6"]},{"name":"mdi:format-header-decrease","tags":["text / content / format","format heading decease"]},{"name":"mdi:format-header-equal","tags":["text / content / format","format heading equal"]},{"name":"mdi:format-header-increase","tags":["text / content / format","format heading increase"]},{"name":"mdi:format-header-pound","tags":["text / content / format","format header hash","format heading pound","format heading hash","format heading markdown"]},{"name":"mdi:format-horizontal-align-center","tags":["text / content / format","format horizontal align centre","arrow horizontal collapse"]},{"name":"mdi:format-horizontal-align-left","tags":["text / content / format"]},{"name":"mdi:format-horizontal-align-right","tags":["text / content / format"]},{"name":"mdi:format-letter-case","tags":["text / content / format"]},{"name":"mdi:format-letter-case-lower","tags":["text / content / format","format lowercase"]},{"name":"mdi:format-letter-case-upper","tags":["text / content / format","format uppercase"]},{"name":"mdi:format-letter-ends-with","tags":["text / content / format"]},{"name":"mdi:format-letter-matches","tags":["text / content / format"]},{"name":"mdi:format-letter-spacing","tags":["text / content / format","format kerning"]},{"name":"mdi:format-letter-spacing-variant","tags":["text / content / format"]},{"name":"mdi:format-letter-starts-with","tags":["text / content / format"]},{"name":"mdi:format-line-height","tags":["text / content / format"]},{"name":"mdi:format-list-bulleted-triangle","tags":["text / content / format"]},{"name":"mdi:format-list-bulleted-type","tags":["text / content / format"]},{"name":"mdi:format-list-checks","tags":["text / content / format","to do"]},{"name":"mdi:format-list-group","tags":["text / content / format"]},{"name":"mdi:format-list-group-plus","tags":["text / content / format","format list group add"]},{"name":"mdi:format-list-text","tags":["text / content / format"]},{"name":"mdi:format-overline","tags":["text / content / format"]},{"name":"mdi:format-page-split","tags":["text / content / format"]},{"name":"mdi:format-paragraph","tags":["text / content / format"]},{"name":"mdi:format-paragraph-spacing","tags":["text / content / format"]},{"name":"mdi:format-pilcrow","tags":["text / content / format"]},{"name":"mdi:format-quote-close-outline","tags":["text / content / format"]},{"name":"mdi:format-quote-open","tags":["text / content / format"]},{"name":"mdi:format-quote-open-outline","tags":["text / content / format"]},{"name":"mdi:format-section","tags":["text / content / format"]},{"name":"mdi:format-subscript","tags":["text / content / format"]},{"name":"mdi:format-superscript","tags":["text / content / format","math","exponent"]},{"name":"mdi:format-text","tags":["text / content / format"]},{"name":"mdi:format-text-rotation-down-vertical","tags":["text / content / format"]},{"name":"mdi:format-text-variant","tags":["text / content / format"]},{"name":"mdi:format-text-variant-outline","tags":["text / content / format"]},{"name":"mdi:format-underline-wavy","tags":["text / content / format"]},{"name":"mdi:format-wrap-inline","tags":["text / content / format"]},{"name":"mdi:format-wrap-square","tags":["text / content / format"]},{"name":"mdi:format-wrap-tight","tags":["text / content / format"]},{"name":"mdi:format-wrap-top-bottom","tags":["text / content / format"]},{"name":"mdi:forum-minus","tags":["chat minus","forum subtract","chat subtract"]},{"name":"mdi:forum-minus-outline","tags":["chat minus outline","forum subtract outline","chat subtract outline"]},{"name":"mdi:forum-plus","tags":["chat plus","forum add","chat add"]},{"name":"mdi:forum-plus-outline","tags":["chat plus outline","chat add outline","forum add outline"]},{"name":"mdi:forum-remove","tags":["forum delete","chat remove","chat delete"]},{"name":"mdi:forum-remove-outline","tags":["forum delete outline","chat remove outline","chat delete outline"]},{"name":"mdi:forwardburger","tags":[]},{"name":"mdi:fountain","tags":[]},{"name":"mdi:fountain-pen","tags":["drawing / art"]},{"name":"mdi:fountain-pen-tip","tags":["drawing / art"]},{"name":"mdi:fraction-one-half","tags":[]},{"name":"mdi:french-fries","tags":["food / drink","chips","finger chips","french fry","fried potatoes","fries","frites"]},{"name":"mdi:frequently-asked-questions","tags":["faq"]},{"name":"mdi:fridge","tags":["home automation","fridge filled","refrigerator","kitchen"]},{"name":"mdi:fridge-alert","tags":["home automation","alert / error"]},{"name":"mdi:fridge-alert-outline","tags":["home automation","alert / error"]},{"name":"mdi:fridge-bottom","tags":["home automation","fridge filled top","refrigerator bottom"]},{"name":"mdi:fridge-industrial","tags":["home automation"]},{"name":"mdi:fridge-industrial-alert","tags":["home automation","alert / error"]},{"name":"mdi:fridge-industrial-alert-outline","tags":["home automation","alert / error"]},{"name":"mdi:fridge-industrial-off","tags":["home automation"]},{"name":"mdi:fridge-industrial-off-outline","tags":["home automation"]},{"name":"mdi:fridge-industrial-outline","tags":["home automation"]},{"name":"mdi:fridge-off","tags":["home automation"]},{"name":"mdi:fridge-off-outline","tags":["home automation"]},{"name":"mdi:fridge-outline","tags":["home automation","kitchen","refrigerator outline"]},{"name":"mdi:fridge-top","tags":["home automation","fridge filled bottom","refrigerator top"]},{"name":"mdi:fridge-variant","tags":["home automation"]},{"name":"mdi:fridge-variant-alert","tags":["home automation","alert / error"]},{"name":"mdi:fridge-variant-alert-outline","tags":["home automation","alert / error"]},{"name":"mdi:fridge-variant-off","tags":["home automation"]},{"name":"mdi:fridge-variant-off-outline","tags":["home automation"]},{"name":"mdi:fridge-variant-outline","tags":["home automation"]},{"name":"mdi:fruit-cherries","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-cherries-off","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-citrus","tags":["food / drink","agriculture","fruit lemon","fruit lime"]},{"name":"mdi:fruit-citrus-off","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-grapes","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-grapes-outline","tags":["food / drink","agriculture"]},{"name":"mdi:fruit-pear","tags":["food / drink"]},{"name":"mdi:fruit-pineapple","tags":["food / drink","agriculture","fruit ananas"]},{"name":"mdi:fruit-watermelon","tags":["food / drink","agriculture"]},{"name":"mdi:fuel","tags":["automotive","petrol","gasoline"]},{"name":"mdi:fuel-cell","tags":["automotive","battery","battery"]},{"name":"mdi:function","tags":["math"]},{"name":"mdi:function-variant","tags":["math"]},{"name":"mdi:furigana-horizontal","tags":["text / content / format","ruby horizontal"]},{"name":"mdi:furigana-vertical","tags":["text / content / format","zhuyin","ruby vertical"]},{"name":"mdi:fuse","tags":["automotive"]},{"name":"mdi:fuse-alert","tags":["automotive","alert / error"]},{"name":"mdi:fuse-blade","tags":["automotive"]},{"name":"mdi:fuse-off","tags":["automotive"]},{"name":"mdi:gamepad-circle","tags":["gaming / rpg","controller circle"]},{"name":"mdi:gamepad-circle-down","tags":["gaming / rpg","controller circle down"]},{"name":"mdi:gamepad-circle-left","tags":["gaming / rpg","controller circle left"]},{"name":"mdi:gamepad-circle-outline","tags":["gaming / rpg","controller circle outline"]},{"name":"mdi:gamepad-circle-right","tags":["gaming / rpg","controller circle right"]},{"name":"mdi:gamepad-circle-up","tags":["gaming / rpg","controller circle up"]},{"name":"mdi:gamepad-down","tags":["gaming / rpg","controller down"]},{"name":"mdi:gamepad-left","tags":["gaming / rpg","controller left"]},{"name":"mdi:gamepad-outline","tags":["gaming / rpg","home automation","controller outline","games outline"]},{"name":"mdi:gamepad-right","tags":["gaming / rpg","controller right"]},{"name":"mdi:gamepad-round","tags":["gaming / rpg","controller round"]},{"name":"mdi:gamepad-round-down","tags":["gaming / rpg","controller round down"]},{"name":"mdi:gamepad-round-left","tags":["gaming / rpg","controller round left"]},{"name":"mdi:gamepad-round-outline","tags":["gaming / rpg","controller round outline"]},{"name":"mdi:gamepad-round-right","tags":["gaming / rpg","controller round right"]},{"name":"mdi:gamepad-round-up","tags":["gaming / rpg","controller round up"]},{"name":"mdi:gamepad-up","tags":["gaming / rpg","controller up"]},{"name":"mdi:gamepad-variant","tags":["gaming / rpg","controller variant"]},{"name":"mdi:gamepad-variant-outline","tags":["gaming / rpg","controller variant outline"]},{"name":"mdi:gamma","tags":["alpha / numeric"]},{"name":"mdi:gantry-crane","tags":[]},{"name":"mdi:garage","tags":["home automation"]},{"name":"mdi:garage-alert","tags":["home automation","alert / error","garage warning"]},{"name":"mdi:garage-alert-variant","tags":["home automation","alert / error"]},{"name":"mdi:garage-lock","tags":["home automation","lock"]},{"name":"mdi:garage-open","tags":["home automation"]},{"name":"mdi:garage-open-variant","tags":["home automation"]},{"name":"mdi:garage-variant","tags":["home automation"]},{"name":"mdi:garage-variant-lock","tags":["home automation","lock"]},{"name":"mdi:gas-burner","tags":["home automation","stove burner","cooktop burner","grill"]},{"name":"mdi:gas-cylinder","tags":["tank","oxygen tank"]},{"name":"mdi:gas-station-off","tags":[]},{"name":"mdi:gas-station-off-outline","tags":[]},{"name":"mdi:gate","tags":["home automation"]},{"name":"mdi:gate-alert","tags":["home automation","alert / error"]},{"name":"mdi:gate-and","tags":["logic gate and"]},{"name":"mdi:gate-arrow-left","tags":["home automation"]},{"name":"mdi:gate-arrow-right","tags":["home automation"]},{"name":"mdi:gate-buffer","tags":[]},{"name":"mdi:gate-nand","tags":["logic gate nand"]},{"name":"mdi:gate-nor","tags":["logic gate nor"]},{"name":"mdi:gate-not","tags":["logic gate not"]},{"name":"mdi:gate-open","tags":["home automation"]},{"name":"mdi:gate-or","tags":["logic gate or"]},{"name":"mdi:gate-xnor","tags":["logic gate xnor"]},{"name":"mdi:gate-xor","tags":["logic gate xor"]},{"name":"mdi:gauge-empty","tags":["automotive","home automation"]},{"name":"mdi:gauge-full","tags":["automotive","home automation"]},{"name":"mdi:gauge-low","tags":["automotive","home automation"]},{"name":"mdi:gavel","tags":["court hammer"]},{"name":"mdi:gender-female","tags":["venus"]},{"name":"mdi:gender-male","tags":["mars"]},{"name":"mdi:gender-male-female","tags":[]},{"name":"mdi:gender-male-female-variant","tags":["mercury"]},{"name":"mdi:gender-non-binary","tags":["gender enby"]},{"name":"mdi:gender-transgender","tags":[]},{"name":"mdi:gesture-double-tap","tags":["interaction double tap","hand double tap"]},{"name":"mdi:gesture-pinch","tags":[]},{"name":"mdi:gesture-spread","tags":[]},{"name":"mdi:gesture-swipe-down","tags":[]},{"name":"mdi:gesture-swipe-horizontal","tags":[]},{"name":"mdi:gesture-swipe-left","tags":[]},{"name":"mdi:gesture-swipe-right","tags":[]},{"name":"mdi:gesture-swipe-up","tags":[]},{"name":"mdi:gesture-swipe-vertical","tags":[]},{"name":"mdi:gesture-tap","tags":["interaction tap","hand tap","gesture touch"]},{"name":"mdi:gesture-tap-box","tags":["gesture touch box"]},{"name":"mdi:gesture-tap-button","tags":["form","call to action","cta","button pointer","gesture touch button"]},{"name":"mdi:gesture-two-double-tap","tags":[]},{"name":"mdi:gesture-two-tap","tags":[]},{"name":"mdi:ghost","tags":["gaming / rpg","inky","blinky","pinky","clyde"]},{"name":"mdi:ghost-off","tags":["gaming / rpg"]},{"name":"mdi:ghost-off-outline","tags":["gaming / rpg"]},{"name":"mdi:ghost-outline","tags":["gaming / rpg"]},{"name":"mdi:gift","tags":["holiday","present","package","donate"]},{"name":"mdi:gift-off","tags":["holiday","present off","package off","donate off"]},{"name":"mdi:gift-off-outline","tags":["holiday","present off outline","package off outline","donate off outline"]},{"name":"mdi:gift-open","tags":["holiday","present open","package open"]},{"name":"mdi:gift-open-outline","tags":["holiday","present open outline","package open outline"]},{"name":"mdi:gift-outline","tags":["shopping","holiday","donate outline","present outline","package outline"]},{"name":"mdi:glass-cocktail-off","tags":["food / drink"]},{"name":"mdi:glass-flute","tags":["food / drink","alcohol","cocktail","cup","drink"]},{"name":"mdi:glass-fragile","tags":["food / drink","glass broken"]},{"name":"mdi:glass-mug","tags":["food / drink","pub","bar","beer","alcohol","cup","drink","local bar"]},{"name":"mdi:glass-mug-off","tags":["food / drink"]},{"name":"mdi:glass-mug-variant","tags":["food / drink","pub","bar","beer","drink","alcohol","cup","local bar"]},{"name":"mdi:glass-mug-variant-off","tags":["food / drink"]},{"name":"mdi:glass-pint-outline","tags":["food / drink"]},{"name":"mdi:glass-stange","tags":["food / drink","alcohol","bar","cocktail","cup","drink"]},{"name":"mdi:glass-tulip","tags":["food / drink","bar","alcohol","cocktail","cup","drink"]},{"name":"mdi:glass-wine","tags":["food / drink","bar","alcohol","cocktail","cup","drink"]},{"name":"mdi:glasses","tags":["clothing"]},{"name":"mdi:globe-light","tags":["home automation"]},{"name":"mdi:globe-light-outline","tags":["home automation"]},{"name":"mdi:globe-model","tags":[]},{"name":"mdi:go-kart","tags":["sport","cart"]},{"name":"mdi:go-kart-track","tags":[]},{"name":"mdi:gold","tags":[]},{"name":"mdi:golf-cart","tags":["sport","transportation + other"]},{"name":"mdi:gondola","tags":["transportation + other","cable car"]},{"name":"mdi:gradient-horizontal","tags":["drawing / art"]},{"name":"mdi:graph","tags":["dependency","dependencies"]},{"name":"mdi:graph-outline","tags":["dependency","dependencies"]},{"name":"mdi:grave-stone","tags":["holiday","headstone","tombstone","cemetery","graveyard"]},{"name":"mdi:greater-than","tags":["math"]},{"name":"mdi:greater-than-or-equal","tags":["math"]},{"name":"mdi:greenhouse","tags":["home automation","agriculture","nature","glasshouse","hothouse","shed"]},{"name":"mdi:grid-large","tags":[]},{"name":"mdi:group","tags":[]},{"name":"mdi:guitar-acoustic","tags":["music"]},{"name":"mdi:guitar-electric","tags":["music"]},{"name":"mdi:guitar-pick","tags":["music"]},{"name":"mdi:guitar-pick-outline","tags":["music"]},{"name":"mdi:guy-fawkes-mask","tags":[]},{"name":"mdi:hair-dryer","tags":["health / beauty"]},{"name":"mdi:hair-dryer-outline","tags":["health / beauty"]},{"name":"mdi:halloween","tags":["holiday","pumpkin face","pumpkin carved","jack o lantern","emoji halloween","emoticon halloween"]},{"name":"mdi:hamburger","tags":["food / drink","burger","fast food","food"]},{"name":"mdi:hamburger-check","tags":["food / drink","burger check"]},{"name":"mdi:hamburger-minus","tags":["food / drink","burger minus"]},{"name":"mdi:hamburger-off","tags":["food / drink","burger off","fast food off","food off"]},{"name":"mdi:hamburger-plus","tags":["food / drink","burger plus","burger add"]},{"name":"mdi:hamburger-remove","tags":["food / drink","burger remove"]},{"name":"mdi:hammer-sickle","tags":["communism"]},{"name":"mdi:hand-back-left-off","tags":[]},{"name":"mdi:hand-back-left-off-outline","tags":[]},{"name":"mdi:hand-back-right-off","tags":[]},{"name":"mdi:hand-back-right-off-outline","tags":[]},{"name":"mdi:hand-clap","tags":["applause"]},{"name":"mdi:hand-clap-off","tags":["applause off"]},{"name":"mdi:hand-coin","tags":["banking","charity","donation"]},{"name":"mdi:hand-coin-outline","tags":["banking","charity outline","donation outline"]},{"name":"mdi:hand-cycle","tags":["sport","hand bike"]},{"name":"mdi:hand-extended","tags":["hand open","hand palm"]},{"name":"mdi:hand-extended-outline","tags":["hand open outline","hand palm outline"]},{"name":"mdi:hand-heart-outline","tags":[]},{"name":"mdi:hand-okay","tags":[]},{"name":"mdi:hand-peace","tags":[]},{"name":"mdi:hand-peace-variant","tags":[]},{"name":"mdi:hand-pointing-down","tags":[]},{"name":"mdi:hand-pointing-left","tags":[]},{"name":"mdi:hand-pointing-right","tags":[]},{"name":"mdi:hand-pointing-up","tags":[]},{"name":"mdi:hand-saw","tags":["hardware / tools"]},{"name":"mdi:hand-water","tags":["medical / hospital","hand wash"]},{"name":"mdi:handcuffs","tags":[]},{"name":"mdi:hands-pray","tags":[]},{"name":"mdi:handshake","tags":["business","deal","help","partnership"]},{"name":"mdi:handshake-outline","tags":["business outline","deal outline","help outline","partnership outline"]},{"name":"mdi:hanger","tags":["clothing","home automation","coat hanger","clothes hanger","closet"]},{"name":"mdi:hard-hat","tags":["hardware / tools","clothing","helmet"]},{"name":"mdi:harddisk","tags":["hdd"]},{"name":"mdi:harddisk-plus","tags":["hdd plus"]},{"name":"mdi:harddisk-remove","tags":["hdd remove"]},{"name":"mdi:hazard-lights","tags":["automotive","warning lights"]},{"name":"mdi:hdmi-port","tags":["video / movie","home automation"]},{"name":"mdi:head","tags":[]},{"name":"mdi:head-alert","tags":["alert / error"]},{"name":"mdi:head-alert-outline","tags":["alert / error"]},{"name":"mdi:head-check","tags":[]},{"name":"mdi:head-check-outline","tags":[]},{"name":"mdi:head-cog-outline","tags":["settings","psychology outline"]},{"name":"mdi:head-dots-horizontal","tags":["head thinking"]},{"name":"mdi:head-dots-horizontal-outline","tags":["head thinking outline"]},{"name":"mdi:head-flash","tags":["head ache"]},{"name":"mdi:head-flash-outline","tags":["head ache outline"]},{"name":"mdi:head-heart","tags":["head love"]},{"name":"mdi:head-heart-outline","tags":["head love outline"]},{"name":"mdi:head-lightbulb","tags":["head idea","head bulb"]},{"name":"mdi:head-lightbulb-outline","tags":["head idea outline","head bulb outline"]},{"name":"mdi:head-minus","tags":[]},{"name":"mdi:head-minus-outline","tags":[]},{"name":"mdi:head-outline","tags":[]},{"name":"mdi:head-plus","tags":[]},{"name":"mdi:head-plus-outline","tags":[]},{"name":"mdi:head-question","tags":[]},{"name":"mdi:head-question-outline","tags":[]},{"name":"mdi:head-remove","tags":[]},{"name":"mdi:head-remove-outline","tags":[]},{"name":"mdi:head-snowflake","tags":["head freeze","brain freeze"]},{"name":"mdi:head-snowflake-outline","tags":["head freeze outline","brain freeze outline"]},{"name":"mdi:head-sync","tags":["head reload","head refresh"]},{"name":"mdi:head-sync-outline","tags":["head reload outline","head refresh outline"]},{"name":"mdi:headphones-bluetooth","tags":[]},{"name":"mdi:headphones-off","tags":["audio","device / tech","music"]},{"name":"mdi:headphones-settings","tags":["audio","settings"]},{"name":"mdi:headset-dock","tags":["audio"]},{"name":"mdi:headset-off","tags":["audio","device / tech"]},{"name":"mdi:heart-box","tags":[]},{"name":"mdi:heart-box-outline","tags":[]},{"name":"mdi:heart-broken","tags":[]},{"name":"mdi:heart-broken-outline","tags":[]},{"name":"mdi:heart-circle","tags":[]},{"name":"mdi:heart-circle-outline","tags":[]},{"name":"mdi:heart-cog","tags":["settings"]},{"name":"mdi:heart-cog-outline","tags":["settings"]},{"name":"mdi:heart-flash","tags":["medical / hospital","aed","defibrillator"]},{"name":"mdi:heart-half","tags":["gaming / rpg"]},{"name":"mdi:heart-half-full","tags":["gaming / rpg"]},{"name":"mdi:heart-half-outline","tags":["gaming / rpg"]},{"name":"mdi:heart-minus","tags":[]},{"name":"mdi:heart-minus-outline","tags":[]},{"name":"mdi:heart-multiple","tags":["hearts"]},{"name":"mdi:heart-multiple-outline","tags":["hearts outline"]},{"name":"mdi:heart-off","tags":["medical / hospital"]},{"name":"mdi:heart-off-outline","tags":["medical / hospital"]},{"name":"mdi:heart-plus","tags":[]},{"name":"mdi:heart-plus-outline","tags":[]},{"name":"mdi:heart-remove","tags":[]},{"name":"mdi:heart-remove-outline","tags":[]},{"name":"mdi:heart-settings","tags":["settings"]},{"name":"mdi:heart-settings-outline","tags":["settings"]},{"name":"mdi:heat-wave","tags":["home automation","weather","agriculture","keep warm","warmth"]},{"name":"mdi:heating-coil","tags":["home automation","radiator coil","heated floor"]},{"name":"mdi:helicopter","tags":["transportation + flying"]},{"name":"mdi:help","tags":["question mark"]},{"name":"mdi:help-box","tags":["question mark box"]},{"name":"mdi:help-box-multiple","tags":["quiz","question box multiple"]},{"name":"mdi:help-box-multiple-outline","tags":["quiz outline","question box multiple outline"]},{"name":"mdi:help-box-outline","tags":["question box outline"]},{"name":"mdi:help-network","tags":["question network"]},{"name":"mdi:help-network-outline","tags":["question network outline"]},{"name":"mdi:help-rhombus","tags":["question mark rhombus"]},{"name":"mdi:help-rhombus-outline","tags":["question mark rhombus outline"]},{"name":"mdi:hexadecimal","tags":["developer / languages"]},{"name":"mdi:hexagon","tags":["shape"]},{"name":"mdi:hexagon-multiple","tags":["shape","hexagons"]},{"name":"mdi:hexagon-multiple-outline","tags":["nature"]},{"name":"mdi:hexagon-outline","tags":["shape"]},{"name":"mdi:hexagon-slice-1","tags":[]},{"name":"mdi:hexagon-slice-2","tags":[]},{"name":"mdi:hexagon-slice-3","tags":[]},{"name":"mdi:hexagon-slice-4","tags":[]},{"name":"mdi:hexagon-slice-5","tags":[]},{"name":"mdi:hexagon-slice-6","tags":[]},{"name":"mdi:hexagram","tags":["shape","holiday","star","christmas star"]},{"name":"mdi:hexagram-outline","tags":["shape","holiday","star outline","christmas star outline"]},{"name":"mdi:high-definition","tags":["video / movie","hd"]},{"name":"mdi:highway","tags":["transportation + road","autobahn","motorway"]},{"name":"mdi:hockey-puck","tags":["sport"]},{"name":"mdi:hololens","tags":["gaming / rpg"]},{"name":"mdi:home-account","tags":["account / user","home automation","home user","house account","house user"]},{"name":"mdi:home-alert","tags":["home automation","alert / error","home warning","house alert","house warning"]},{"name":"mdi:home-alert-outline","tags":["home automation","alert / error","house alert outline","home warning outline","house warning outline"]},{"name":"mdi:home-analytics","tags":["home automation","chart home","home chart","home report","house analytics","house chart"]},{"name":"mdi:home-automation","tags":["home automation","house automation","home wireless","house wireless","smart home","smart house"]},{"name":"mdi:home-battery","tags":["home automation","battery","home energy","home power","home electricity","house energy","house battery","house power"]},{"name":"mdi:home-battery-outline","tags":["home automation","battery","home energy outline","home power outline","home electricity outline","house battery outline","house power outline","house energy outline"]},{"name":"mdi:home-circle","tags":["home automation","house circle"]},{"name":"mdi:home-circle-outline","tags":["home automation","house circle outline"]},{"name":"mdi:home-clock","tags":["home automation","date / time","home time","home schedule","house time","house clock","house schedule"]},{"name":"mdi:home-clock-outline","tags":["home automation","date / time","home time outline","home schedule outline","house clock outline","house time outline","house schedule outline"]},{"name":"mdi:home-edit","tags":["home automation","edit / modify","house edit"]},{"name":"mdi:home-edit-outline","tags":["home automation","edit / modify","house edit outline"]},{"name":"mdi:home-export-outline","tags":["home automation","house export outline"]},{"name":"mdi:home-floor-0","tags":["home automation","house floor 0","home floor zero","house floor zero"]},{"name":"mdi:home-floor-1","tags":["home automation","house floor 1","home floor one","house floor one","home floor first","house floor first"]},{"name":"mdi:home-floor-2","tags":["home automation","house floor 2","home floor two","house floor two","home floor second","house floor second"]},{"name":"mdi:home-floor-3","tags":["home automation","house floor 3","home floor three","house floor three","home floor third","house floor third"]},{"name":"mdi:home-floor-a","tags":["home automation","home floor attic","house floor a","house floor attic"]},{"name":"mdi:home-floor-b","tags":["home automation","home floor basement","house floor b","house floor basement"]},{"name":"mdi:home-floor-g","tags":["home automation","home floor ground","house floor g","house floor ground"]},{"name":"mdi:home-floor-l","tags":["home automation","home floor loft","home floor lower","house floor l","house floor loft","house floor lower"]},{"name":"mdi:home-floor-negative-1","tags":["home automation","house floor negative 1","home floor negative one","home floor minus 1","home floor minus one","house floor negative one","house floor minus 1","house floor minus one"]},{"name":"mdi:home-group","tags":["home automation","house group","neighbourhood","estate","housing estate"]},{"name":"mdi:home-group-minus","tags":["home automation","house group minus"]},{"name":"mdi:home-group-plus","tags":["home automation","house group plus","home group add","house group add"]},{"name":"mdi:home-group-remove","tags":["home automation","house group remove"]},{"name":"mdi:home-import-outline","tags":["home automation","house import outline"]},{"name":"mdi:home-lightbulb","tags":["home automation","home bulb","house lightbulb","house bulb"]},{"name":"mdi:home-lightbulb-outline","tags":["home automation","home bulb outline","house lightbulb outline","house bulb outline"]},{"name":"mdi:home-lightning-bolt","tags":["home automation","home energy","home power","home electricity","home flash","house lightning bolt","house flash"]},{"name":"mdi:home-lightning-bolt-outline","tags":["home automation","home energy","home power","home electricity","home flash","house lightning bolt outline","house flash outline"]},{"name":"mdi:home-lock","tags":["home automation","lock","house lock","home secure","house secure"]},{"name":"mdi:home-lock-open","tags":["home automation","lock","house lock open"]},{"name":"mdi:home-map-marker","tags":["home automation","navigation","house map marker","home location"]},{"name":"mdi:home-minus","tags":["home automation","house minus"]},{"name":"mdi:home-minus-outline","tags":["home automation","house minus outline"]},{"name":"mdi:home-modern","tags":["home automation","house modern"]},{"name":"mdi:home-off","tags":["home automation","house off"]},{"name":"mdi:home-off-outline","tags":["home automation","house off outline"]},{"name":"mdi:home-percent","tags":[]},{"name":"mdi:home-percent-outline","tags":["home automation"]},{"name":"mdi:home-plus","tags":["home automation","home add","house plus","house add"]},{"name":"mdi:home-plus-outline","tags":["home automation","house plus outline","house add outline"]},{"name":"mdi:home-remove","tags":["home automation","house remove"]},{"name":"mdi:home-remove-outline","tags":["home automation","house remove outline"]},{"name":"mdi:home-roof","tags":["home automation","home chimney","home attic","house roof","house attic","house chimney"]},{"name":"mdi:home-search","tags":["home automation","house search","home find","house find"]},{"name":"mdi:home-search-outline","tags":["home automation","house search outline","home find outline","house find outline"]},{"name":"mdi:home-silo","tags":["home automation","agriculture","farm house","farm home"]},{"name":"mdi:home-silo-outline","tags":["agriculture","home automation","farm house outline","farm home outline"]},{"name":"mdi:home-sound-in","tags":["home automation"]},{"name":"mdi:home-sound-in-outline","tags":["home automation"]},{"name":"mdi:home-sound-out","tags":["home automation"]},{"name":"mdi:home-sound-out-outline","tags":["home automation"]},{"name":"mdi:home-switch","tags":["home automation","home swap","house switch","house swap"]},{"name":"mdi:home-switch-outline","tags":["home automation","home swap outline","house swap outline","house switch outline"]},{"name":"mdi:home-thermometer","tags":["home automation","home climate","home temperature","house thermometer","house climate","house temperature"]},{"name":"mdi:home-thermometer-outline","tags":["home automation","home climate outline","home temperature outline","house thermometer outline","house climate outline","house temperature outline"]},{"name":"mdi:hook","tags":[]},{"name":"mdi:hook-off","tags":[]},{"name":"mdi:hoop-house","tags":["agriculture","home automation","green house"]},{"name":"mdi:hops","tags":["food / drink","agriculture"]},{"name":"mdi:horizontal-rotate-clockwise","tags":[]},{"name":"mdi:horizontal-rotate-counterclockwise","tags":[]},{"name":"mdi:horse","tags":["transportation + other","animal","agriculture","equestrian"]},{"name":"mdi:horse-human","tags":["transportation + other","agriculture","people / family","horseback riding","horse riding","equestrian"]},{"name":"mdi:horse-variant","tags":["animal","agriculture","equestrian variant"]},{"name":"mdi:horse-variant-fast","tags":["animal","agriculture"]},{"name":"mdi:horseshoe","tags":["sport","agriculture","luck"]},{"name":"mdi:hospital","tags":["medical / hospital","swiss cross","dispensary"]},{"name":"mdi:hospital-box-outline","tags":["medical / hospital","swiss cross box outline","dispensary box outline"]},{"name":"mdi:hospital-building","tags":["places","medical / hospital"]},{"name":"mdi:hospital-marker","tags":["medical / hospital","navigation","hospital location"]},{"name":"mdi:hours-24","tags":["date / time"]},{"name":"mdi:hubspot","tags":[]},{"name":"mdi:human-baby-changing-table","tags":["people / family","medical / hospital"]},{"name":"mdi:human-capacity-increase","tags":["account / user","transportation + other","people / family"]},{"name":"mdi:human-child","tags":["people / family"]},{"name":"mdi:human-dolly","tags":["people / family","human hand truck","human trolley"]},{"name":"mdi:human-edit","tags":["people / family","edit / modify"]},{"name":"mdi:human-female-boy","tags":["people / family","mother","mom","woman child","mum"]},{"name":"mdi:human-female-dance","tags":["people / family","sport","ballet"]},{"name":"mdi:human-female-female","tags":["people / family","woman woman","women"]},{"name":"mdi:human-female-girl","tags":["people / family","mother","mom","woman child","mum"]},{"name":"mdi:human-male-board","tags":["people / family","teacher","teaching","lecture","college","blackboard","whiteboard","human man board"]},{"name":"mdi:human-male-board-poll","tags":["people / family","teach poll"]},{"name":"mdi:human-male-boy","tags":["people / family","father","dad","man child"]},{"name":"mdi:human-male-child","tags":["people / family"]},{"name":"mdi:human-male-girl","tags":["people / family","father","dad","man child"]},{"name":"mdi:human-male-height","tags":["medical / hospital","people / family"]},{"name":"mdi:human-male-height-variant","tags":["medical / hospital","people / family"]},{"name":"mdi:human-male-male","tags":["people / family","man man","men"]},{"name":"mdi:human-non-binary","tags":["people / family","human genderless","human transgender"]},{"name":"mdi:human-queue","tags":["people / family","human line"]},{"name":"mdi:human-wheelchair","tags":["people / family","medical / hospital","human accessible"]},{"name":"mdi:human-white-cane","tags":["people / family","medical / hospital","human blind"]},{"name":"mdi:hvac-off","tags":["home automation","heating off","ventilation off","air conditioning off"]},{"name":"mdi:hydraulic-oil-level","tags":["automotive"]},{"name":"mdi:hydraulic-oil-temperature","tags":["automotive"]},{"name":"mdi:hydro-power","tags":["device / tech","agriculture","hydraulic turbine","water turbine","watermill"]},{"name":"mdi:hydrogen-station","tags":["automotive"]},{"name":"mdi:ice-cream-off","tags":["food / drink"]},{"name":"mdi:ice-pop","tags":["food / drink","popsicle"]},{"name":"mdi:id-card","tags":[]},{"name":"mdi:identifier","tags":["developer / languages","key"]},{"name":"mdi:ideogram-cjk","tags":["alpha / numeric","ideogram chinese japanese korean","writing system cjk"]},{"name":"mdi:ideogram-cjk-variant","tags":["alpha / numeric","ideogram chinese japanese korean variant","writing system cjk variant"]},{"name":"mdi:image-area","tags":[]},{"name":"mdi:image-area-close","tags":[]},{"name":"mdi:image-broken","tags":[]},{"name":"mdi:image-check","tags":[]},{"name":"mdi:image-check-outline","tags":[]},{"name":"mdi:image-edit","tags":["edit / modify"]},{"name":"mdi:image-edit-outline","tags":["edit / modify"]},{"name":"mdi:image-filter-hdr-outline","tags":["photography","nature","mountain outline","landscape outline"]},{"name":"mdi:image-lock","tags":["lock","photography","image secure"]},{"name":"mdi:image-lock-outline","tags":["photography","lock","image secure outline"]},{"name":"mdi:image-marker","tags":["navigation","image location"]},{"name":"mdi:image-marker-outline","tags":["navigation","image location outline"]},{"name":"mdi:image-minus","tags":[]},{"name":"mdi:image-minus-outline","tags":[]},{"name":"mdi:image-move","tags":[]},{"name":"mdi:image-off","tags":[]},{"name":"mdi:image-off-outline","tags":[]},{"name":"mdi:image-outline","tags":[]},{"name":"mdi:image-plus","tags":["image add"]},{"name":"mdi:image-plus-outline","tags":["image add outline"]},{"name":"mdi:image-refresh","tags":["photography"]},{"name":"mdi:image-refresh-outline","tags":["photography"]},{"name":"mdi:image-remove","tags":[]},{"name":"mdi:image-remove-outline","tags":[]},{"name":"mdi:image-sync","tags":["photography"]},{"name":"mdi:image-sync-outline","tags":["photography"]},{"name":"mdi:import","tags":["input"]},{"name":"mdi:inbox-arrow-down-outline","tags":[]},{"name":"mdi:inbox-arrow-up","tags":["move from inbox"]},{"name":"mdi:inbox-arrow-up-outline","tags":[]},{"name":"mdi:inbox-full","tags":[]},{"name":"mdi:inbox-full-outline","tags":[]},{"name":"mdi:inbox-outline","tags":[]},{"name":"mdi:inbox-remove","tags":[]},{"name":"mdi:inbox-remove-outline","tags":[]},{"name":"mdi:incognito","tags":["anonymous","spy"]},{"name":"mdi:incognito-circle-off","tags":["anonymous circle off","spy circle off"]},{"name":"mdi:incognito-off","tags":["spy off","anonymous off"]},{"name":"mdi:induction","tags":["home automation","automotive","ignition"]},{"name":"mdi:infinity","tags":["math"]},{"name":"mdi:information-box","tags":["settings","info box"]},{"name":"mdi:information-box-outline","tags":["settings","info box outline"]},{"name":"mdi:information-off","tags":["info off","info circle off","information circle off"]},{"name":"mdi:information-off-outline","tags":["info circle off outline","information circle off outline","information off outline","info off outline"]},{"name":"mdi:information-slab-box","tags":["settings","info slab box"]},{"name":"mdi:information-slab-box-outline","tags":["settings","info slab box outline"]},{"name":"mdi:information-slab-circle","tags":["settings","info slab circle"]},{"name":"mdi:information-slab-circle-outline","tags":["settings","info slab circle outline"]},{"name":"mdi:information-slab-symbol","tags":["settings","info slab symbol"]},{"name":"mdi:information-symbol","tags":["settings","info symbol"]},{"name":"mdi:information-variant","tags":["info variant","about variant","information serif symbol","info variant symbol"]},{"name":"mdi:information-variant-box","tags":["settings","info variant box","information serif box","info serif box"]},{"name":"mdi:information-variant-box-outline","tags":["settings","info variant box outline","information serif box outline","info serif box outline"]},{"name":"mdi:information-variant-circle","tags":["settings","information serif circle","info serif circle","info variant circle"]},{"name":"mdi:information-variant-circle-outline","tags":["settings","information serif circle outline","info variant circle outline","info serif circle outline"]},{"name":"mdi:instrument-triangle","tags":["music","dinner bell"]},{"name":"mdi:integrated-circuit-chip","tags":["banking","icc","chip"]},{"name":"mdi:ip","tags":["internet protocol"]},{"name":"mdi:ip-network","tags":[]},{"name":"mdi:ip-network-outline","tags":[]},{"name":"mdi:ip-outline","tags":["internet protocol outline"]},{"name":"mdi:ipod","tags":["apple ipod"]},{"name":"mdi:iron-board","tags":["home automation","clothing"]},{"name":"mdi:island","tags":["places"]},{"name":"mdi:iv-bag","tags":["medical / hospital"]},{"name":"mdi:jeepney","tags":["transportation + road"]},{"name":"mdi:jellyfish","tags":["animal"]},{"name":"mdi:jellyfish-outline","tags":["animal"]},{"name":"mdi:jump-rope","tags":["sport"]},{"name":"mdi:kangaroo","tags":["animal","marsupial"]},{"name":"mdi:keg","tags":["food / drink"]},{"name":"mdi:kettle","tags":["home automation","food / drink","tea kettle","kettle full","tea kettle full"]},{"name":"mdi:kettle-alert","tags":["home automation","alert / error","food / drink","tea kettle alert","kettle full alert","tea kettle full alert"]},{"name":"mdi:kettle-alert-outline","tags":["home automation","alert / error","food / drink","tea kettle alert outline","kettle empty alert","tea kettle empty alert"]},{"name":"mdi:kettle-off","tags":["home automation","food / drink","tea kettle off","tea kettle full off","kettle full off"]},{"name":"mdi:kettle-off-outline","tags":["home automation","food / drink","tea kettle off outline","kettle empty off","tea kettle empty off"]},{"name":"mdi:kettle-outline","tags":["food / drink","home automation","tea kettle outline","kettle empty","tea kettle empty"]},{"name":"mdi:kettle-pour-over","tags":[]},{"name":"mdi:kettle-steam","tags":["home automation","food / drink","tea kettle steam","kettle full steam","tea kettle full steam"]},{"name":"mdi:kettle-steam-outline","tags":["home automation","food / drink","tea kettle steam outline","kettle empty steam","tea kettle empty steam"]},{"name":"mdi:kettlebell","tags":["sport"]},{"name":"mdi:key-alert","tags":["alert / error"]},{"name":"mdi:key-alert-outline","tags":["alert / error"]},{"name":"mdi:key-arrow-right","tags":[]},{"name":"mdi:key-chain","tags":["automotive","home automation"]},{"name":"mdi:key-chain-variant","tags":["automotive","home automation"]},{"name":"mdi:key-change","tags":[]},{"name":"mdi:key-link","tags":["foreign key","sql foreign key"]},{"name":"mdi:key-minus","tags":[]},{"name":"mdi:key-plus","tags":["key add"]},{"name":"mdi:key-remove","tags":[]},{"name":"mdi:key-star","tags":["primary key","sql primary key","key favorite"]},{"name":"mdi:key-variant","tags":["automotive"]},{"name":"mdi:key-wireless","tags":[]},{"name":"mdi:keyboard-close-outline","tags":["keyboard hide outline"]},{"name":"mdi:keyboard-esc","tags":[]},{"name":"mdi:keyboard-f1","tags":[]},{"name":"mdi:keyboard-f10","tags":[]},{"name":"mdi:keyboard-f11","tags":[]},{"name":"mdi:keyboard-f12","tags":[]},{"name":"mdi:keyboard-f2","tags":[]},{"name":"mdi:keyboard-f3","tags":[]},{"name":"mdi:keyboard-f4","tags":[]},{"name":"mdi:keyboard-f5","tags":[]},{"name":"mdi:keyboard-f6","tags":[]},{"name":"mdi:keyboard-f7","tags":[]},{"name":"mdi:keyboard-f8","tags":[]},{"name":"mdi:keyboard-f9","tags":[]},{"name":"mdi:keyboard-off","tags":[]},{"name":"mdi:keyboard-off-outline","tags":[]},{"name":"mdi:keyboard-settings","tags":["settings"]},{"name":"mdi:keyboard-settings-outline","tags":["settings"]},{"name":"mdi:keyboard-space","tags":[]},{"name":"mdi:keyboard-tab-reverse","tags":[]},{"name":"mdi:keyboard-variant","tags":[]},{"name":"mdi:khanda","tags":["religion","sikh"]},{"name":"mdi:klingon","tags":[]},{"name":"mdi:knife","tags":["silverware knife","cutlery knife"]},{"name":"mdi:knife-military","tags":["gaming / rpg","dagger"]},{"name":"mdi:knob","tags":["audio","volume knob","volume control","dial","tuner","switch","adjuster"]},{"name":"mdi:koala","tags":["animal","marsupial","emoji koala","emoticon koala"]},{"name":"mdi:label-multiple","tags":[]},{"name":"mdi:label-multiple-outline","tags":[]},{"name":"mdi:label-percent","tags":[]},{"name":"mdi:label-percent-outline","tags":[]},{"name":"mdi:ladder","tags":["hardware / tools"]},{"name":"mdi:lambda","tags":["gaming / rpg","math"]},{"name":"mdi:lamp","tags":["home automation"]},{"name":"mdi:lamp-outline","tags":["home automation"]},{"name":"mdi:lamps","tags":["home automation","lights"]},{"name":"mdi:lamps-outline","tags":["home automation","lights outline"]},{"name":"mdi:lan","tags":["local area network"]},{"name":"mdi:lan-check","tags":[]},{"name":"mdi:lan-connect","tags":["local area network connect"]},{"name":"mdi:lan-disconnect","tags":["local area network disconnect"]},{"name":"mdi:lan-pending","tags":["local area network pending"]},{"name":"mdi:land-fields","tags":["agriculture"]},{"name":"mdi:land-plots","tags":["agriculture"]},{"name":"mdi:land-plots-circle","tags":["agriculture"]},{"name":"mdi:land-plots-circle-variant","tags":["agriculture"]},{"name":"mdi:land-plots-marker","tags":["agriculture"]},{"name":"mdi:land-rows-horizontal","tags":["agriculture"]},{"name":"mdi:land-rows-vertical","tags":["agriculture"]},{"name":"mdi:laptop-account","tags":["account / user","device / tech","teleconference","virtual meeting","video chat"]},{"name":"mdi:laptop-off","tags":["device / tech"]},{"name":"mdi:lasso","tags":[]},{"name":"mdi:latitude","tags":["navigation","geographic information system"]},{"name":"mdi:lava-lamp","tags":["home automation"]},{"name":"mdi:layers-edit","tags":["geographic information system","edit / modify"]},{"name":"mdi:layers-minus","tags":["geographic information system"]},{"name":"mdi:layers-plus","tags":["geographic information system"]},{"name":"mdi:layers-remove","tags":["geographic information system"]},{"name":"mdi:layers-search","tags":["geographic information system"]},{"name":"mdi:layers-search-outline","tags":["geographic information system"]},{"name":"mdi:layers-triple","tags":[]},{"name":"mdi:layers-triple-outline","tags":[]},{"name":"mdi:leaf","tags":["nature","food / drink","agriculture"]},{"name":"mdi:leaf-circle","tags":["nature","agriculture","green circle","organic"]},{"name":"mdi:leaf-circle-outline","tags":["agriculture","nature","green circle outline","organic outline"]},{"name":"mdi:leaf-maple","tags":["nature"]},{"name":"mdi:leaf-maple-off","tags":["nature"]},{"name":"mdi:leaf-off","tags":["nature","food / drink","agriculture"]},{"name":"mdi:lectern","tags":["podium","dais","rostrum","lecturn"]},{"name":"mdi:led-off","tags":["home automation"]},{"name":"mdi:led-on","tags":["home automation"]},{"name":"mdi:led-outline","tags":["home automation"]},{"name":"mdi:led-strip","tags":["home automation","light strip"]},{"name":"mdi:led-strip-variant","tags":["home automation","light strip variant"]},{"name":"mdi:led-strip-variant-off","tags":["home automation","light strip variant off"]},{"name":"mdi:led-variant-off","tags":["home automation"]},{"name":"mdi:led-variant-on","tags":["home automation"]},{"name":"mdi:led-variant-outline","tags":["home automation"]},{"name":"mdi:leek","tags":["food / drink"]},{"name":"mdi:less-than","tags":["math"]},{"name":"mdi:less-than-or-equal","tags":["math"]},{"name":"mdi:library-outline","tags":["places","local library outline"]},{"name":"mdi:lifebuoy","tags":["transportation + water","life preserver","support","help","overboard"]},{"name":"mdi:light-flood-down","tags":["home automation","floodlight down"]},{"name":"mdi:light-flood-up","tags":["home automation","floodlight up"]},{"name":"mdi:light-recessed","tags":["home automation","can light","pot light","high hat light","hi hat light","downlight"]},{"name":"mdi:light-switch","tags":["home automation","toggle switch","rocker switch"]},{"name":"mdi:light-switch-off","tags":["home automation","toggle switch off","rocker switch off"]},{"name":"mdi:lightbulb-alert","tags":["home automation","alert / error","lightbulb error"]},{"name":"mdi:lightbulb-alert-outline","tags":["home automation","alert / error","lightbulb error outline"]},{"name":"mdi:lightbulb-auto","tags":["home automation","lightbulb automatic","lightbulb motion"]},{"name":"mdi:lightbulb-auto-outline","tags":["home automation","lightbulb automatic outline","lightbulb motion outline"]},{"name":"mdi:lightbulb-cfl","tags":["home automation","bulb cfl"]},{"name":"mdi:lightbulb-cfl-off","tags":["home automation","bulb cfl off"]},{"name":"mdi:lightbulb-cfl-spiral","tags":["home automation","bulb cfl spiral"]},{"name":"mdi:lightbulb-cfl-spiral-off","tags":["home automation","bulb cfl spiral off"]},{"name":"mdi:lightbulb-fluorescent-tube","tags":["home automation"]},{"name":"mdi:lightbulb-fluorescent-tube-outline","tags":["home automation"]},{"name":"mdi:lightbulb-group","tags":["home automation","bulb group"]},{"name":"mdi:lightbulb-group-off","tags":["home automation","bulb group off"]},{"name":"mdi:lightbulb-group-off-outline","tags":["home automation","bulb group off outline"]},{"name":"mdi:lightbulb-group-outline","tags":["home automation","bulb group outline"]},{"name":"mdi:lightbulb-multiple","tags":["home automation","lightbulbs","bulb multiple","bulbs"]},{"name":"mdi:lightbulb-multiple-off","tags":["home automation","lightbulbs off","bulb multiple off","bulbs off"]},{"name":"mdi:lightbulb-multiple-off-outline","tags":["home automation","lightbulbs off outline","bulb multiple off outline","bulbs off outline"]},{"name":"mdi:lightbulb-multiple-outline","tags":["home automation","lightbulbs outline","bulb multiple outline","bulbs outline"]},{"name":"mdi:lightbulb-night","tags":["home automation","night light","nite light","lightbulb moon star"]},{"name":"mdi:lightbulb-night-outline","tags":["home automation","night light outline","nite light outline","lightbulb moon star outline"]},{"name":"mdi:lightbulb-off","tags":["home automation","bulb off"]},{"name":"mdi:lightbulb-off-outline","tags":["home automation","bulb off outline"]},{"name":"mdi:lightbulb-on","tags":["home automation","idea","bulb on","lightbulb dimmer 100"]},{"name":"mdi:lightbulb-on-10","tags":["home automation","lightbulb dimmer 10"]},{"name":"mdi:lightbulb-on-20","tags":["home automation","lightbulb dimmer 20"]},{"name":"mdi:lightbulb-on-30","tags":["home automation","lightbulb dimmer 30"]},{"name":"mdi:lightbulb-on-40","tags":["home automation","lightbulb dimmer 40"]},{"name":"mdi:lightbulb-on-50","tags":["home automation","lightbulb dimmer 50"]},{"name":"mdi:lightbulb-on-60","tags":["home automation","lightbulb dimmer 60"]},{"name":"mdi:lightbulb-on-70","tags":["home automation","lightbulb dimmer 70"]},{"name":"mdi:lightbulb-on-80","tags":["home automation","lightbulb dimmer 80"]},{"name":"mdi:lightbulb-on-90","tags":["home automation","lightbulb dimmer 90"]},{"name":"mdi:lightbulb-on-outline","tags":["home automation","idea","bulb on outline"]},{"name":"mdi:lightbulb-outline","tags":["home automation","idea","bulb outline"]},{"name":"mdi:lightbulb-question","tags":["home automation","lightbulb help"]},{"name":"mdi:lightbulb-question-outline","tags":["home automation","lightbulb help outline"]},{"name":"mdi:lightbulb-spot","tags":["home automation","lightbulb halogen","lightbulb gu10"]},{"name":"mdi:lightbulb-spot-off","tags":["home automation","lightbulb halogen off","lightbulb gu10 off"]},{"name":"mdi:lightbulb-variant","tags":["home automation","lightbulb edison","lightbulb filament"]},{"name":"mdi:lightbulb-variant-outline","tags":["home automation","lightbulb edison outline","lightbulb filament outline"]},{"name":"mdi:lighthouse","tags":["beacon"]},{"name":"mdi:lighthouse-on","tags":["beacon"]},{"name":"mdi:lightning-bolt","tags":["home automation","weather","thunder","storm","energy","electricity"]},{"name":"mdi:lightning-bolt-outline","tags":["home automation","weather","thunder outline","storm outline","energy outline","electricity outline"]},{"name":"mdi:line-scan","tags":[]},{"name":"mdi:lingerie","tags":["clothing","underwear","bra","panties"]},{"name":"mdi:link-box","tags":[]},{"name":"mdi:link-box-outline","tags":[]},{"name":"mdi:link-box-variant","tags":[]},{"name":"mdi:link-box-variant-outline","tags":[]},{"name":"mdi:link-lock","tags":["lock","block chain"]},{"name":"mdi:link-variant","tags":[]},{"name":"mdi:link-variant-minus","tags":[]},{"name":"mdi:link-variant-off","tags":[]},{"name":"mdi:link-variant-plus","tags":[]},{"name":"mdi:link-variant-remove","tags":[]},{"name":"mdi:lipstick","tags":["health / beauty"]},{"name":"mdi:liquid-spot","tags":["automotive","medical / hospital","ink spot","puddle","water","blood","spill","oil","dirty"]},{"name":"mdi:list-box","tags":["form"]},{"name":"mdi:list-box-outline","tags":["form outline"]},{"name":"mdi:loading","tags":[]},{"name":"mdi:location-enter","tags":["home automation","presence enter"]},{"name":"mdi:location-exit","tags":["home automation","presence exit"]},{"name":"mdi:lock-alert","tags":["lock","alert / error","home automation","lock warning","password alert","encryption alert","password warning","encryption warning"]},{"name":"mdi:lock-alert-outline","tags":["home automation","alert / error","lock","lock warning outline","password alert outline","encryption alert outline","password warning outline","encryption warning outline"]},{"name":"mdi:lock-check","tags":["lock","password check","password secure","encryption check","encryption secure","password verified","encryption verified"]},{"name":"mdi:lock-check-outline","tags":["lock","password check outline","password secure outline","encryption check outline","encryption secure outline","password verified outline","encryption verified outline"]},{"name":"mdi:lock-minus","tags":["lock","password minus","encryption minus"]},{"name":"mdi:lock-minus-outline","tags":["lock","password minus outline","encryption minus"]},{"name":"mdi:lock-off","tags":["lock","password off","not protected","unsecure","encryption off"]},{"name":"mdi:lock-off-outline","tags":["lock","password off outline","unsecure outline","not protected outline","encryption off outline"]},{"name":"mdi:lock-open-alert","tags":["alert / error","home automation","lock","unlocked alert","decrypted alert","lock open warning","unlocked warning","decrypted warning"]},{"name":"mdi:lock-open-alert-outline","tags":["home automation","alert / error","lock","unlocked alert outline","lock open warning outline","decrypted alert outline","unlocked warning outline","decrypted warning outline"]},{"name":"mdi:lock-open-check","tags":["lock","unlocked check","decrypted check"]},{"name":"mdi:lock-open-check-outline","tags":["lock","unlocked check outline","decrypted check outline"]},{"name":"mdi:lock-open-minus","tags":["lock","unlocked minus","decrypted minus"]},{"name":"mdi:lock-open-minus-outline","tags":["lock","unlocked minus outline","decrypted minus outline"]},{"name":"mdi:lock-open-plus","tags":["lock","unlocked plus","decrypted plus","lock open add","unlocked add","decrypted add"]},{"name":"mdi:lock-open-plus-outline","tags":["lock","unlocked plus outline","lock open add outline","unlocked add outline","decrypted plus outline","decrypted add outline"]},{"name":"mdi:lock-open-remove","tags":["lock","unlocked remove","decrypted remove"]},{"name":"mdi:lock-open-remove-outline","tags":["lock","unlocked remove outline","decrypted remove outline"]},{"name":"mdi:lock-open-variant","tags":["lock","home automation","unlocked variant","decrypted variant"]},{"name":"mdi:lock-open-variant-outline","tags":["lock","home automation","unlocked variant outline","decrypted variant outline"]},{"name":"mdi:lock-pattern","tags":[]},{"name":"mdi:lock-percent","tags":["lock rate"]},{"name":"mdi:lock-percent-open","tags":["lock rate open"]},{"name":"mdi:lock-percent-open-outline","tags":["lock rate open outline"]},{"name":"mdi:lock-percent-open-variant","tags":["lock rate open variant"]},{"name":"mdi:lock-percent-open-variant-outline","tags":["lock rate open variant outline"]},{"name":"mdi:lock-percent-outline","tags":["lock rate outline"]},{"name":"mdi:lock-plus","tags":["lock","enhanced encryption","lock add","encryption add","password add","password plus","encryption plus"]},{"name":"mdi:lock-plus-outline","tags":["lock","lock add outline","password plus outline","password add outline","encryption plus outline","encryption add outline"]},{"name":"mdi:lock-question","tags":["lock","forgot password","password question","encryption question"]},{"name":"mdi:lock-remove","tags":["lock","password remove","encryption remove"]},{"name":"mdi:lock-remove-outline","tags":["lock","password remove outline","encryption remove outline"]},{"name":"mdi:lock-smart","tags":["home automation"]},{"name":"mdi:locker","tags":[]},{"name":"mdi:locker-multiple","tags":["lockers"]},{"name":"mdi:login","tags":["log in","sign in"]},{"name":"mdi:login-variant","tags":["log in variant","sign in variant"]},{"name":"mdi:logout","tags":["log out","sign out"]},{"name":"mdi:logout-variant","tags":["log out variant","sign out variant"]},{"name":"mdi:longitude","tags":["navigation","geographic information system"]},{"name":"mdi:lotion","tags":["medical / hospital","health / beauty"]},{"name":"mdi:lotion-outline","tags":["medical / hospital","health / beauty"]},{"name":"mdi:lungs","tags":["medical / hospital"]},{"name":"mdi:mace","tags":["gaming / rpg"]},{"name":"mdi:magazine-pistol","tags":["ammunition pistol"]},{"name":"mdi:magazine-rifle","tags":["ammunition rifle"]},{"name":"mdi:magic-staff","tags":["gaming / rpg","staff shimmer","magic wand"]},{"name":"mdi:magnet","tags":[]},{"name":"mdi:magnet-on","tags":[]},{"name":"mdi:magnify-close","tags":[]},{"name":"mdi:magnify-expand","tags":["geographic information system","search expand"]},{"name":"mdi:magnify-minus","tags":["zoom out","search minus"]},{"name":"mdi:magnify-minus-cursor","tags":["zoom out cursor"]},{"name":"mdi:magnify-plus","tags":["zoom in","magnify add","search plus","search add"]},{"name":"mdi:magnify-plus-cursor","tags":["zoom in cursor","magnify add cursor"]},{"name":"mdi:magnify-remove-cursor","tags":[]},{"name":"mdi:magnify-remove-outline","tags":["geographic information system"]},{"name":"mdi:magnify-scan","tags":[]},{"name":"mdi:mail","tags":[]},{"name":"mdi:mailbox","tags":[]},{"name":"mdi:mailbox-open","tags":[]},{"name":"mdi:mailbox-open-outline","tags":[]},{"name":"mdi:mailbox-open-up","tags":[]},{"name":"mdi:mailbox-open-up-outline","tags":[]},{"name":"mdi:mailbox-outline","tags":[]},{"name":"mdi:mailbox-up","tags":[]},{"name":"mdi:mailbox-up-outline","tags":[]},{"name":"mdi:map-check","tags":["navigation","geographic information system","map tick"]},{"name":"mdi:map-check-outline","tags":["navigation","geographic information system","map tick outline"]},{"name":"mdi:map-clock","tags":["navigation","geographic information system","date / time","timezone"]},{"name":"mdi:map-clock-outline","tags":["navigation","geographic information system","date / time","timezone outline"]},{"name":"mdi:map-legend","tags":["navigation","geographic information system"]},{"name":"mdi:map-marker-alert","tags":["navigation","alert / error","geographic information system","location alert","location warning"]},{"name":"mdi:map-marker-alert-outline","tags":["navigation","alert / error","geographic information system","location alert outline","location warning outline"]},{"name":"mdi:map-marker-check-outline","tags":["navigation","geographic information system","location check outline","where to vote outline"]},{"name":"mdi:map-marker-distance","tags":["navigation","geographic information system","location distance"]},{"name":"mdi:map-marker-down","tags":["navigation","geographic information system","location down"]},{"name":"mdi:map-marker-left","tags":["navigation","geographic information system","location left"]},{"name":"mdi:map-marker-left-outline","tags":["navigation","geographic information system","location left outline"]},{"name":"mdi:map-marker-minus","tags":["navigation","geographic information system","location minus"]},{"name":"mdi:map-marker-minus-outline","tags":["geographic information system","navigation","location minus outline"]},{"name":"mdi:map-marker-multiple","tags":["navigation","geographic information system","map markers","location multiple","locations"]},{"name":"mdi:map-marker-multiple-outline","tags":["navigation","geographic information system","locations outline","location multiple outline","map markers outline"]},{"name":"mdi:map-marker-off","tags":["navigation","geographic information system","location off"]},{"name":"mdi:map-marker-off-outline","tags":["navigation","geographic information system","location off outline"]},{"name":"mdi:map-marker-path","tags":["navigation","geographic information system","location path"]},{"name":"mdi:map-marker-plus","tags":["navigation","geographic information system","location plus","map marker add","location add"]},{"name":"mdi:map-marker-plus-outline","tags":["geographic information system","navigation","map marker add outline","location plus outline","location add outline"]},{"name":"mdi:map-marker-radius","tags":["navigation","geographic information system","home automation","location radius"]},{"name":"mdi:map-marker-radius-outline","tags":["navigation","geographic information system","home automation","location radius outline"]},{"name":"mdi:map-marker-remove","tags":["navigation","geographic information system","location remove"]},{"name":"mdi:map-marker-remove-outline","tags":["geographic information system","navigation","location remove outline"]},{"name":"mdi:map-marker-remove-variant","tags":["navigation","geographic information system","location remove variant outline"]},{"name":"mdi:map-marker-right","tags":["navigation","geographic information system","location right"]},{"name":"mdi:map-marker-right-outline","tags":["navigation","geographic information system","location right outline"]},{"name":"mdi:map-marker-star","tags":["navigation","map marker favorite","location star","location favorite"]},{"name":"mdi:map-marker-star-outline","tags":["navigation","map marker favorite outline","location star outline","location favorite outline"]},{"name":"mdi:map-marker-up","tags":["navigation","geographic information system","location up"]},{"name":"mdi:map-minus","tags":["navigation","geographic information system"]},{"name":"mdi:map-plus","tags":["navigation","geographic information system","map add"]},{"name":"mdi:map-search","tags":["navigation","geographic information system"]},{"name":"mdi:map-search-outline","tags":["navigation","geographic information system"]},{"name":"mdi:margin","tags":[]},{"name":"mdi:marker-cancel","tags":["text / content / format"]},{"name":"mdi:math-compass","tags":["math","drawing / art","navigation","maths compass"]},{"name":"mdi:math-cos","tags":["math","math cosine","maths cos"]},{"name":"mdi:math-integral","tags":["math"]},{"name":"mdi:math-integral-box","tags":["math"]},{"name":"mdi:math-log","tags":["math"]},{"name":"mdi:math-norm","tags":["math","developer / languages","code or","parallel"]},{"name":"mdi:math-norm-box","tags":["math","developer / languages","code or box","parallel box"]},{"name":"mdi:math-sin","tags":["math","math sine","maths sin"]},{"name":"mdi:math-tan","tags":["math","math tangent","maths tan"]},{"name":"mdi:matrix","tags":[]},{"name":"mdi:medal","tags":["gaming / rpg","sport","award"]},{"name":"mdi:medal-outline","tags":["sport"]},{"name":"mdi:medical-bag","tags":["medical / hospital","first aid kit","medicine"]},{"name":"mdi:menorah","tags":["religion","holiday","candelabrum","candelabra","candle"]},{"name":"mdi:menorah-fire","tags":["religion","holiday","menorah flame","candle flame","candelabra flame","candelabra fire","candle fire","candelabrum fire","candelabrum flame"]},{"name":"mdi:menu-down-outline","tags":["arrow","caret down outline"]},{"name":"mdi:menu-left","tags":["arrow","arrow left"]},{"name":"mdi:menu-left-outline","tags":[]},{"name":"mdi:menu-right","tags":["arrow","arrow right"]},{"name":"mdi:menu-right-outline","tags":[]},{"name":"mdi:menu-swap","tags":["arrow"]},{"name":"mdi:menu-swap-outline","tags":["arrow"]},{"name":"mdi:menu-up-outline","tags":["arrow","caret up outline"]},{"name":"mdi:message-alert-outline","tags":["alert / error","announcement outline","feedback outline","message warning outline","sms failed outline"]},{"name":"mdi:message-arrow-left","tags":[]},{"name":"mdi:message-arrow-left-outline","tags":[]},{"name":"mdi:message-arrow-right","tags":[]},{"name":"mdi:message-arrow-right-outline","tags":[]},{"name":"mdi:message-check","tags":[]},{"name":"mdi:message-check-outline","tags":[]},{"name":"mdi:message-cog","tags":["settings"]},{"name":"mdi:message-cog-outline","tags":["settings"]},{"name":"mdi:message-fast","tags":[]},{"name":"mdi:message-fast-outline","tags":[]},{"name":"mdi:message-image-outline","tags":[]},{"name":"mdi:message-lock","tags":["lock","message secure"]},{"name":"mdi:message-lock-outline","tags":["lock"]},{"name":"mdi:message-minus","tags":[]},{"name":"mdi:message-minus-outline","tags":[]},{"name":"mdi:message-off","tags":[]},{"name":"mdi:message-off-outline","tags":[]},{"name":"mdi:message-plus","tags":["message add"]},{"name":"mdi:message-plus-outline","tags":[]},{"name":"mdi:message-processing-outline","tags":[]},{"name":"mdi:message-question","tags":[]},{"name":"mdi:message-question-outline","tags":[]},{"name":"mdi:message-reply-outline","tags":[]},{"name":"mdi:message-reply-text-outline","tags":[]},{"name":"mdi:message-settings","tags":["settings"]},{"name":"mdi:message-settings-outline","tags":["settings"]},{"name":"mdi:message-star","tags":[]},{"name":"mdi:message-star-outline","tags":[]},{"name":"mdi:message-text-clock","tags":["date / time"]},{"name":"mdi:message-text-clock-outline","tags":["date / time"]},{"name":"mdi:message-text-fast","tags":[]},{"name":"mdi:message-text-fast-outline","tags":[]},{"name":"mdi:message-text-lock","tags":["lock","message text secure"]},{"name":"mdi:message-text-lock-outline","tags":["lock"]},{"name":"mdi:message-text-outline","tags":[]},{"name":"mdi:metronome","tags":["music","tempo","bpm","beats per minute"]},{"name":"mdi:metronome-tick","tags":["music","tempo tick","bpm tick","beats per minute tick"]},{"name":"mdi:micro-sd","tags":[]},{"name":"mdi:microphone-message","tags":["tts","text to speech"]},{"name":"mdi:microphone-message-off","tags":["tts off","text to speech off"]},{"name":"mdi:microphone-minus","tags":["microphone remove"]},{"name":"mdi:microphone-plus","tags":["microphone add"]},{"name":"mdi:microphone-question","tags":["audio","music","microphone help"]},{"name":"mdi:microphone-question-outline","tags":["audio","music","microphone help outline"]},{"name":"mdi:microphone-variant","tags":["music"]},{"name":"mdi:microphone-variant-off","tags":["music"]},{"name":"mdi:microscope","tags":["science"]},{"name":"mdi:microsoft-xbox-controller-battery-unknown","tags":["battery","gaming / rpg","microsoft xbox gamepad battery unknown"]},{"name":"mdi:microwave","tags":["home automation","food / drink","microwave oven"]},{"name":"mdi:microwave-off","tags":["home automation"]},{"name":"mdi:middleware","tags":["arrow"]},{"name":"mdi:middleware-outline","tags":["arrow"]},{"name":"mdi:midi-port","tags":["music"]},{"name":"mdi:mine","tags":[]},{"name":"mdi:mini-sd","tags":[]},{"name":"mdi:minidisc","tags":[]},{"name":"mdi:minus-box-multiple","tags":["form","library minus"]},{"name":"mdi:minus-box-multiple-outline","tags":["form","library minus outline"]},{"name":"mdi:minus-circle-multiple","tags":["form","coins minus"]},{"name":"mdi:minus-circle-multiple-outline","tags":["form","coins minus outline"]},{"name":"mdi:minus-circle-off","tags":["do not disturb off","remove circle off","do not enter off"]},{"name":"mdi:minus-circle-off-outline","tags":["do not disturb off outline","remove circle off outline","do not enter off outline"]},{"name":"mdi:minus-network","tags":[]},{"name":"mdi:minus-network-outline","tags":[]},{"name":"mdi:minus-thick","tags":[]},{"name":"mdi:mirror","tags":["home automation"]},{"name":"mdi:mirror-rectangle","tags":["home automation"]},{"name":"mdi:mirror-variant","tags":["home automation"]},{"name":"mdi:mixed-reality","tags":[]},{"name":"mdi:molecule","tags":["science"]},{"name":"mdi:molecule-co","tags":["home automation","science","carbon monoxide","gas co"]},{"name":"mdi:molecule-co2","tags":["science","home automation","periodic table carbon dioxide","gas co2"]},{"name":"mdi:monitor-account","tags":["account / user","device / tech","teleconference","virtual meeting","video chat"]},{"name":"mdi:monitor-arrow-down","tags":["device / tech","monitor download"]},{"name":"mdi:monitor-arrow-down-variant","tags":["device / tech","monitor download"]},{"name":"mdi:monitor-dashboard","tags":["device / tech"]},{"name":"mdi:monitor-edit","tags":["edit / modify"]},{"name":"mdi:monitor-eye","tags":[]},{"name":"mdi:monitor-lock","tags":["device / tech","lock"]},{"name":"mdi:monitor-multiple","tags":["device / tech","monitors"]},{"name":"mdi:monitor-shimmer","tags":["device / tech","monitor clean"]},{"name":"mdi:monitor-small","tags":["device / tech","monitor crt"]},{"name":"mdi:monitor-speaker","tags":["device / tech"]},{"name":"mdi:monitor-speaker-off","tags":["device / tech"]},{"name":"mdi:monitor-star","tags":["device / tech","monitor favorite"]},{"name":"mdi:monitor-vertical","tags":[]},{"name":"mdi:moon-first-quarter","tags":["weather"]},{"name":"mdi:moon-full","tags":["weather"]},{"name":"mdi:moon-last-quarter","tags":["weather"]},{"name":"mdi:moon-new","tags":["weather"]},{"name":"mdi:moon-waning-crescent","tags":["weather"]},{"name":"mdi:moon-waning-gibbous","tags":["weather"]},{"name":"mdi:moon-waxing-crescent","tags":["weather"]},{"name":"mdi:moon-waxing-gibbous","tags":["weather"]},{"name":"mdi:mortar-pestle","tags":[]},{"name":"mdi:mother-heart","tags":["people / family"]},{"name":"mdi:mother-nurse","tags":["medical / hospital","people / family","breast feed"]},{"name":"mdi:motion-sensor","tags":["home automation","motion detector"]},{"name":"mdi:motion-sensor-off","tags":["home automation"]},{"name":"mdi:motorbike-electric","tags":["transportation + road","motorcycle electric"]},{"name":"mdi:motorbike-off","tags":["transportation + road","motorcycle off"]},{"name":"mdi:mouse-bluetooth","tags":[]},{"name":"mdi:mouse-move-down","tags":[]},{"name":"mdi:mouse-move-up","tags":[]},{"name":"mdi:mouse-move-vertical","tags":[]},{"name":"mdi:mouse-off","tags":[]},{"name":"mdi:mouse-variant","tags":[]},{"name":"mdi:mouse-variant-off","tags":[]},{"name":"mdi:move-resize","tags":[]},{"name":"mdi:move-resize-variant","tags":[]},{"name":"mdi:movie-check","tags":["video / movie","slate check","clapperboard check","film check"]},{"name":"mdi:movie-check-outline","tags":["video / movie","slate check outline","clapperboard check outline","film check outline"]},{"name":"mdi:movie-cog","tags":["video / movie","settings","slate cog","clapperboard cog","film cog"]},{"name":"mdi:movie-cog-outline","tags":["video / movie","settings","slate cog outline","clapperboard cog outline","film cog outline"]},{"name":"mdi:movie-edit","tags":["video / movie","edit / modify","slate edit","clapperboard edit","film edit"]},{"name":"mdi:movie-edit-outline","tags":["video / movie","edit / modify","slate edit outline","clapperboard edit outline","film edit outline"]},{"name":"mdi:movie-minus","tags":["video / movie","slate minus","clapperboard minus","film minus"]},{"name":"mdi:movie-minus-outline","tags":["video / movie","slate minus outline","clapperboard minus outline","film minus outline"]},{"name":"mdi:movie-off","tags":["video / movie","slate off","clapperboard off","film off"]},{"name":"mdi:movie-off-outline","tags":["video / movie","slate off outline","clapperboard off outline","film off outline"]},{"name":"mdi:movie-open","tags":["video / movie","slate open","clapperboard open","film open","movie creation"]},{"name":"mdi:movie-open-check","tags":["video / movie","slate open check","clapperboard open check","film open check"]},{"name":"mdi:movie-open-check-outline","tags":["video / movie","slate open check outline","clapperboard open check outline","film open check outline"]},{"name":"mdi:movie-open-cog","tags":["video / movie","settings","slate open cog","clapperboard open cog","film open cog"]},{"name":"mdi:movie-open-cog-outline","tags":["video / movie","settings","slate open cog outline","clapperboard open cog outline","film open cog outline"]},{"name":"mdi:movie-open-edit","tags":["video / movie","edit / modify","slate open edit","clapperboard open edit","film open edit"]},{"name":"mdi:movie-open-edit-outline","tags":["video / movie","edit / modify","slate open edit outline","clapperboard open edit outline","film open edit outline"]},{"name":"mdi:movie-open-minus","tags":["video / movie","slate open minus","clapperboard open minus","film open minus"]},{"name":"mdi:movie-open-minus-outline","tags":["video / movie","slate open minus outline","clapperboard open minus outline","film open minus outline"]},{"name":"mdi:movie-open-off","tags":["video / movie","slate open off","clapperboard open off","film open off"]},{"name":"mdi:movie-open-off-outline","tags":["video / movie","slate open off outline","clapperboard open off outline","film open off outline"]},{"name":"mdi:movie-open-outline","tags":["video / movie","slate open outline","clapperboard open outline","film open outline","movie creation"]},{"name":"mdi:movie-open-play","tags":["video / movie","slate open play","clapperboard open play","film open play"]},{"name":"mdi:movie-open-play-outline","tags":["video / movie","slate open play outline","clapperboard open play outline","film open play outline"]},{"name":"mdi:movie-open-plus","tags":["video / movie","clapperboard open plus","slate open plus","flim open plus"]},{"name":"mdi:movie-open-plus-outline","tags":["video / movie","slate open plus outline","clapperboard open plus outline","film open plus outline"]},{"name":"mdi:movie-open-remove","tags":["video / movie","slate open remove","clapperboard open remove","film open remove"]},{"name":"mdi:movie-open-remove-outline","tags":["video / movie","slate open remove outline","clapperboard open remove outline","film open remove outline"]},{"name":"mdi:movie-open-settings","tags":["video / movie","settings","slate open settings","clapperboard open settings","film open settings"]},{"name":"mdi:movie-open-settings-outline","tags":["video / movie","settings","slate open settings outline","clapperboard open settings outline","film open settings outline"]},{"name":"mdi:movie-open-star","tags":["video / movie","slate open star","clapperboard open star","film open star","movie open favorite"]},{"name":"mdi:movie-open-star-outline","tags":["video / movie","slate open star outline","clapperboard open star outline","film open star outline","movie open favorite outline"]},{"name":"mdi:movie-play","tags":["video / movie","slate play","clapperboard play","film play"]},{"name":"mdi:movie-play-outline","tags":["video / movie","slate play outline","clapperboard play outline","film play outline"]},{"name":"mdi:movie-plus","tags":["video / movie","slate plus","clapperboard plus","film plus"]},{"name":"mdi:movie-plus-outline","tags":["video / movie","slate plus outline","clapperboard plus outline","film plus outline"]},{"name":"mdi:movie-remove","tags":["video / movie","slate remove","clapperboard remove","film remove"]},{"name":"mdi:movie-remove-outline","tags":["video / movie","slate remove outline","clapperboard remove outline","film remove outline"]},{"name":"mdi:movie-roll","tags":["video / movie","film reel"]},{"name":"mdi:movie-search","tags":["video / movie"]},{"name":"mdi:movie-search-outline","tags":["video / movie"]},{"name":"mdi:movie-settings","tags":["video / movie","settings","slate settings","clapperboard settings","film settings"]},{"name":"mdi:movie-settings-outline","tags":["video / movie","settings","slate settings outline","clapperboard settings outline","film settings outline"]},{"name":"mdi:movie-star","tags":["video / movie","slate star","clapperboard star","film star","movie favorite"]},{"name":"mdi:movie-star-outline","tags":["video / movie","slate star outline","clapperboard star outline","film star outline","movie favorite outline"]},{"name":"mdi:mower","tags":["hardware / tools","home automation"]},{"name":"mdi:mower-bag","tags":["hardware / tools","home automation"]},{"name":"mdi:mower-bag-on","tags":["hardware / tools","home automation"]},{"name":"mdi:mower-on","tags":["hardware / tools","home automation"]},{"name":"mdi:muffin","tags":["food / drink"]},{"name":"mdi:multicast","tags":["multiplex","broadcast"]},{"name":"mdi:multimedia","tags":["audio","video / movie","photography","audio","video","image","music","movie","picture"]},{"name":"mdi:multiplication","tags":["math"]},{"name":"mdi:multiplication-box","tags":["math"]},{"name":"mdi:mushroom","tags":["nature","food / drink","agriculture","fungus"]},{"name":"mdi:mushroom-off","tags":["food / drink","nature","agriculture"]},{"name":"mdi:mushroom-off-outline","tags":["food / drink","nature","agriculture"]},{"name":"mdi:mushroom-outline","tags":["nature","food / drink","agriculture","fungus outline"]},{"name":"mdi:music","tags":["audio","music"]},{"name":"mdi:music-accidental-double-flat","tags":["music"]},{"name":"mdi:music-accidental-double-sharp","tags":["music"]},{"name":"mdi:music-accidental-flat","tags":["music"]},{"name":"mdi:music-accidental-natural","tags":["music"]},{"name":"mdi:music-accidental-sharp","tags":["music"]},{"name":"mdi:music-box","tags":["audio","music"]},{"name":"mdi:music-box-multiple-outline","tags":["music","library music outline"]},{"name":"mdi:music-box-outline","tags":["audio","music"]},{"name":"mdi:music-circle","tags":["audio","music","note circle"]},{"name":"mdi:music-circle-outline","tags":["music","audio","note circle outline"]},{"name":"mdi:music-clef-alto","tags":["music","music c clef","music clef tenor","music clef soprano","music clef baritone"]},{"name":"mdi:music-clef-bass","tags":["music","music f clef"]},{"name":"mdi:music-clef-treble","tags":["music","music g clef"]},{"name":"mdi:music-note","tags":["audio","music"]},{"name":"mdi:music-note-bluetooth","tags":["audio","music"]},{"name":"mdi:music-note-bluetooth-off","tags":["audio","music"]},{"name":"mdi:music-note-eighth","tags":["audio","music"]},{"name":"mdi:music-note-eighth-dotted","tags":["music"]},{"name":"mdi:music-note-half","tags":["audio","music"]},{"name":"mdi:music-note-half-dotted","tags":["music"]},{"name":"mdi:music-note-minus","tags":[]},{"name":"mdi:music-note-off","tags":["audio","music"]},{"name":"mdi:music-note-off-outline","tags":["music"]},{"name":"mdi:music-note-outline","tags":["music"]},{"name":"mdi:music-note-plus","tags":["audio","music","music note add"]},{"name":"mdi:music-note-quarter","tags":["audio","music"]},{"name":"mdi:music-note-quarter-dotted","tags":["music"]},{"name":"mdi:music-note-sixteenth","tags":["audio","music"]},{"name":"mdi:music-note-sixteenth-dotted","tags":["music"]},{"name":"mdi:music-note-whole","tags":["audio","music"]},{"name":"mdi:music-note-whole-dotted","tags":["music"]},{"name":"mdi:music-off","tags":["audio","music"]},{"name":"mdi:music-rest-eighth","tags":["music"]},{"name":"mdi:music-rest-half","tags":["music"]},{"name":"mdi:music-rest-quarter","tags":["music"]},{"name":"mdi:music-rest-sixteenth","tags":["music"]},{"name":"mdi:music-rest-whole","tags":["music"]},{"name":"mdi:nail","tags":["hardware / tools"]},{"name":"mdi:nas","tags":["network attached storage"]},{"name":"mdi:nature-outline","tags":["nature"]},{"name":"mdi:nature-people-outline","tags":["account / user","nature"]},{"name":"mdi:necklace","tags":["clothing"]},{"name":"mdi:needle","tags":["medical / hospital","syringe","injection","medicine","shot","drug","immunization","pharmaceutical"]},{"name":"mdi:needle-off","tags":["medical / hospital","syringe off","injection off","medicine off","shot off","drug off","immunization off","pharmaceutical off"]},{"name":"mdi:network","tags":[]},{"name":"mdi:network-off","tags":[]},{"name":"mdi:network-off-outline","tags":[]},{"name":"mdi:network-outline","tags":[]},{"name":"mdi:network-pos","tags":["banking","network point of sale","network cash box"]},{"name":"mdi:network-strength-1","tags":["cellphone / phone"]},{"name":"mdi:network-strength-1-alert","tags":["cellphone / phone","alert / error","network strength 1 warning"]},{"name":"mdi:network-strength-2","tags":["cellphone / phone"]},{"name":"mdi:network-strength-2-alert","tags":["cellphone / phone","alert / error","network strength 2 warning"]},{"name":"mdi:network-strength-3","tags":["cellphone / phone"]},{"name":"mdi:network-strength-3-alert","tags":["cellphone / phone","alert / error","network strength 3 warning"]},{"name":"mdi:network-strength-4","tags":["cellphone / phone"]},{"name":"mdi:network-strength-4-alert","tags":["cellphone / phone","alert / error","network strength 4 warning"]},{"name":"mdi:network-strength-4-cog","tags":["settings","network strength 4 settings","data settings"]},{"name":"mdi:network-strength-off","tags":["cellphone / phone"]},{"name":"mdi:network-strength-off-outline","tags":["cellphone / phone"]},{"name":"mdi:network-strength-outline","tags":["cellphone / phone","network strength 0"]},{"name":"mdi:newspaper-check","tags":[]},{"name":"mdi:newspaper-minus","tags":[]},{"name":"mdi:newspaper-plus","tags":[]},{"name":"mdi:newspaper-remove","tags":[]},{"name":"mdi:newspaper-variant-multiple","tags":[]},{"name":"mdi:newspaper-variant-multiple-outline","tags":[]},{"name":"mdi:nfc-search-variant","tags":[]},{"name":"mdi:nfc-tap","tags":["near field communication tap"]},{"name":"mdi:nfc-variant-off","tags":["home automation","near field communication off"]},{"name":"mdi:ninja","tags":[]},{"name":"mdi:nintendo-game-boy","tags":["gaming / rpg"]},{"name":"mdi:not-equal","tags":[]},{"name":"mdi:not-equal-variant","tags":["math"]},{"name":"mdi:note","tags":["paper","sticky note","post it note"]},{"name":"mdi:note-alert","tags":["alert / error","paper alert","sticky note alert","post it note alert"]},{"name":"mdi:note-alert-outline","tags":["alert / error","paper alert outline","post it note alert outline","sticky note alert outline"]},{"name":"mdi:note-check","tags":["paper check","sticky note check","post it note check"]},{"name":"mdi:note-check-outline","tags":["paper check outline","sticky note check outline","post it note check outline"]},{"name":"mdi:note-edit","tags":["edit / modify","paper edit","sticky note edit","post it note edit"]},{"name":"mdi:note-edit-outline","tags":["edit / modify","paper edit outline","sticky note edit outline","post it note edit outline"]},{"name":"mdi:note-minus","tags":["paper minus","sticky note minus","post it note minus"]},{"name":"mdi:note-minus-outline","tags":["paper minus outline","sticky note minus outline","post it note minus outline"]},{"name":"mdi:note-multiple","tags":["notes","papers","sticky notes","post it notes"]},{"name":"mdi:note-multiple-outline","tags":["notes outline","papers outline","sticky notes outline","post it notes outline"]},{"name":"mdi:note-off","tags":["paper off","sticky note off","post it note off"]},{"name":"mdi:note-off-outline","tags":["paper off outline","sticky note off outline","post it note off outline"]},{"name":"mdi:note-outline","tags":["paper outline","sticky note outline","post it note outline"]},{"name":"mdi:note-plus","tags":["note add","paper plus","paper add","sticky note plus","sticky note add","post it note plus","post it note add"]},{"name":"mdi:note-plus-outline","tags":["note add outline","paper plus outline","paper add outline","sticky note plus outline","sticky note add outline","post it note plus outline","post it note add outline"]},{"name":"mdi:note-remove","tags":["paper remove","sticky note remove","post it note remove"]},{"name":"mdi:note-remove-outline","tags":[]},{"name":"mdi:note-search","tags":["paper search","sticky note search","post it note search"]},{"name":"mdi:note-search-outline","tags":["paper search outline","sticky note search outline","post it note search outline"]},{"name":"mdi:note-text","tags":["paper text","sticky note text","post it note text"]},{"name":"mdi:note-text-outline","tags":["paper text outline","sticky note text outline","post it note text outline"]},{"name":"mdi:notebook","tags":["journal","planner","diary"]},{"name":"mdi:notebook-check","tags":[]},{"name":"mdi:notebook-check-outline","tags":[]},{"name":"mdi:notebook-edit","tags":["edit / modify"]},{"name":"mdi:notebook-edit-outline","tags":["edit / modify"]},{"name":"mdi:notebook-heart","tags":["notebook favorite","notebook love"]},{"name":"mdi:notebook-heart-outline","tags":["notebook favorite outline","notebook love outline"]},{"name":"mdi:notebook-minus","tags":[]},{"name":"mdi:notebook-minus-outline","tags":[]},{"name":"mdi:notebook-multiple","tags":["journal multiple","planner multiple"]},{"name":"mdi:notebook-outline","tags":["journal outline","planner outline"]},{"name":"mdi:notebook-plus","tags":[]},{"name":"mdi:notebook-plus-outline","tags":[]},{"name":"mdi:notebook-remove","tags":[]},{"name":"mdi:notebook-remove-outline","tags":[]},{"name":"mdi:nuke","tags":["nuclear","atomic bomb"]},{"name":"mdi:null","tags":[]},{"name":"mdi:numeric","tags":["alpha / numeric","numbers","1 2 3","one two three","123"]},{"name":"mdi:numeric-0","tags":["alpha / numeric","number 0","numeric zero"]},{"name":"mdi:numeric-0-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-0-circle","tags":["alpha / numeric","numeric zero circle","number 0 circle","number zero circle"]},{"name":"mdi:numeric-0-circle-outline","tags":["alpha / numeric","numeric zero circle outline","number 0 circle outline","number zero circle outline"]},{"name":"mdi:numeric-1","tags":["alpha / numeric","number 1","numeric one"]},{"name":"mdi:numeric-1-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-1-circle","tags":["alpha / numeric","numeric one circle","number 1 circle","number one circle"]},{"name":"mdi:numeric-1-circle-outline","tags":["alpha / numeric","numeric one circle outline","number 1 circle outline","number one circle outline"]},{"name":"mdi:numeric-10","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-box","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-box-multiple-outline","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-box-outline","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-circle","tags":["alpha / numeric"]},{"name":"mdi:numeric-10-circle-outline","tags":["alpha / numeric"]},{"name":"mdi:numeric-2","tags":["alpha / numeric","number 2","numeric two"]},{"name":"mdi:numeric-2-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-2-circle","tags":["alpha / numeric","numeric two circle","number 2 circle","number two circle"]},{"name":"mdi:numeric-2-circle-outline","tags":["alpha / numeric","numeric two circle outline","number 2 circle outline","number two circle outline"]},{"name":"mdi:numeric-3","tags":["alpha / numeric","number 3","numeric three"]},{"name":"mdi:numeric-3-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-3-circle","tags":["alpha / numeric","numeric three circle","number 3 circle","number three circle"]},{"name":"mdi:numeric-3-circle-outline","tags":["alpha / numeric","numeric three circle outline","number 3 circle outline","number three circle outline"]},{"name":"mdi:numeric-4","tags":["alpha / numeric","number 4","numeric four"]},{"name":"mdi:numeric-4-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-4-circle","tags":["alpha / numeric","numeric four circle","number 4 circle","number four circle"]},{"name":"mdi:numeric-4-circle-outline","tags":["alpha / numeric","numeric four circle outline","number 4 circle outline","number four circle outline"]},{"name":"mdi:numeric-5","tags":["alpha / numeric","number 5","numeric five"]},{"name":"mdi:numeric-5-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-5-circle","tags":["alpha / numeric","numeric five circle","number 5 circle","number five circle"]},{"name":"mdi:numeric-5-circle-outline","tags":["alpha / numeric","numeric five circle outline","number 5 circle outline","number five circle outline"]},{"name":"mdi:numeric-6","tags":["alpha / numeric","number 6","numeric six"]},{"name":"mdi:numeric-6-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-6-circle","tags":["alpha / numeric","numeric six circle","number 6 circle","number six circle"]},{"name":"mdi:numeric-6-circle-outline","tags":["alpha / numeric","numeric six circle outline","number 6 circle outline","number six circle outline"]},{"name":"mdi:numeric-7","tags":["alpha / numeric","number 7","numeric seven"]},{"name":"mdi:numeric-7-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-7-circle","tags":["alpha / numeric","numeric seven circle","number 7 circle","number seven circle"]},{"name":"mdi:numeric-7-circle-outline","tags":["alpha / numeric","numeric seven circle outline","number 7 circle outline","number seven circle outline"]},{"name":"mdi:numeric-8","tags":["alpha / numeric","number 8","numeric eight"]},{"name":"mdi:numeric-8-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-8-circle","tags":["alpha / numeric","numeric eight circle","number 8 circle","number eight circle"]},{"name":"mdi:numeric-8-circle-outline","tags":["alpha / numeric","numeric eight circle outline","number 8 circle outline","number eight circle outline"]},{"name":"mdi:numeric-9","tags":["alpha / numeric","number 9","numeric nine"]},{"name":"mdi:numeric-9-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-9-circle","tags":["alpha / numeric","numeric nine circle","number 9 circle","number nine circle"]},{"name":"mdi:numeric-9-circle-outline","tags":["alpha / numeric","numeric nine circle outline","number 9 circle outline","number nine circle outline"]},{"name":"mdi:numeric-9-plus","tags":["alpha / numeric"]},{"name":"mdi:numeric-9-plus-box-multiple","tags":["alpha / numeric"]},{"name":"mdi:numeric-9-plus-circle","tags":["alpha / numeric","numeric nine plus circle","number 9 plus circle","number nine plus circle"]},{"name":"mdi:numeric-9-plus-circle-outline","tags":["alpha / numeric","numeric nine plus circle outline","number 9 plus circle outline","number nine plus circle outline"]},{"name":"mdi:numeric-negative-1","tags":["alpha / numeric","decrement","minus one"]},{"name":"mdi:numeric-off","tags":["alpha / numeric","numbers off","123 off","one two three off"]},{"name":"mdi:numeric-positive-1","tags":["alpha / numeric","increment","plus one"]},{"name":"mdi:nut","tags":["hardware / tools"]},{"name":"mdi:nutrition","tags":["food / drink"]},{"name":"mdi:oar","tags":[]},{"name":"mdi:ocarina","tags":["music","gaming / rpg"]},{"name":"mdi:ocr","tags":["optical character recognition"]},{"name":"mdi:octagon","tags":["shape","transportation + road","stop"]},{"name":"mdi:octagon-outline","tags":["shape","transportation + road","stop outline"]},{"name":"mdi:octagram","tags":["shape","starburst"]},{"name":"mdi:octagram-edit","tags":["shape","starburst edit"]},{"name":"mdi:octagram-edit-outline","tags":["shape","starburst edit outline"]},{"name":"mdi:octagram-minus","tags":["shape","starburst plus"]},{"name":"mdi:octagram-minus-outline","tags":["shape","starburst minus outline"]},{"name":"mdi:octagram-outline","tags":["shape","starburst outline"]},{"name":"mdi:octagram-plus","tags":["shape","starburst plus"]},{"name":"mdi:octagram-plus-outline","tags":[]},{"name":"mdi:octahedron","tags":["shape"]},{"name":"mdi:octahedron-off","tags":["shape"]},{"name":"mdi:offer","tags":[]},{"name":"mdi:office-building","tags":["places"]},{"name":"mdi:office-building-cog","tags":["settings","places","office building settings"]},{"name":"mdi:office-building-cog-outline","tags":["settings","places","office building settings outline"]},{"name":"mdi:office-building-marker","tags":["navigation","places","office building location"]},{"name":"mdi:office-building-marker-outline","tags":["navigation","places","office building location outline"]},{"name":"mdi:office-building-minus","tags":[]},{"name":"mdi:office-building-minus-outline","tags":[]},{"name":"mdi:office-building-outline","tags":["places"]},{"name":"mdi:office-building-plus","tags":[]},{"name":"mdi:office-building-plus-outline","tags":[]},{"name":"mdi:office-building-remove","tags":[]},{"name":"mdi:office-building-remove-outline","tags":[]},{"name":"mdi:oil","tags":["automotive"]},{"name":"mdi:oil-lamp","tags":["wish","genie lamp"]},{"name":"mdi:oil-level","tags":["automotive"]},{"name":"mdi:oil-temperature","tags":["automotive"]},{"name":"mdi:om","tags":["religion","religion hindu","hinduism"]},{"name":"mdi:omega","tags":["ohm","electrical resistance"]},{"name":"mdi:one-up","tags":["gaming / rpg","1up","extra life"]},{"name":"mdi:orbit","tags":["science"]},{"name":"mdi:orbit-variant","tags":["photography","camera flip"]},{"name":"mdi:order-alphabetical-ascending","tags":["text / content / format"]},{"name":"mdi:order-alphabetical-descending","tags":["text / content / format"]},{"name":"mdi:order-bool-ascending","tags":["text / content / format"]},{"name":"mdi:order-bool-ascending-variant","tags":["text / content / format","order checkbox ascending"]},{"name":"mdi:order-bool-descending","tags":["text / content / format","order checkbox descending"]},{"name":"mdi:order-bool-descending-variant","tags":["text / content / format"]},{"name":"mdi:order-numeric-ascending","tags":["text / content / format"]},{"name":"mdi:order-numeric-descending","tags":["text / content / format"]},{"name":"mdi:ornament","tags":["holiday"]},{"name":"mdi:ornament-variant","tags":["holiday"]},{"name":"mdi:outdoor-lamp","tags":["home automation","outdoor light"]},{"name":"mdi:owl","tags":["animal","holiday"]},{"name":"mdi:pac-man","tags":["gaming / rpg"]},{"name":"mdi:package","tags":["box"]},{"name":"mdi:package-check","tags":["package delivered"]},{"name":"mdi:package-up","tags":["unarchive","box up","this side up"]},{"name":"mdi:package-variant","tags":["box variant"]},{"name":"mdi:package-variant-closed","tags":["box variant closed"]},{"name":"mdi:package-variant-closed-check","tags":["package variant closed delivered"]},{"name":"mdi:package-variant-closed-minus","tags":["package variant closed subtract","box variant closed minus","box variant closed subtract"]},{"name":"mdi:package-variant-closed-plus","tags":["box variant closed plus","package variant closed add","box variant closed add"]},{"name":"mdi:package-variant-closed-remove","tags":["box variant closed remove"]},{"name":"mdi:package-variant-minus","tags":["box variant minus","package variant subtract","box variant subtract"]},{"name":"mdi:package-variant-plus","tags":["box variant plus","package variant add","box variant add"]},{"name":"mdi:package-variant-remove","tags":["box variant remove"]},{"name":"mdi:page-layout-body","tags":[]},{"name":"mdi:page-layout-footer","tags":[]},{"name":"mdi:page-layout-header","tags":[]},{"name":"mdi:page-layout-header-footer","tags":["page layout marginals"]},{"name":"mdi:page-layout-sidebar-left","tags":[]},{"name":"mdi:page-layout-sidebar-right","tags":[]},{"name":"mdi:page-next","tags":["read more"]},{"name":"mdi:page-next-outline","tags":["read more outline"]},{"name":"mdi:page-previous","tags":[]},{"name":"mdi:page-previous-outline","tags":[]},{"name":"mdi:pail","tags":["bucket"]},{"name":"mdi:pail-minus","tags":["bucket minus"]},{"name":"mdi:pail-minus-outline","tags":["bucket minus outline"]},{"name":"mdi:pail-off","tags":["bucket off"]},{"name":"mdi:pail-off-outline","tags":["bucket off outline"]},{"name":"mdi:pail-outline","tags":["bucket outline"]},{"name":"mdi:pail-plus","tags":["bucket plus"]},{"name":"mdi:pail-plus-outline","tags":["bucket plus outline"]},{"name":"mdi:pail-remove","tags":["bucket remove"]},{"name":"mdi:pail-remove-outline","tags":["bucket remove outline"]},{"name":"mdi:palette-advanced","tags":["color","drawing / art","paint"]},{"name":"mdi:palette-swatch-variant","tags":["drawing / art","color","style","paint","material"]},{"name":"mdi:palm-tree","tags":["nature"]},{"name":"mdi:pan","tags":[]},{"name":"mdi:pan-bottom-left","tags":["pan down left"]},{"name":"mdi:pan-bottom-right","tags":["pan down right"]},{"name":"mdi:pan-down","tags":[]},{"name":"mdi:pan-horizontal","tags":[]},{"name":"mdi:pan-left","tags":[]},{"name":"mdi:pan-right","tags":[]},{"name":"mdi:pan-top-left","tags":["pan up left"]},{"name":"mdi:pan-top-right","tags":["pan up right"]},{"name":"mdi:pan-up","tags":[]},{"name":"mdi:pan-vertical","tags":[]},{"name":"mdi:panda","tags":["animal","emoji panda","emoticon panda"]},{"name":"mdi:paper-cut-vertical","tags":[]},{"name":"mdi:paper-roll","tags":["home automation","printer","lavatory roll","bathroom tissue","toilet paper","kitchen roll","paper towels","receipt roll"]},{"name":"mdi:paper-roll-outline","tags":["home automation","printer","lavatory roll outline","bathroom tissue outline","kitchen roll outline","paper towels outline","toilet paper outline","receipt roll outline"]},{"name":"mdi:paperclip-check","tags":["paperclip tick","attachment check","attachment tick"]},{"name":"mdi:paperclip-lock","tags":["lock","attachment lock"]},{"name":"mdi:paperclip-minus","tags":["paperclip subtract","attachment minus","attachment subtract"]},{"name":"mdi:paperclip-off","tags":["attachment off"]},{"name":"mdi:paperclip-plus","tags":["paperclip add","attachment plus","attachment add"]},{"name":"mdi:paperclip-remove","tags":["attachment remove"]},{"name":"mdi:parachute","tags":["transportation + flying"]},{"name":"mdi:parachute-outline","tags":["transportation + flying"]},{"name":"mdi:passport","tags":[]},{"name":"mdi:passport-biometric","tags":["passport electronic"]},{"name":"mdi:patio-heater","tags":["home automation"]},{"name":"mdi:pause-box","tags":["audio","music"]},{"name":"mdi:pause-box-outline","tags":["audio","music"]},{"name":"mdi:pause-octagon","tags":["stop pause"]},{"name":"mdi:pause-octagon-outline","tags":["stop pause outline"]},{"name":"mdi:paw","tags":["animal","nature","pets"]},{"name":"mdi:paw-off","tags":["animal"]},{"name":"mdi:paw-off-outline","tags":["animal"]},{"name":"mdi:paw-outline","tags":["animal"]},{"name":"mdi:peace","tags":[]},{"name":"mdi:peanut","tags":["food / drink","agriculture","allergen","food allergy"]},{"name":"mdi:peanut-off","tags":["food / drink","agriculture","allergen off","food allergy off"]},{"name":"mdi:peanut-off-outline","tags":["food / drink","agriculture","allergen off outline","food allergy off outline"]},{"name":"mdi:peanut-outline","tags":["food / drink","agriculture","allergen outline","food allergy outline"]},{"name":"mdi:pen","tags":["drawing / art"]},{"name":"mdi:pen-lock","tags":["lock"]},{"name":"mdi:pen-minus","tags":[]},{"name":"mdi:pen-off","tags":[]},{"name":"mdi:pen-plus","tags":["pen add"]},{"name":"mdi:pen-remove","tags":[]},{"name":"mdi:pencil-box","tags":["drawing / art","edit box"]},{"name":"mdi:pencil-box-multiple","tags":["edit / modify","library edit"]},{"name":"mdi:pencil-box-multiple-outline","tags":["edit / modify","library edit outline"]},{"name":"mdi:pencil-box-outline","tags":["drawing / art","edit box outline"]},{"name":"mdi:pencil-circle","tags":["drawing / art","edit circle"]},{"name":"mdi:pencil-circle-outline","tags":["drawing / art","edit circle outline"]},{"name":"mdi:pencil-lock","tags":["lock"]},{"name":"mdi:pencil-lock-outline","tags":["lock"]},{"name":"mdi:pencil-minus","tags":[]},{"name":"mdi:pencil-minus-outline","tags":[]},{"name":"mdi:pencil-off","tags":["edit off"]},{"name":"mdi:pencil-off-outline","tags":["edit off outline"]},{"name":"mdi:pencil-plus","tags":["pencil add"]},{"name":"mdi:pencil-plus-outline","tags":["pencil add outline"]},{"name":"mdi:pencil-remove","tags":[]},{"name":"mdi:pencil-remove-outline","tags":[]},{"name":"mdi:pencil-ruler","tags":["drawing / art","design"]},{"name":"mdi:pencil-ruler-outline","tags":["drawing / art"]},{"name":"mdi:penguin","tags":["animal","emoji penguin","emoticon penguin","linux"]},{"name":"mdi:pentagon","tags":["shape"]},{"name":"mdi:pentagon-outline","tags":["shape"]},{"name":"mdi:pentagram","tags":[]},{"name":"mdi:percent","tags":["math","shopping","discount","sale"]},{"name":"mdi:percent-box","tags":["math","shopping","discount box","sale box"]},{"name":"mdi:percent-box-outline","tags":["math","shopping","discount box outline","sale box outline"]},{"name":"mdi:percent-circle","tags":["math","shopping","discount circle","sale circle"]},{"name":"mdi:percent-circle-outline","tags":["math","shopping","discount circle outline","sale circle outline"]},{"name":"mdi:percent-outline","tags":["math","shopping","discount outline","sale outline"]},{"name":"mdi:periodic-table","tags":["science"]},{"name":"mdi:perspective-less","tags":["math","perspective decrease"]},{"name":"mdi:perspective-more","tags":["math","perspective increase"]},{"name":"mdi:ph","tags":["science","home automation","acid","base","potential of hydrogen","power of hydrogen"]},{"name":"mdi:phone-alert","tags":["cellphone / phone","alert / error"]},{"name":"mdi:phone-alert-outline","tags":["cellphone / phone","alert / error"]},{"name":"mdi:phone-cancel","tags":["cellphone / phone","phone block"]},{"name":"mdi:phone-cancel-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-check","tags":["cellphone / phone"]},{"name":"mdi:phone-check-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-classic","tags":["cellphone / phone"]},{"name":"mdi:phone-classic-off","tags":[]},{"name":"mdi:phone-clock","tags":["cellphone / phone","date / time","phone schedule","phone time"]},{"name":"mdi:phone-dial","tags":["cellphone / phone","phone keypad"]},{"name":"mdi:phone-dial-outline","tags":["cellphone / phone","phone keypad outline"]},{"name":"mdi:phone-incoming","tags":["cellphone / phone","telephone incoming"]},{"name":"mdi:phone-incoming-outgoing","tags":["cellphone / phone"]},{"name":"mdi:phone-incoming-outgoing-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-log","tags":["cellphone / phone"]},{"name":"mdi:phone-log-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-off","tags":["cellphone / phone"]},{"name":"mdi:phone-outgoing","tags":["cellphone / phone"]},{"name":"mdi:phone-outgoing-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-refresh","tags":["cellphone / phone","phone redial"]},{"name":"mdi:phone-refresh-outline","tags":["cellphone / phone","phone redial outline"]},{"name":"mdi:phone-remove","tags":["cellphone / phone"]},{"name":"mdi:phone-remove-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-return","tags":["cellphone / phone"]},{"name":"mdi:phone-return-outline","tags":["cellphone / phone"]},{"name":"mdi:phone-rotate-landscape","tags":["cellphone / phone"]},{"name":"mdi:phone-rotate-portrait","tags":["cellphone / phone"]},{"name":"mdi:phone-sync","tags":["cellphone / phone","phone redial"]},{"name":"mdi:phone-sync-outline","tags":["cellphone / phone","phone redial outline"]},{"name":"mdi:phone-voip","tags":["cellphone / phone"]},{"name":"mdi:pi","tags":["math"]},{"name":"mdi:pi-box","tags":["math"]},{"name":"mdi:pickaxe","tags":[]},{"name":"mdi:pier","tags":["places","transportation + water"]},{"name":"mdi:pier-crane","tags":["transportation + water","places"]},{"name":"mdi:pig","tags":["animal","agriculture","emoji pig","emoticon pig"]},{"name":"mdi:pill","tags":["medical / hospital","medicine","capsule","drug","pharmaceutical"]},{"name":"mdi:pill-multiple","tags":["medical / hospital","medicine","medication","drugs"]},{"name":"mdi:pill-off","tags":["medical / hospital","medicine off","capsule off","drug off","pharmaceutical off"]},{"name":"mdi:pillar","tags":["historic","column"]},{"name":"mdi:pin-off","tags":["keep off"]},{"name":"mdi:pin-off-outline","tags":["keep off outline"]},{"name":"mdi:pine-tree","tags":["holiday","nature","places","agriculture","forest","plant"]},{"name":"mdi:pine-tree-box","tags":["holiday","nature","agriculture","plant"]},{"name":"mdi:pine-tree-fire","tags":["nature","agriculture","wildfire","controlled burn"]},{"name":"mdi:pine-tree-variant","tags":["nature","places","agriculture"]},{"name":"mdi:pine-tree-variant-outline","tags":["places","nature","agriculture"]},{"name":"mdi:pipe","tags":["home automation"]},{"name":"mdi:pipe-disconnected","tags":["home automation"]},{"name":"mdi:pipe-leak","tags":["home automation"]},{"name":"mdi:pipe-valve","tags":["home automation"]},{"name":"mdi:pirate","tags":[]},{"name":"mdi:pistol","tags":["gun"]},{"name":"mdi:piston","tags":["automotive"]},{"name":"mdi:pitchfork","tags":["hardware / tools"]},{"name":"mdi:plane-car","tags":["transportation + flying","transportation + road","airport shuttle","airport taxi","airplane car"]},{"name":"mdi:plane-train","tags":["transportation + flying","transportation + other","airport shuttle","airplane train"]},{"name":"mdi:play-box","tags":[]},{"name":"mdi:play-box-edit-outline","tags":[]},{"name":"mdi:play-box-lock","tags":["video / movie","lock"]},{"name":"mdi:play-box-lock-open","tags":["video / movie","lock"]},{"name":"mdi:play-box-lock-open-outline","tags":["video / movie","lock"]},{"name":"mdi:play-box-lock-outline","tags":["video / movie","lock"]},{"name":"mdi:play-network","tags":["media network"]},{"name":"mdi:play-network-outline","tags":["media network outline"]},{"name":"mdi:play-outline","tags":[]},{"name":"mdi:play-pause","tags":["home automation"]},{"name":"mdi:playlist-edit","tags":["edit / modify"]},{"name":"mdi:playlist-minus","tags":[]},{"name":"mdi:pliers","tags":["hardware / tools"]},{"name":"mdi:plus-box-multiple-outline","tags":[]},{"name":"mdi:plus-circle-multiple","tags":["coins plus"]},{"name":"mdi:plus-lock","tags":["lock","plus secure"]},{"name":"mdi:plus-lock-open","tags":["lock"]},{"name":"mdi:plus-minus","tags":["math"]},{"name":"mdi:plus-minus-box","tags":["math"]},{"name":"mdi:plus-minus-variant","tags":["math"]},{"name":"mdi:plus-network","tags":["add network"]},{"name":"mdi:plus-network-outline","tags":["add network outline"]},{"name":"mdi:plus-outline","tags":[]},{"name":"mdi:plus-thick","tags":["math","add thick","add bold","plus bold"]},{"name":"mdi:podium","tags":["sport"]},{"name":"mdi:podium-bronze","tags":["sport","podium third"]},{"name":"mdi:podium-gold","tags":["sport","podium first"]},{"name":"mdi:podium-silver","tags":["sport","podium second"]},{"name":"mdi:point-of-sale","tags":[]},{"name":"mdi:pokeball","tags":["gaming / rpg"]},{"name":"mdi:poker-chip","tags":["gaming / rpg","casino chip","gambling chip"]},{"name":"mdi:polaroid","tags":[]},{"name":"mdi:police-badge","tags":[]},{"name":"mdi:police-badge-outline","tags":[]},{"name":"mdi:police-station","tags":["places"]},{"name":"mdi:poll","tags":["bar chart","report","performance","analytics"]},{"name":"mdi:pool","tags":["places","home automation","swimming pool"]},{"name":"mdi:pool-thermometer","tags":["home automation","pool temperature"]},{"name":"mdi:popcorn","tags":["food / drink"]},{"name":"mdi:post-lamp","tags":["home automation","post light"]},{"name":"mdi:post-outline","tags":["blog outline"]},{"name":"mdi:postage-stamp","tags":[]},{"name":"mdi:pot","tags":["food / drink","holiday"]},{"name":"mdi:pot-mix","tags":["food / drink","holiday"]},{"name":"mdi:pot-mix-outline","tags":["food / drink","holiday"]},{"name":"mdi:pot-outline","tags":["food / drink","holiday"]},{"name":"mdi:pot-steam","tags":["food / drink","holiday"]},{"name":"mdi:pot-steam-outline","tags":["food / drink","holiday"]},{"name":"mdi:pound","tags":["hashtag"]},{"name":"mdi:pound-box","tags":["hashtag box"]},{"name":"mdi:pound-box-outline","tags":["hashtag box outline"]},{"name":"mdi:power-cycle","tags":[]},{"name":"mdi:power-off","tags":[]},{"name":"mdi:power-on","tags":[]},{"name":"mdi:power-plug-battery","tags":["home automation","battery","battery backup"]},{"name":"mdi:power-plug-battery-outline","tags":["home automation","battery","battery backup outline"]},{"name":"mdi:power-plug-off","tags":["home automation","power off"]},{"name":"mdi:power-plug-off-outline","tags":["home automation"]},{"name":"mdi:power-plug-outline","tags":["home automation"]},{"name":"mdi:power-sleep","tags":[]},{"name":"mdi:power-socket","tags":["home automation","plug socket"]},{"name":"mdi:power-socket-au","tags":["home automation","plug socket au","power socket type i","power socket cn","power socket ar","power socket nz","power socket pg","power socket australia","power socket china","power socket argentina","power socket new zealand","power socket papua new guinea"]},{"name":"mdi:power-socket-ch","tags":["home automation","plug socket ch","power socket type j","plug socket type j","power socket switzerland","plug socket switzerland"]},{"name":"mdi:power-socket-de","tags":["home automation"]},{"name":"mdi:power-socket-eu","tags":["home automation","plug socket eu","power socket europe"]},{"name":"mdi:power-socket-fr","tags":["home automation"]},{"name":"mdi:power-socket-it","tags":[]},{"name":"mdi:power-socket-jp","tags":["home automation"]},{"name":"mdi:power-socket-uk","tags":["home automation","plug socket uk","power socket type g","power socket ie","power socket hk","power socket my","power socket cy","power socket mt","power socket sg","power socket united kingdom","power socket ireland","power socket hong kong","power socket malaysia","power socket cyprus","power socket malta","power socket singapore"]},{"name":"mdi:power-socket-us","tags":["home automation","plug socket us","power socket ca","power socket mx","power socket type b","power socket united states","power socket japan","power socket canada","power socket mexico"]},{"name":"mdi:power-standby","tags":[]},{"name":"mdi:powershell","tags":[]},{"name":"mdi:prescription","tags":["medical / hospital"]},{"name":"mdi:presentation","tags":[]},{"name":"mdi:presentation-play","tags":[]},{"name":"mdi:pretzel","tags":["food / drink"]},{"name":"mdi:printer-3d","tags":["printer","home automation"]},{"name":"mdi:printer-3d-nozzle","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-alert","tags":["alert / error","printer"]},{"name":"mdi:printer-3d-nozzle-alert-outline","tags":["alert / error","printer"]},{"name":"mdi:printer-3d-nozzle-heat","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-heat-outline","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-off","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-off-outline","tags":["printer"]},{"name":"mdi:printer-3d-nozzle-outline","tags":["printer"]},{"name":"mdi:printer-3d-off","tags":["printer"]},{"name":"mdi:printer-alert","tags":["printer","home automation","alert / error","printer warning","paper jam"]},{"name":"mdi:printer-check","tags":["printer"]},{"name":"mdi:printer-eye","tags":["printer","printer preview","printer view"]},{"name":"mdi:printer-off","tags":["printer"]},{"name":"mdi:printer-pos","tags":["printer","printer point of sale","printer receipt"]},{"name":"mdi:printer-pos-alert","tags":["alert / error","printer","printer point of sale alert","printer receipt alert"]},{"name":"mdi:printer-pos-alert-outline","tags":["printer","alert / error","printer point of sale alert outline","printer receipt alert outline"]},{"name":"mdi:printer-pos-cancel","tags":["printer","printer point of sale cancel","printer receipt cancel"]},{"name":"mdi:printer-pos-cancel-outline","tags":["printer","printer point of sale cancel outline","printer receipt cancel outline"]},{"name":"mdi:printer-pos-check","tags":["printer","printer point of sale check","printer receipt check"]},{"name":"mdi:printer-pos-check-outline","tags":["printer","printer point of sale check outline","printer receipt check outline"]},{"name":"mdi:printer-pos-cog","tags":["printer","printer point of sale cog","printer receipt cog"]},{"name":"mdi:printer-pos-cog-outline","tags":["printer","printer point of sale cog outline","printer receipt cog outline"]},{"name":"mdi:printer-pos-edit","tags":["printer","printer point of sale edit","printer receipt edit"]},{"name":"mdi:printer-pos-edit-outline","tags":["printer","printer point of sale edit outline","printer receipt edit outline"]},{"name":"mdi:printer-pos-minus","tags":["printer","printer point of sale minus","printer receipt minus"]},{"name":"mdi:printer-pos-minus-outline","tags":["printer","printer point of sale minus outline","printer receipt minus outline"]},{"name":"mdi:printer-pos-network","tags":["printer","printer point of sale network","printer receipt network"]},{"name":"mdi:printer-pos-network-outline","tags":["printer","printer point of sale network outline","printer receipt network outline"]},{"name":"mdi:printer-pos-off","tags":["printer","printer point of sale off","printer receipt off"]},{"name":"mdi:printer-pos-off-outline","tags":["printer","printer point of sale off outline","printer receipt off outline"]},{"name":"mdi:printer-pos-outline","tags":["printer","printer point of sale outline","printer receipt outline"]},{"name":"mdi:printer-pos-pause","tags":["printer","printer point of sale pause","printer receipt pause"]},{"name":"mdi:printer-pos-pause-outline","tags":["printer","printer point of sale pause outline","printer receipt pause outline"]},{"name":"mdi:printer-pos-play","tags":["printer","printer point of sale play","printer receipt play"]},{"name":"mdi:printer-pos-play-outline","tags":["printer","printer point of sale play outline","printer receipt play outline"]},{"name":"mdi:printer-pos-plus","tags":["printer","printer point of sale plus","printer receipt plus"]},{"name":"mdi:printer-pos-plus-outline","tags":["printer","printer point of sale plus outline","printer receipt plus outline"]},{"name":"mdi:printer-pos-refresh","tags":["printer","printer point of sale refresh","printer receipt refresh"]},{"name":"mdi:printer-pos-refresh-outline","tags":["printer","printer point of sale refresh outline","printer receipt refresh outline"]},{"name":"mdi:printer-pos-remove","tags":["printer","printer point of sale remove","printer receipt remove"]},{"name":"mdi:printer-pos-remove-outline","tags":["printer","printer point of sale remove outline","printer receipt remove outline"]},{"name":"mdi:printer-pos-star","tags":["printer","printer point of sale star","printer receipt star","printer favorite","printer primary"]},{"name":"mdi:printer-pos-star-outline","tags":["printer","printer point of sale star outline","printer receipt star outline"]},{"name":"mdi:printer-pos-stop","tags":["printer","printer point of sale stop","printer receipt stop"]},{"name":"mdi:printer-pos-stop-outline","tags":["printer","printer point of sale stop outline","printer receipt stop outline"]},{"name":"mdi:printer-pos-sync","tags":["printer","printer point of sale sync","printer receipt sync"]},{"name":"mdi:printer-pos-sync-outline","tags":["printer","printer point of sale sync outline","printer receipt sync outline"]},{"name":"mdi:printer-pos-wrench","tags":["printer","printer point of sale wrench","printer receipt wrench"]},{"name":"mdi:printer-pos-wrench-outline","tags":["printer","printer point of sale wrench outline","printer receipt wrench outline"]},{"name":"mdi:printer-search","tags":["printer","printer preview","printer magnify"]},{"name":"mdi:printer-settings","tags":["settings","printer"]},{"name":"mdi:printer-wireless","tags":["printer"]},{"name":"mdi:professional-hexagon","tags":[]},{"name":"mdi:progress-alert","tags":["alert / error","progress warning"]},{"name":"mdi:progress-check","tags":["progress tick"]},{"name":"mdi:progress-clock","tags":["date / time"]},{"name":"mdi:progress-close","tags":[]},{"name":"mdi:progress-download","tags":[]},{"name":"mdi:progress-helper","tags":[]},{"name":"mdi:progress-pencil","tags":[]},{"name":"mdi:progress-question","tags":[]},{"name":"mdi:progress-star","tags":[]},{"name":"mdi:progress-star-four-points","tags":["progress auto"]},{"name":"mdi:progress-upload","tags":[]},{"name":"mdi:progress-wrench","tags":["hardware / tools","progress spanner"]},{"name":"mdi:projector","tags":["device / tech","home automation"]},{"name":"mdi:projector-off","tags":["device / tech","home automation"]},{"name":"mdi:projector-screen","tags":["device / tech","home automation"]},{"name":"mdi:projector-screen-off","tags":["home automation"]},{"name":"mdi:projector-screen-off-outline","tags":["home automation"]},{"name":"mdi:projector-screen-outline","tags":["home automation"]},{"name":"mdi:projector-screen-variant","tags":["home automation"]},{"name":"mdi:projector-screen-variant-off","tags":["home automation"]},{"name":"mdi:projector-screen-variant-off-outline","tags":["home automation"]},{"name":"mdi:projector-screen-variant-outline","tags":["home automation"]},{"name":"mdi:protocol","tags":[]},{"name":"mdi:publish-off","tags":["arrow","publish disabled"]},{"name":"mdi:pulse","tags":["medical / hospital","vitals"]},{"name":"mdi:pump","tags":[]},{"name":"mdi:pump-off","tags":[]},{"name":"mdi:pumpkin","tags":["holiday"]},{"name":"mdi:purse","tags":[]},{"name":"mdi:purse-outline","tags":[]},{"name":"mdi:puzzle-check","tags":["gaming / rpg"]},{"name":"mdi:puzzle-check-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-edit","tags":["gaming / rpg","edit / modify"]},{"name":"mdi:puzzle-edit-outline","tags":["gaming / rpg","edit / modify"]},{"name":"mdi:puzzle-heart","tags":["gaming / rpg"]},{"name":"mdi:puzzle-heart-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-minus","tags":["gaming / rpg"]},{"name":"mdi:puzzle-minus-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-plus","tags":["gaming / rpg"]},{"name":"mdi:puzzle-plus-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-remove","tags":["gaming / rpg"]},{"name":"mdi:puzzle-remove-outline","tags":["gaming / rpg"]},{"name":"mdi:puzzle-star","tags":["gaming / rpg","puzzle favorite"]},{"name":"mdi:puzzle-star-outline","tags":["gaming / rpg","puzzle favorite outline"]},{"name":"mdi:pyramid","tags":["shape"]},{"name":"mdi:pyramid-off","tags":["shape"]},{"name":"mdi:qrcode","tags":[]},{"name":"mdi:qrcode-edit","tags":["edit / modify"]},{"name":"mdi:qrcode-minus","tags":[]},{"name":"mdi:qrcode-plus","tags":[]},{"name":"mdi:qrcode-remove","tags":[]},{"name":"mdi:qrcode-scan","tags":[]},{"name":"mdi:quadcopter","tags":["drone"]},{"name":"mdi:quality-low","tags":["low quality","lq"]},{"name":"mdi:quality-medium","tags":["medium quality","mq"]},{"name":"mdi:quora","tags":[]},{"name":"mdi:rabbit","tags":["animal","nature","bunny","hare"]},{"name":"mdi:radiator","tags":["home automation","heater"]},{"name":"mdi:radiator-disabled","tags":["home automation","heater disabled"]},{"name":"mdi:radiator-off","tags":["home automation","heater off"]},{"name":"mdi:radio-am","tags":["audio"]},{"name":"mdi:radio-fm","tags":["audio"]},{"name":"mdi:radio-handheld","tags":["device / tech"]},{"name":"mdi:radio-off","tags":[]},{"name":"mdi:radio-tower","tags":[]},{"name":"mdi:radioactive","tags":["science","radiation"]},{"name":"mdi:radioactive-circle","tags":["science","radiation circle"]},{"name":"mdi:radioactive-circle-outline","tags":["science","radiation circle outline"]},{"name":"mdi:radioactive-off","tags":["science","radiation off"]},{"name":"mdi:radiobox-indeterminate-variant","tags":["form","radio button indeterminate","radiobox intermediate variant"]},{"name":"mdi:radiology-box","tags":["medical / hospital","x ray box"]},{"name":"mdi:radiology-box-outline","tags":["medical / hospital","x ray box outline"]},{"name":"mdi:radius","tags":["math","circle radius","sphere radius"]},{"name":"mdi:radius-outline","tags":["math","circle radius outline","sphere radius outline"]},{"name":"mdi:railroad-light","tags":["transportation + other","railroad crossing light","train crossing light","level crossing signals"]},{"name":"mdi:rake","tags":["hardware / tools"]},{"name":"mdi:raspberry-pi","tags":["raspberrypi"]},{"name":"mdi:ray-end","tags":[]},{"name":"mdi:ray-end-arrow","tags":[]},{"name":"mdi:ray-start","tags":[]},{"name":"mdi:ray-start-arrow","tags":[]},{"name":"mdi:ray-start-end","tags":[]},{"name":"mdi:ray-vertex","tags":[]},{"name":"mdi:razor-double-edge","tags":["health / beauty","hardware / tools"]},{"name":"mdi:razor-single-edge","tags":["hardware / tools"]},{"name":"mdi:read","tags":[]},{"name":"mdi:receipt","tags":["cloth","fabric","swatch"]},{"name":"mdi:receipt-clock","tags":["receipt pending"]},{"name":"mdi:receipt-clock-outline","tags":["receipt pending"]},{"name":"mdi:receipt-outline","tags":["cloth outline","fabric outline","swatch outline"]},{"name":"mdi:receipt-send","tags":[]},{"name":"mdi:receipt-send-outline","tags":[]},{"name":"mdi:receipt-text-arrow-left","tags":["invoice arrow left","invoice receive"]},{"name":"mdi:receipt-text-arrow-left-outline","tags":["invoice arrow left outline","invoice receive outline"]},{"name":"mdi:receipt-text-arrow-right","tags":["invoice arrow right","invoice send"]},{"name":"mdi:receipt-text-arrow-right-outline","tags":["invoice arrow right outline","invoice send outline"]},{"name":"mdi:receipt-text-check","tags":["invoice check"]},{"name":"mdi:receipt-text-check-outline","tags":["invoice check outline"]},{"name":"mdi:receipt-text-clock","tags":["invoice clock","invoice schedule","receipt text pending"]},{"name":"mdi:receipt-text-clock-outline","tags":["invoice clock outline","invoice schedule outline","receipt text pending"]},{"name":"mdi:receipt-text-edit","tags":["invoice edit"]},{"name":"mdi:receipt-text-edit-outline","tags":["invoice edit outline"]},{"name":"mdi:receipt-text-minus","tags":["invoice minus"]},{"name":"mdi:receipt-text-minus-outline","tags":["invoice minus outline"]},{"name":"mdi:receipt-text-plus","tags":["invoice plus","invoice add","receipt text add"]},{"name":"mdi:receipt-text-plus-outline","tags":["invoice plus","invoice add","receipt text add"]},{"name":"mdi:receipt-text-remove","tags":["invoice remove"]},{"name":"mdi:receipt-text-remove-outline","tags":["invoice remove outline"]},{"name":"mdi:receipt-text-send","tags":[]},{"name":"mdi:receipt-text-send-outline","tags":[]},{"name":"mdi:record","tags":["home automation","fiber manual record"]},{"name":"mdi:record-circle","tags":[]},{"name":"mdi:record-circle-outline","tags":[]},{"name":"mdi:record-player","tags":["home automation"]},{"name":"mdi:record-rec","tags":["home automation"]},{"name":"mdi:rectangle","tags":["shape"]},{"name":"mdi:rectangle-outline","tags":["shape"]},{"name":"mdi:recycle","tags":[]},{"name":"mdi:recycle-variant","tags":[]},{"name":"mdi:redo-variant","tags":["arrow"]},{"name":"mdi:reflect-horizontal","tags":[]},{"name":"mdi:reflect-vertical","tags":[]},{"name":"mdi:refresh-auto","tags":["automotive","auto start","automatic start","auto stop","automatic stop","automatic","refresh automatic"]},{"name":"mdi:refresh-circle","tags":[]},{"name":"mdi:regex","tags":["regular expression"]},{"name":"mdi:registered-trademark","tags":[]},{"name":"mdi:reiterate","tags":["arrow"]},{"name":"mdi:relation-many-to-many","tags":["database"]},{"name":"mdi:relation-many-to-one","tags":["database"]},{"name":"mdi:relation-many-to-one-or-many","tags":["database"]},{"name":"mdi:relation-many-to-only-one","tags":["database"]},{"name":"mdi:relation-many-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-many-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-one-or-many-to-many","tags":["database"]},{"name":"mdi:relation-one-or-many-to-one","tags":["database"]},{"name":"mdi:relation-one-or-many-to-one-or-many","tags":["database"]},{"name":"mdi:relation-one-or-many-to-only-one","tags":["database"]},{"name":"mdi:relation-one-or-many-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-one-or-many-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-one-to-many","tags":["database"]},{"name":"mdi:relation-one-to-one","tags":["database"]},{"name":"mdi:relation-one-to-one-or-many","tags":["database"]},{"name":"mdi:relation-one-to-only-one","tags":["database"]},{"name":"mdi:relation-one-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-one-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-only-one-to-many","tags":["database"]},{"name":"mdi:relation-only-one-to-one","tags":["database"]},{"name":"mdi:relation-only-one-to-one-or-many","tags":["database"]},{"name":"mdi:relation-only-one-to-only-one","tags":["database"]},{"name":"mdi:relation-only-one-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-only-one-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-many","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-one","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-one-or-many","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-only-one","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-zero-or-many-to-zero-or-one","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-many","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-one","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-one-or-many","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-only-one","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-zero-or-many","tags":["database"]},{"name":"mdi:relation-zero-or-one-to-zero-or-one","tags":["database"]},{"name":"mdi:reload","tags":["automotive","arrow","car engine start","loop","rotate clockwise"]},{"name":"mdi:reload-alert","tags":["alert / error"]},{"name":"mdi:remote-desktop","tags":[]},{"name":"mdi:remote-off","tags":[]},{"name":"mdi:remote-tv","tags":["device / tech"]},{"name":"mdi:remote-tv-off","tags":["device / tech"]},{"name":"mdi:rename-box","tags":[]},{"name":"mdi:rename-box-outline","tags":[]},{"name":"mdi:reorder-vertical","tags":[]},{"name":"mdi:repeat-off","tags":[]},{"name":"mdi:repeat-variant","tags":["arrow","twitter retweet","repost"]},{"name":"mdi:reply-all-outline","tags":["arrow"]},{"name":"mdi:reply-circle","tags":["arrow"]},{"name":"mdi:reply-outline","tags":["arrow"]},{"name":"mdi:reproduction","tags":["medical / hospital"]},{"name":"mdi:resistor","tags":[]},{"name":"mdi:resistor-nodes","tags":[]},{"name":"mdi:resize","tags":[]},{"name":"mdi:resize-bottom-right","tags":["drag"]},{"name":"mdi:responsive","tags":[]},{"name":"mdi:restart-alert","tags":["alert / error"]},{"name":"mdi:restart-off","tags":[]},{"name":"mdi:restore-alert","tags":["alert / error"]},{"name":"mdi:rewind-10","tags":[]},{"name":"mdi:rewind-15","tags":[]},{"name":"mdi:rewind-30","tags":[]},{"name":"mdi:rewind-45","tags":[]},{"name":"mdi:rewind-5","tags":[]},{"name":"mdi:rewind-60","tags":[]},{"name":"mdi:rhombus","tags":["shape","diamond"]},{"name":"mdi:rhombus-medium","tags":["shape"]},{"name":"mdi:rhombus-medium-outline","tags":["shape"]},{"name":"mdi:rhombus-outline","tags":["shape","diamond outline"]},{"name":"mdi:rhombus-split","tags":["shape","collection"]},{"name":"mdi:rhombus-split-outline","tags":["shape"]},{"name":"mdi:rice","tags":["food / drink"]},{"name":"mdi:rickshaw","tags":["transportation + road","transportation + other"]},{"name":"mdi:rickshaw-electric","tags":["transportation + road","transportation + other"]},{"name":"mdi:ring","tags":[]},{"name":"mdi:rivet","tags":["hardware / tools"]},{"name":"mdi:road","tags":["transportation + road"]},{"name":"mdi:road-variant","tags":["transportation + road"]},{"name":"mdi:robber","tags":[]},{"name":"mdi:robot","tags":["home automation","emoji robot","emoticon robot"]},{"name":"mdi:robot-angry","tags":["emoji robot angry","emoticon robot angry"]},{"name":"mdi:robot-angry-outline","tags":["emoji robot angry outline","emoticon robot angry outline"]},{"name":"mdi:robot-confused","tags":["emoji robot confused","emoticon robot confused"]},{"name":"mdi:robot-confused-outline","tags":["emoji robot confused outline","emoticon robot confused outline"]},{"name":"mdi:robot-dead","tags":["emoji robot dead","emoticon robot dead"]},{"name":"mdi:robot-dead-outline","tags":["emoji robot dead outline","emoticon robot dead outline"]},{"name":"mdi:robot-excited","tags":["emoticon robot excited","emoji robot excited"]},{"name":"mdi:robot-excited-outline","tags":["emoji robot excited outline","emoticon robot excited outline"]},{"name":"mdi:robot-happy","tags":["emoji robot happy","emoticon robot happy"]},{"name":"mdi:robot-happy-outline","tags":["emoji robot happy outline","emoticon robot happy outline"]},{"name":"mdi:robot-industrial","tags":["autonomous","assembly"]},{"name":"mdi:robot-industrial-outline","tags":[]},{"name":"mdi:robot-love","tags":["emoji robot love","emoticon robot love"]},{"name":"mdi:robot-love-outline","tags":[]},{"name":"mdi:robot-mower","tags":["home automation","lawn mower"]},{"name":"mdi:robot-mower-outline","tags":["home automation","lawn mower outline"]},{"name":"mdi:robot-off","tags":["emoji robot off","emoticon robot off"]},{"name":"mdi:robot-off-outline","tags":[]},{"name":"mdi:robot-outline","tags":["emoji robot outline","emoticon robot outline"]},{"name":"mdi:robot-vacuum","tags":["device / tech","home automation","roomba"]},{"name":"mdi:robot-vacuum-alert","tags":["alert / error","home automation","robot vacuum error"]},{"name":"mdi:robot-vacuum-off","tags":["home automation"]},{"name":"mdi:robot-vacuum-variant","tags":["home automation","neato"]},{"name":"mdi:robot-vacuum-variant-alert","tags":["alert / error","home automation","robot vacuum variant error"]},{"name":"mdi:robot-vacuum-variant-off","tags":["home automation"]},{"name":"mdi:rocket-launch","tags":["science","transportation + flying"]},{"name":"mdi:rocket-launch-outline","tags":["science","transportation + flying"]},{"name":"mdi:roller-skate","tags":["sport"]},{"name":"mdi:roller-skate-off","tags":["sport"]},{"name":"mdi:rollerblade","tags":["sport"]},{"name":"mdi:rollerblade-off","tags":["sport"]},{"name":"mdi:rolodex","tags":[]},{"name":"mdi:rolodex-outline","tags":[]},{"name":"mdi:roman-numeral-1","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-10","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-2","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-3","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-4","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-5","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-6","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-7","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-8","tags":["alpha / numeric"]},{"name":"mdi:roman-numeral-9","tags":["alpha / numeric"]},{"name":"mdi:rotate-3d-variant","tags":["3d rotation"]},{"name":"mdi:rotate-left-variant","tags":[]},{"name":"mdi:rotate-orbit","tags":["gyro","accelerometer"]},{"name":"mdi:rotate-right-variant","tags":[]},{"name":"mdi:router","tags":[]},{"name":"mdi:router-network","tags":[]},{"name":"mdi:router-wireless-off","tags":[]},{"name":"mdi:routes","tags":["sign routes"]},{"name":"mdi:routes-clock","tags":["date / time"]},{"name":"mdi:rss-box","tags":["rss feed box"]},{"name":"mdi:rss-off","tags":[]},{"name":"mdi:rug","tags":["home automation","carpet"]},{"name":"mdi:ruler","tags":["hardware / tools","drawing / art"]},{"name":"mdi:ruler-square","tags":["hardware / tools","drawing / art","square","carpentry","architecture"]},{"name":"mdi:ruler-square-compass","tags":["hardware / tools","mason","masonic","freemasonry"]},{"name":"mdi:run-fast","tags":["home automation","sport","people / family","velocity","human run fast"]},{"name":"mdi:rv-truck","tags":["transportation + road","recreational vehicle","campervan"]},{"name":"mdi:sack","tags":["gaming / rpg"]},{"name":"mdi:sack-outline","tags":[]},{"name":"mdi:sack-percent","tags":[]},{"name":"mdi:safe","tags":["banking"]},{"name":"mdi:safe-square","tags":[]},{"name":"mdi:safe-square-outline","tags":[]},{"name":"mdi:safety-goggles","tags":["science","safety glasses"]},{"name":"mdi:sail-boat-sink","tags":["transportation + water","sail boat crash","sail boat wreck"]},{"name":"mdi:sale","tags":["shopping","discount"]},{"name":"mdi:sale-outline","tags":["shopping","discount outline"]},{"name":"mdi:satellite-uplink","tags":[]},{"name":"mdi:satellite-variant","tags":[]},{"name":"mdi:sausage","tags":["food / drink"]},{"name":"mdi:sausage-off","tags":["food / drink"]},{"name":"mdi:saw-blade","tags":["hardware / tools"]},{"name":"mdi:sawtooth-wave","tags":["audio"]},{"name":"mdi:scale","tags":["food / drink","science"]},{"name":"mdi:scale-balance","tags":["science","justice","legal"]},{"name":"mdi:scale-bathroom","tags":["home automation","medical / hospital"]},{"name":"mdi:scale-off","tags":["science"]},{"name":"mdi:scale-unbalanced","tags":[]},{"name":"mdi:scan-helper","tags":[]},{"name":"mdi:scanner-off","tags":["device / tech"]},{"name":"mdi:scent","tags":["aroma","fragrance","smell","odor"]},{"name":"mdi:scent-off","tags":["aroma off","smell off","fragrance off","odor off"]},{"name":"mdi:scissors-cutting","tags":[]},{"name":"mdi:scoreboard","tags":["sport"]},{"name":"mdi:scoreboard-outline","tags":["sport"]},{"name":"mdi:screw-flat-top","tags":["hardware / tools"]},{"name":"mdi:screw-lag","tags":["hardware / tools"]},{"name":"mdi:screw-machine-flat-top","tags":["hardware / tools"]},{"name":"mdi:screw-machine-round-top","tags":["hardware / tools"]},{"name":"mdi:screw-round-top","tags":["hardware / tools"]},{"name":"mdi:screwdriver","tags":["hardware / tools"]},{"name":"mdi:script","tags":["gaming / rpg","scroll"]},{"name":"mdi:script-outline","tags":["gaming / rpg","scroll outline"]},{"name":"mdi:script-text","tags":["gaming / rpg","scroll text"]},{"name":"mdi:script-text-key","tags":[]},{"name":"mdi:script-text-key-outline","tags":[]},{"name":"mdi:script-text-outline","tags":["gaming / rpg","scroll text outline"]},{"name":"mdi:script-text-play","tags":[]},{"name":"mdi:script-text-play-outline","tags":[]},{"name":"mdi:seal","tags":["ribbon","prize","award"]},{"name":"mdi:seal-variant","tags":["ribbon","prize","award"]},{"name":"mdi:search-web","tags":["search globe","global search","internet search"]},{"name":"mdi:seat-passenger","tags":[]},{"name":"mdi:seatbelt","tags":["automotive","seat belt","safety belt"]},{"name":"mdi:security-network","tags":["shield network","uac network","administrator network"]},{"name":"mdi:seed","tags":["agriculture","nature","food / drink"]},{"name":"mdi:seed-off","tags":["nature","food / drink","agriculture"]},{"name":"mdi:seed-off-outline","tags":["nature","food / drink","agriculture"]},{"name":"mdi:seed-outline","tags":["agriculture","nature","food / drink"]},{"name":"mdi:seed-plus","tags":["agriculture","nature","seed add"]},{"name":"mdi:seed-plus-outline","tags":["agriculture","nature","seed add outline"]},{"name":"mdi:seesaw","tags":["playground seesaw"]},{"name":"mdi:select","tags":[]},{"name":"mdi:select-arrow-down","tags":[]},{"name":"mdi:select-arrow-up","tags":[]},{"name":"mdi:select-compare","tags":[]},{"name":"mdi:select-drag","tags":[]},{"name":"mdi:select-inverse","tags":["selection invert"]},{"name":"mdi:select-marker","tags":["navigation","select location"]},{"name":"mdi:select-multiple","tags":[]},{"name":"mdi:select-multiple-marker","tags":["navigation","select multiple location"]},{"name":"mdi:select-off","tags":[]},{"name":"mdi:select-place","tags":[]},{"name":"mdi:select-remove","tags":[]},{"name":"mdi:select-search","tags":[]},{"name":"mdi:selection","tags":[]},{"name":"mdi:selection-drag","tags":[]},{"name":"mdi:selection-ellipse","tags":[]},{"name":"mdi:selection-ellipse-remove","tags":[]},{"name":"mdi:selection-marker","tags":["navigation","selection location"]},{"name":"mdi:selection-multiple","tags":[]},{"name":"mdi:selection-multiple-marker","tags":["navigation","selection multiple location"]},{"name":"mdi:selection-off","tags":[]},{"name":"mdi:selection-remove","tags":[]},{"name":"mdi:selection-search","tags":[]},{"name":"mdi:send-check","tags":[]},{"name":"mdi:send-check-outline","tags":[]},{"name":"mdi:send-circle","tags":[]},{"name":"mdi:send-circle-outline","tags":[]},{"name":"mdi:send-lock","tags":["lock","send secure"]},{"name":"mdi:send-lock-outline","tags":["lock"]},{"name":"mdi:send-outline","tags":["paper airplane outline","paper plane outline"]},{"name":"mdi:send-variant-clock","tags":[]},{"name":"mdi:send-variant-clock-outline","tags":[]},{"name":"mdi:serial-port","tags":["vga"]},{"name":"mdi:server","tags":["storage"]},{"name":"mdi:server-minus","tags":["server remove"]},{"name":"mdi:server-network","tags":[]},{"name":"mdi:server-network-off","tags":[]},{"name":"mdi:server-off","tags":[]},{"name":"mdi:server-plus","tags":["server add"]},{"name":"mdi:server-remove","tags":[]},{"name":"mdi:server-security","tags":["server shield"]},{"name":"mdi:set-all","tags":["database","set union","set or","full outer join","sql full outer join"]},{"name":"mdi:set-center","tags":["database","set centre","set intersection","set and","inner join","sql inner join"]},{"name":"mdi:set-center-right","tags":["database","set centre right","outer join right","sql right outer join"]},{"name":"mdi:set-left","tags":["database","difference left"]},{"name":"mdi:set-left-center","tags":["database","set left centre","outer join left","sql left outer join"]},{"name":"mdi:set-left-right","tags":["database","exclusion","set xor"]},{"name":"mdi:set-merge","tags":[]},{"name":"mdi:set-none","tags":["database","set null","set not","venn diagram"]},{"name":"mdi:set-right","tags":["database","difference right"]},{"name":"mdi:set-split","tags":[]},{"name":"mdi:set-top-box","tags":["home automation"]},{"name":"mdi:settings-helper","tags":["settings"]},{"name":"mdi:shaker","tags":["food / drink","pepper","fish food"]},{"name":"mdi:shaker-outline","tags":["food / drink","salt","fish food outline"]},{"name":"mdi:shape-circle-plus","tags":["shape","shape circle add"]},{"name":"mdi:shape-oval-plus","tags":[]},{"name":"mdi:shape-plus","tags":["shape","shape add","category plus"]},{"name":"mdi:shape-plus-outline","tags":["shape","shape add outline","category plus outline"]},{"name":"mdi:shape-polygon-plus","tags":["shape","shape polygon add"]},{"name":"mdi:shape-rectangle-plus","tags":["shape","shape rectangle add"]},{"name":"mdi:shape-square-plus","tags":["shape","shape square add"]},{"name":"mdi:shape-square-rounded-plus","tags":[]},{"name":"mdi:share-all","tags":[]},{"name":"mdi:share-all-outline","tags":[]},{"name":"mdi:share-circle","tags":["arrow"]},{"name":"mdi:share-off","tags":["arrow","forward off"]},{"name":"mdi:share-off-outline","tags":["arrow","forward off outline"]},{"name":"mdi:share-outline","tags":["arrow","forward outline"]},{"name":"mdi:share-variant-outline","tags":[]},{"name":"mdi:shark","tags":["animal","jaws"]},{"name":"mdi:shark-fin","tags":["animal"]},{"name":"mdi:shark-fin-outline","tags":["animal"]},{"name":"mdi:shark-off","tags":["animal","jaws off"]},{"name":"mdi:sheep","tags":["animal","agriculture","emoji sheep","emoticon sheep"]},{"name":"mdi:shield","tags":["gaming / rpg"]},{"name":"mdi:shield-account","tags":["account / user","home automation","security account","shield user","shield person","alarm arm home"]},{"name":"mdi:shield-account-outline","tags":["account / user","home automation","security account outline","shield user outline","shield person outline","alarm arm home outline"]},{"name":"mdi:shield-airplane","tags":["transportation + flying","shield aeroplane","shield plane","plane shield"]},{"name":"mdi:shield-airplane-outline","tags":["transportation + flying","shield aeroplane outline","shield plane outline"]},{"name":"mdi:shield-alert","tags":["alert / error","shield warning"]},{"name":"mdi:shield-alert-outline","tags":["alert / error","shield warning outline"]},{"name":"mdi:shield-bug","tags":["antivirus"]},{"name":"mdi:shield-bug-outline","tags":["antivirus outline"]},{"name":"mdi:shield-car","tags":["automotive","car security","car insurance"]},{"name":"mdi:shield-check-outline","tags":["shield tick outline"]},{"name":"mdi:shield-cross","tags":["gaming / rpg","religion","shield templar","shield christianity"]},{"name":"mdi:shield-cross-outline","tags":["gaming / rpg","religion","shield templar outline","shield christianity outline"]},{"name":"mdi:shield-crown","tags":["gaming / rpg","administrator"]},{"name":"mdi:shield-crown-outline","tags":["gaming / rpg","administrator outline"]},{"name":"mdi:shield-edit","tags":["edit / modify"]},{"name":"mdi:shield-edit-outline","tags":["edit / modify"]},{"name":"mdi:shield-half","tags":[]},{"name":"mdi:shield-half-full","tags":[]},{"name":"mdi:shield-home","tags":["home automation","security home","shield house","alarm arm home"]},{"name":"mdi:shield-home-outline","tags":["home automation","shield house outline","alarm arm home"]},{"name":"mdi:shield-link-variant","tags":[]},{"name":"mdi:shield-link-variant-outline","tags":[]},{"name":"mdi:shield-lock","tags":["lock","home automation","security lock","alarm arm away"]},{"name":"mdi:shield-lock-open","tags":["home automation","lock","shield unlocked"]},{"name":"mdi:shield-lock-open-outline","tags":["home automation","lock","shield unlocked outline"]},{"name":"mdi:shield-lock-outline","tags":["lock","home automation","alarm arm away outline","security lock outline"]},{"name":"mdi:shield-moon","tags":["home automation","alarm arm night"]},{"name":"mdi:shield-moon-outline","tags":["home automation","alarm arm night outline"]},{"name":"mdi:shield-off","tags":["security off"]},{"name":"mdi:shield-off-outline","tags":[]},{"name":"mdi:shield-outline","tags":["gaming / rpg"]},{"name":"mdi:shield-refresh","tags":[]},{"name":"mdi:shield-refresh-outline","tags":[]},{"name":"mdi:shield-remove","tags":[]},{"name":"mdi:shield-remove-outline","tags":[]},{"name":"mdi:shield-star","tags":["badge","shield favorite"]},{"name":"mdi:shield-star-outline","tags":["badge outline","shield favorite outline"]},{"name":"mdi:shield-sun","tags":["weather","sun protection"]},{"name":"mdi:shield-sun-outline","tags":["weather","sun protection outline"]},{"name":"mdi:shield-sword","tags":["gaming / rpg","moderator"]},{"name":"mdi:shield-sword-outline","tags":["gaming / rpg","moderator outline"]},{"name":"mdi:shield-sync","tags":[]},{"name":"mdi:shield-sync-outline","tags":[]},{"name":"mdi:shimmer","tags":["sparkles"]},{"name":"mdi:shipping-pallet","tags":[]},{"name":"mdi:shoe-ballet","tags":["sport","clothing","slippers ballet"]},{"name":"mdi:shoe-cleat","tags":["sport","clothing"]},{"name":"mdi:shoe-formal","tags":["clothing"]},{"name":"mdi:shoe-heel","tags":["clothing"]},{"name":"mdi:shoe-print","tags":["footprints"]},{"name":"mdi:shoe-sneaker","tags":["sport","clothing","shoe running"]},{"name":"mdi:shopping-music","tags":["shopping"]},{"name":"mdi:shopping-search","tags":["shopping"]},{"name":"mdi:shopping-search-outline","tags":["shopping"]},{"name":"mdi:shore","tags":[]},{"name":"mdi:shovel","tags":["hardware / tools","gardening"]},{"name":"mdi:shovel-off","tags":["hardware / tools"]},{"name":"mdi:shower","tags":["home automation","bathtub","bathroom"]},{"name":"mdi:shower-head","tags":["home automation","bathroom"]},{"name":"mdi:shredder","tags":[]},{"name":"mdi:shuffle-disabled","tags":["arrow"]},{"name":"mdi:shuffle-variant","tags":["arrow"]},{"name":"mdi:shuriken","tags":["ninja star"]},{"name":"mdi:sickle","tags":["hardware / tools"]},{"name":"mdi:sigma-lower","tags":[]},{"name":"mdi:sign-caution","tags":["transportation + road","barrier"]},{"name":"mdi:sign-direction","tags":["milestone"]},{"name":"mdi:sign-direction-minus","tags":["milestone minus"]},{"name":"mdi:sign-direction-plus","tags":["milestone plus","sign direction add","milestone add"]},{"name":"mdi:sign-direction-remove","tags":["milestone remove"]},{"name":"mdi:sign-pole","tags":[]},{"name":"mdi:sign-real-estate","tags":[]},{"name":"mdi:sign-text","tags":[]},{"name":"mdi:sign-yield","tags":["transportation + road","give way"]},{"name":"mdi:signal","tags":["cellphone / phone"]},{"name":"mdi:signal-2g","tags":["cellphone / phone"]},{"name":"mdi:signal-3g","tags":["cellphone / phone"]},{"name":"mdi:signal-4g","tags":["cellphone / phone"]},{"name":"mdi:signal-5g","tags":["cellphone / phone"]},{"name":"mdi:signal-cellular-1","tags":["cellphone / phone"]},{"name":"mdi:signal-cellular-2","tags":["cellphone / phone"]},{"name":"mdi:signal-cellular-3","tags":["cellphone / phone"]},{"name":"mdi:signal-cellular-outline","tags":["cellphone / phone","signal cellular 0"]},{"name":"mdi:signal-distance-variant","tags":[]},{"name":"mdi:signal-hspa","tags":["cellphone / phone"]},{"name":"mdi:signal-hspa-plus","tags":["cellphone / phone"]},{"name":"mdi:signal-off","tags":["cellphone / phone"]},{"name":"mdi:signal-variant","tags":[]},{"name":"mdi:signature","tags":["form"]},{"name":"mdi:signature-freehand","tags":["form"]},{"name":"mdi:signature-image","tags":["form"]},{"name":"mdi:signature-text","tags":["form"]},{"name":"mdi:silo","tags":["agriculture","farm"]},{"name":"mdi:silo-outline","tags":["agriculture","farm outline"]},{"name":"mdi:silverware-clean","tags":["food / drink","silverware shimmer","cutlery clean"]},{"name":"mdi:silverware-fork","tags":["food / drink","cutlery fork"]},{"name":"mdi:silverware-spoon","tags":["food / drink","cutlery spoon"]},{"name":"mdi:silverware-variant","tags":["food / drink","places","cutlery variant"]},{"name":"mdi:sim-alert-outline","tags":["cellphone / phone","alert / error"]},{"name":"mdi:sim-off-outline","tags":["cellphone / phone"]},{"name":"mdi:sim-outline","tags":["cellphone / phone","sim card outline","subscriber identity module outline","subscriber identification module outline"]},{"name":"mdi:sine-wave","tags":["audio","alternating current","current ac","wave","analog","frequency","amplitude"]},{"name":"mdi:sitemap","tags":["workflow","flowchart"]},{"name":"mdi:sitemap-outline","tags":["workflow outline","flowchart outline"]},{"name":"mdi:size-l","tags":["size large"]},{"name":"mdi:size-m","tags":["size medium"]},{"name":"mdi:size-s","tags":["size small"]},{"name":"mdi:size-xl","tags":["size extra large"]},{"name":"mdi:size-xs","tags":["size extra small"]},{"name":"mdi:size-xxl","tags":["size extra extra large"]},{"name":"mdi:size-xxs","tags":["size extra extra small"]},{"name":"mdi:size-xxxl","tags":[]},{"name":"mdi:skate-off","tags":["sport"]},{"name":"mdi:skew-less","tags":["math","skew decrease"]},{"name":"mdi:skew-more","tags":["math","skew increase"]},{"name":"mdi:ski-water","tags":["sport","people / family","transportation + water","human ski water"]},{"name":"mdi:skip-backward","tags":["home automation","title backward","previous title"]},{"name":"mdi:skip-backward-outline","tags":[]},{"name":"mdi:skip-forward","tags":["home automation","title forward","next title"]},{"name":"mdi:skip-forward-outline","tags":[]},{"name":"mdi:skip-next-circle","tags":[]},{"name":"mdi:skip-next-circle-outline","tags":[]},{"name":"mdi:skip-next-outline","tags":[]},{"name":"mdi:skip-previous-circle","tags":[]},{"name":"mdi:skip-previous-circle-outline","tags":[]},{"name":"mdi:skip-previous-outline","tags":[]},{"name":"mdi:skull","tags":["holiday","gaming / rpg"]},{"name":"mdi:skull-crossbones","tags":["gaming / rpg","holiday","jolly roger"]},{"name":"mdi:skull-crossbones-outline","tags":["gaming / rpg","holiday","jolly roger outline"]},{"name":"mdi:skull-outline","tags":["holiday","gaming / rpg"]},{"name":"mdi:skull-scan","tags":["medical / hospital","x ray","radiology"]},{"name":"mdi:skull-scan-outline","tags":["medical / hospital","x ray outline","radiology outline"]},{"name":"mdi:slash-forward","tags":["math","divide","division"]},{"name":"mdi:slash-forward-box","tags":["math","divide box","division box"]},{"name":"mdi:sleep-off","tags":[]},{"name":"mdi:slide","tags":["playground slide"]},{"name":"mdi:slope-downhill","tags":[]},{"name":"mdi:slope-uphill","tags":[]},{"name":"mdi:slot-machine","tags":["casino","gambling"]},{"name":"mdi:slot-machine-outline","tags":["casino outline","gambling outline"]},{"name":"mdi:smart-card","tags":["account / user"]},{"name":"mdi:smart-card-off","tags":["account / user"]},{"name":"mdi:smart-card-off-outline","tags":["account / user"]},{"name":"mdi:smart-card-outline","tags":["account / user"]},{"name":"mdi:smart-card-reader","tags":["account / user"]},{"name":"mdi:smart-card-reader-outline","tags":["account / user"]},{"name":"mdi:smog","tags":[]},{"name":"mdi:smoke","tags":["smog","fire"]},{"name":"mdi:smoke-detector-alert","tags":["home automation","alert / error"]},{"name":"mdi:smoke-detector-alert-outline","tags":["home automation","alert / error"]},{"name":"mdi:smoke-detector-off","tags":["home automation"]},{"name":"mdi:smoke-detector-off-outline","tags":["home automation"]},{"name":"mdi:smoke-detector-outline","tags":["home automation"]},{"name":"mdi:smoke-detector-variant","tags":["home automation"]},{"name":"mdi:smoke-detector-variant-alert","tags":["home automation","alert / error"]},{"name":"mdi:smoke-detector-variant-off","tags":["home automation"]},{"name":"mdi:smoking-pipe","tags":[]},{"name":"mdi:smoking-pipe-off","tags":[]},{"name":"mdi:snail","tags":["animal","gastropod"]},{"name":"mdi:snake","tags":["animal","reptile"]},{"name":"mdi:snowflake-alert","tags":["weather","alert / error","home automation","cold alert","snow advisory","freeze advisory"]},{"name":"mdi:snowflake-check","tags":["weather","snowflake approve"]},{"name":"mdi:snowflake-melt","tags":["weather","defrost"]},{"name":"mdi:snowflake-off","tags":["weather"]},{"name":"mdi:snowflake-thermometer","tags":["weather","home automation","frost point","freezing point","snowflake temperature"]},{"name":"mdi:snowflake-variant","tags":["holiday","weather"]},{"name":"mdi:snowman","tags":["holiday"]},{"name":"mdi:soccer-field","tags":["sport","football pitch"]},{"name":"mdi:social-distance-2-meters","tags":["medical / hospital"]},{"name":"mdi:sofa","tags":["home automation","couch","living room","family room"]},{"name":"mdi:sofa-outline","tags":["home automation","couch outline","living room outline","family room outline"]},{"name":"mdi:sofa-single","tags":["home automation","loveseat","love seat","couch","chair accent","living room","family room"]},{"name":"mdi:sofa-single-outline","tags":["home automation","loveseat outline","love seat outline","couch outline","chair accent outline","living room outline","family room outline"]},{"name":"mdi:solar-panel","tags":["home automation","solar energy","solar electricity"]},{"name":"mdi:solar-panel-large","tags":["home automation","solar panel energy","solar panel electricity"]},{"name":"mdi:solar-power","tags":["home automation","solar energy","solar electricity"]},{"name":"mdi:soldering-iron","tags":[]},{"name":"mdi:solid","tags":[]},{"name":"mdi:sort","tags":["text / content / format"]},{"name":"mdi:sort-alphabetical-ascending","tags":["text / content / format"]},{"name":"mdi:sort-alphabetical-ascending-variant","tags":["text / content / format"]},{"name":"mdi:sort-alphabetical-descending","tags":["text / content / format"]},{"name":"mdi:sort-alphabetical-descending-variant","tags":["text / content / format"]},{"name":"mdi:sort-ascending","tags":["text / content / format"]},{"name":"mdi:sort-bool-ascending","tags":["text / content / format"]},{"name":"mdi:sort-bool-ascending-variant","tags":["text / content / format","sort checkbox ascending"]},{"name":"mdi:sort-bool-descending","tags":["text / content / format"]},{"name":"mdi:sort-bool-descending-variant","tags":["text / content / format","sort checkbox descending"]},{"name":"mdi:sort-calendar-ascending","tags":["text / content / format","date / time","sort date ascending"]},{"name":"mdi:sort-calendar-descending","tags":["text / content / format","date / time","sort date descending"]},{"name":"mdi:sort-clock-ascending","tags":["text / content / format","date / time","sort time ascending"]},{"name":"mdi:sort-clock-ascending-outline","tags":["text / content / format","date / time","sort time ascending outline"]},{"name":"mdi:sort-clock-descending","tags":["text / content / format","date / time","sort time descending"]},{"name":"mdi:sort-clock-descending-outline","tags":["text / content / format","date / time","sort time descending outline"]},{"name":"mdi:sort-descending","tags":["text / content / format"]},{"name":"mdi:sort-numeric-ascending","tags":["text / content / format"]},{"name":"mdi:sort-numeric-ascending-variant","tags":["text / content / format"]},{"name":"mdi:sort-numeric-descending","tags":["text / content / format"]},{"name":"mdi:sort-numeric-descending-variant","tags":["text / content / format"]},{"name":"mdi:sort-reverse-variant","tags":["text / content / format"]},{"name":"mdi:sort-variant-lock","tags":["text / content / format","lock"]},{"name":"mdi:sort-variant-lock-open","tags":["text / content / format","lock"]},{"name":"mdi:sort-variant-off","tags":["text / content / format"]},{"name":"mdi:sort-variant-remove","tags":["text / content / format"]},{"name":"mdi:soundbar","tags":["home automation","speaker bar"]},{"name":"mdi:source-branch","tags":["developer / languages"]},{"name":"mdi:source-branch-check","tags":["developer / languages"]},{"name":"mdi:source-branch-minus","tags":["developer / languages"]},{"name":"mdi:source-branch-plus","tags":["developer / languages"]},{"name":"mdi:source-branch-refresh","tags":["developer / languages"]},{"name":"mdi:source-branch-remove","tags":["developer / languages"]},{"name":"mdi:source-branch-sync","tags":["developer / languages"]},{"name":"mdi:source-commit","tags":[]},{"name":"mdi:source-commit-end","tags":[]},{"name":"mdi:source-commit-end-local","tags":[]},{"name":"mdi:source-commit-local","tags":[]},{"name":"mdi:source-commit-next-local","tags":[]},{"name":"mdi:source-commit-start","tags":[]},{"name":"mdi:source-commit-start-next-local","tags":[]},{"name":"mdi:source-fork","tags":["developer / languages"]},{"name":"mdi:source-merge","tags":["developer / languages"]},{"name":"mdi:source-pull","tags":["developer / languages"]},{"name":"mdi:source-repository","tags":["developer / languages"]},{"name":"mdi:source-repository-multiple","tags":["developer / languages","source repositories"]},{"name":"mdi:soy-sauce","tags":["food / drink","soya sauce"]},{"name":"mdi:soy-sauce-off","tags":[]},{"name":"mdi:space-invaders","tags":["gaming / rpg"]},{"name":"mdi:space-station","tags":[]},{"name":"mdi:spade","tags":["hardware / tools"]},{"name":"mdi:speaker-bluetooth","tags":["audio"]},{"name":"mdi:speaker-message","tags":["home automation","audio","text to speech"]},{"name":"mdi:speaker-multiple","tags":["audio","speakers"]},{"name":"mdi:speaker-off","tags":["audio","home automation"]},{"name":"mdi:speaker-pause","tags":["audio","music"]},{"name":"mdi:speaker-play","tags":["audio","music"]},{"name":"mdi:speaker-stop","tags":["audio","music"]},{"name":"mdi:speaker-wireless","tags":["audio","home automation"]},{"name":"mdi:spear","tags":["gaming / rpg","staff","fishing"]},{"name":"mdi:speedometer","tags":["automotive"]},{"name":"mdi:speedometer-medium","tags":["automotive"]},{"name":"mdi:speedometer-slow","tags":["automotive"]},{"name":"mdi:sphere","tags":["shape"]},{"name":"mdi:sphere-off","tags":["shape"]},{"name":"mdi:spider","tags":["holiday","nature","animal","arachnid","bug"]},{"name":"mdi:spider-outline","tags":["animal","holiday","nature","arachnid outline"]},{"name":"mdi:spider-thread","tags":["holiday","nature","animal","arachnid thread","bug"]},{"name":"mdi:spider-web","tags":["holiday","cobweb","arachnid web"]},{"name":"mdi:spirit-level","tags":["hardware / tools"]},{"name":"mdi:spoon-sugar","tags":["food / drink"]},{"name":"mdi:spotlight","tags":["home automation"]},{"name":"mdi:spotlight-beam","tags":["home automation"]},{"name":"mdi:spray","tags":["agriculture","drawing / art","color","paint","aerosol"]},{"name":"mdi:spray-bottle","tags":["cleaning"]},{"name":"mdi:sprinkler","tags":["home automation","agriculture","irrigation"]},{"name":"mdi:sprinkler-fire","tags":["home automation","agriculture","sprinkler mist","mister","sprinkler head"]},{"name":"mdi:sprinkler-variant","tags":["home automation","agriculture","irrigation"]},{"name":"mdi:sprout","tags":["agriculture","nature","seedling","plant","ecology","environment"]},{"name":"mdi:sprout-outline","tags":["agriculture","nature","seedling outline","plant outline","ecology outline","environment outline"]},{"name":"mdi:square","tags":["shape"]},{"name":"mdi:square-circle","tags":["food / drink","vegetarian","lacto vegetarian"]},{"name":"mdi:square-circle-outline","tags":[]},{"name":"mdi:square-edit-outline","tags":["edit / modify"]},{"name":"mdi:square-medium","tags":["shape"]},{"name":"mdi:square-medium-outline","tags":["shape"]},{"name":"mdi:square-off","tags":[]},{"name":"mdi:square-off-outline","tags":[]},{"name":"mdi:square-opacity","tags":["drawing / art","shape","square transparent"]},{"name":"mdi:square-outline","tags":["shape"]},{"name":"mdi:square-root","tags":["math"]},{"name":"mdi:square-root-box","tags":[]},{"name":"mdi:square-rounded","tags":[]},{"name":"mdi:square-rounded-badge","tags":["shape","notification","app badge","push notification"]},{"name":"mdi:square-rounded-badge-outline","tags":["shape","notification","app badge outline","push notification outline"]},{"name":"mdi:square-rounded-outline","tags":[]},{"name":"mdi:square-small","tags":["bullet"]},{"name":"mdi:square-wave","tags":["audio"]},{"name":"mdi:squeegee","tags":[]},{"name":"mdi:ssh","tags":[]},{"name":"mdi:stadium-variant","tags":["places","sport","arena"]},{"name":"mdi:stairs","tags":["transportation + other"]},{"name":"mdi:stairs-box","tags":[]},{"name":"mdi:stairs-down","tags":["transportation + other"]},{"name":"mdi:stairs-up","tags":["transportation + other"]},{"name":"mdi:stamper","tags":[]},{"name":"mdi:standard-definition","tags":["video / movie"]},{"name":"mdi:star-box","tags":["favorite box"]},{"name":"mdi:star-box-multiple","tags":["favorite box multiple"]},{"name":"mdi:star-box-multiple-outline","tags":["favorite box multiple outline"]},{"name":"mdi:star-box-outline","tags":["favorite box outline"]},{"name":"mdi:star-check","tags":["shape","favorite check"]},{"name":"mdi:star-check-outline","tags":["shape","favorite check outline"]},{"name":"mdi:star-cog","tags":["settings","favorite cog"]},{"name":"mdi:star-cog-outline","tags":["settings","favorite cog outline"]},{"name":"mdi:star-crescent","tags":["religion","islam","religion islamic","religion muslim"]},{"name":"mdi:star-david","tags":["religion","jewish","religion judaic","judaism","magen david"]},{"name":"mdi:star-four-points","tags":["shape"]},{"name":"mdi:star-four-points-box","tags":["shape","auto box"]},{"name":"mdi:star-four-points-box-outline","tags":["shape","auto box outline"]},{"name":"mdi:star-four-points-circle","tags":["shape","auto circle"]},{"name":"mdi:star-four-points-circle-outline","tags":["shape","auto circle outline"]},{"name":"mdi:star-four-points-outline","tags":["shape"]},{"name":"mdi:star-four-points-small","tags":["shape"]},{"name":"mdi:star-half","tags":["shape","favorite half"]},{"name":"mdi:star-minus","tags":["shape","favorite minus"]},{"name":"mdi:star-minus-outline","tags":["shape","favorite minus outline"]},{"name":"mdi:star-off","tags":["favorite off"]},{"name":"mdi:star-off-outline","tags":["favorite off outline"]},{"name":"mdi:star-plus","tags":["shape","favorite plus","star add","favorite add"]},{"name":"mdi:star-plus-outline","tags":["shape","star add outline","favorite plus outline","favorite add outline"]},{"name":"mdi:star-remove","tags":["shape","favorite remove"]},{"name":"mdi:star-remove-outline","tags":["shape","favorite remove outline"]},{"name":"mdi:star-settings","tags":["settings","favorite settings"]},{"name":"mdi:star-settings-outline","tags":["settings","favorite settings outline"]},{"name":"mdi:star-shooting","tags":["favorite shooting"]},{"name":"mdi:star-shooting-outline","tags":["favorite shooting outline"]},{"name":"mdi:star-three-points","tags":["shape"]},{"name":"mdi:star-three-points-outline","tags":["shape"]},{"name":"mdi:state-machine","tags":[]},{"name":"mdi:step-backward","tags":[]},{"name":"mdi:step-backward-2","tags":["frame backward"]},{"name":"mdi:step-forward","tags":[]},{"name":"mdi:step-forward-2","tags":["frame forward"]},{"name":"mdi:stethoscope","tags":["medical / hospital"]},{"name":"mdi:sticker","tags":[]},{"name":"mdi:sticker-alert","tags":["alert / error"]},{"name":"mdi:sticker-alert-outline","tags":["alert / error"]},{"name":"mdi:sticker-check","tags":[]},{"name":"mdi:sticker-check-outline","tags":[]},{"name":"mdi:sticker-circle-outline","tags":[]},{"name":"mdi:sticker-minus","tags":[]},{"name":"mdi:sticker-minus-outline","tags":[]},{"name":"mdi:sticker-outline","tags":[]},{"name":"mdi:sticker-plus","tags":[]},{"name":"mdi:sticker-plus-outline","tags":[]},{"name":"mdi:sticker-remove","tags":[]},{"name":"mdi:sticker-remove-outline","tags":[]},{"name":"mdi:sticker-text","tags":[]},{"name":"mdi:sticker-text-outline","tags":[]},{"name":"mdi:stocking","tags":["holiday"]},{"name":"mdi:stomach","tags":["medical / hospital"]},{"name":"mdi:stool","tags":[]},{"name":"mdi:stool-outline","tags":[]},{"name":"mdi:stop-circle","tags":[]},{"name":"mdi:stop-circle-outline","tags":[]},{"name":"mdi:store-alert","tags":["places","shopping","alert / error","shop alert"]},{"name":"mdi:store-alert-outline","tags":["places","shopping","alert / error","shop alert outline"]},{"name":"mdi:store-check","tags":["shopping","places","shop check","shop complete","store complete"]},{"name":"mdi:store-check-outline","tags":["shopping","places","shop complete","store complete outline","shop check outline"]},{"name":"mdi:store-clock","tags":["places","shopping","store schedule","store hours","shop clock","shop hours","shop schedule","store time","shop time"]},{"name":"mdi:store-clock-outline","tags":["places","shopping","date / time","shop clock outline","store hours outline","shop hours outline","store time outline","shop time outline","store schedule outline","shop schedule outline"]},{"name":"mdi:store-cog","tags":["places","shopping","settings","store settings","shop settings"]},{"name":"mdi:store-cog-outline","tags":["places","shopping","settings","store settings outline","shop settings outline","shop cog outline"]},{"name":"mdi:store-edit","tags":["places","shopping","edit / modify","shop edit"]},{"name":"mdi:store-edit-outline","tags":["places","shopping","edit / modify","shop edit outline"]},{"name":"mdi:store-marker","tags":["places","shopping","navigation","store location","shop marker","shop location"]},{"name":"mdi:store-marker-outline","tags":["places","shopping","navigation","store location outline","shop marker outline","shop location outline"]},{"name":"mdi:store-minus","tags":["places","shopping","shop minus"]},{"name":"mdi:store-minus-outline","tags":["places","shopping","shop minus outline"]},{"name":"mdi:store-off","tags":["places","shopping","shop off"]},{"name":"mdi:store-off-outline","tags":["places","shopping","shop off outline"]},{"name":"mdi:store-plus","tags":["places","shopping","shop plus"]},{"name":"mdi:store-plus-outline","tags":["places","shopping","shop plus outline"]},{"name":"mdi:store-remove","tags":["places","shopping","shop remove","store delete","shop delete"]},{"name":"mdi:store-remove-outline","tags":["places","shopping","shop remove outline","store delete outline","shop delete outline"]},{"name":"mdi:store-search","tags":["places","shopping","shop search","store find","shop find","store locator","shop locator","store look up","shop look up"]},{"name":"mdi:store-search-outline","tags":["places","shopping","store find outline","shop search outline","shop find outline","store locator outline","shop locator outline","store look up outline","shop look up outline"]},{"name":"mdi:store-settings","tags":["places","shopping","settings","shop settings"]},{"name":"mdi:store-settings-outline","tags":["places","shopping","settings","shop settings outline"]},{"name":"mdi:storefront","tags":["places","awning"]},{"name":"mdi:storefront-check","tags":[]},{"name":"mdi:storefront-check-outline","tags":[]},{"name":"mdi:storefront-edit","tags":["edit / modify"]},{"name":"mdi:storefront-edit-outline","tags":["edit / modify"]},{"name":"mdi:storefront-minus","tags":[]},{"name":"mdi:storefront-minus-outline","tags":[]},{"name":"mdi:storefront-plus","tags":[]},{"name":"mdi:storefront-plus-outline","tags":[]},{"name":"mdi:storefront-remove","tags":[]},{"name":"mdi:storefront-remove-outline","tags":[]},{"name":"mdi:stove","tags":["food / drink","home automation","cooker","oven"]},{"name":"mdi:strategy","tags":["sport","football play"]},{"name":"mdi:stretch-to-page","tags":["text / content / format","arrow"]},{"name":"mdi:stretch-to-page-outline","tags":["text / content / format","arrow"]},{"name":"mdi:string-lights","tags":["home automation","italian lights","christmas lights","fairy lights"]},{"name":"mdi:string-lights-off","tags":["home automation","italian lights off","christmas lights off","fairy lights off"]},{"name":"mdi:submarine","tags":[]},{"name":"mdi:subway-alert-variant","tags":["alert / error","transportation + other","subway warning variant"]},{"name":"mdi:summit","tags":["peak"]},{"name":"mdi:sun-angle","tags":["weather","solar angle"]},{"name":"mdi:sun-angle-outline","tags":["weather","solar angle outline"]},{"name":"mdi:sun-clock","tags":["weather","home automation","sun schedule","sun time","time of day"]},{"name":"mdi:sun-clock-outline","tags":["weather","home automation","date / time","sun schedule outline","sun time outline","time of day outline"]},{"name":"mdi:sun-compass","tags":["weather","home automation","navigation","sun azimuth","solar compass","solar asimuth"]},{"name":"mdi:sun-snowflake-variant","tags":["home automation","weather","hot cold","heat cool"]},{"name":"mdi:sun-thermometer","tags":["weather","home automation","heat index","sun temperature","day temperature","external temperature","outdoor temperature"]},{"name":"mdi:sun-thermometer-outline","tags":["home automation","weather","external temperature","outside temperature","heat index","day temperature"]},{"name":"mdi:sun-wireless","tags":["home automation","weather","weather sun wireless","illuminance","uv ray","ultraviolet"]},{"name":"mdi:sun-wireless-outline","tags":["home automation","weather","weather sun wireless outline","illuminance outline","uv ray outline","ultraviolet outline"]},{"name":"mdi:sunglasses","tags":["clothing"]},{"name":"mdi:surround-sound-2-0","tags":["audio","stereo"]},{"name":"mdi:surround-sound-2-1","tags":[]},{"name":"mdi:surround-sound-3-1","tags":["audio"]},{"name":"mdi:surround-sound-5-1","tags":["audio"]},{"name":"mdi:surround-sound-5-1-2","tags":[]},{"name":"mdi:surround-sound-7-1","tags":["audio"]},{"name":"mdi:swap-horizontal-circle-outline","tags":["arrow"]},{"name":"mdi:swap-vertical-circle","tags":["arrow"]},{"name":"mdi:swap-vertical-circle-outline","tags":["arrow"]},{"name":"mdi:swim","tags":["sport"]},{"name":"mdi:switch","tags":[]},{"name":"mdi:sword","tags":["gaming / rpg"]},{"name":"mdi:sword-cross","tags":["gaming / rpg"]},{"name":"mdi:syllabary-hangul","tags":["alpha / numeric","writing system hangul"]},{"name":"mdi:syllabary-hiragana","tags":["alpha / numeric","writing system hiragana"]},{"name":"mdi:syllabary-katakana","tags":["alpha / numeric","writing system katakana"]},{"name":"mdi:syllabary-katakana-halfwidth","tags":["alpha / numeric","writing system katakana half width"]},{"name":"mdi:symbol","tags":[]},{"name":"mdi:sync-circle","tags":[]},{"name":"mdi:tab-minus","tags":[]},{"name":"mdi:tab-plus","tags":["tab add"]},{"name":"mdi:tab-remove","tags":[]},{"name":"mdi:tab-search","tags":["tab find"]},{"name":"mdi:table","tags":["text / content / format"]},{"name":"mdi:table-account","tags":["account / user","table user"]},{"name":"mdi:table-alert","tags":["alert / error"]},{"name":"mdi:table-arrow-down","tags":["table download"]},{"name":"mdi:table-arrow-left","tags":["table import"]},{"name":"mdi:table-arrow-right","tags":["table share","table export"]},{"name":"mdi:table-arrow-up","tags":["table upload"]},{"name":"mdi:table-border","tags":["text / content / format"]},{"name":"mdi:table-cancel","tags":[]},{"name":"mdi:table-chair","tags":["home automation","restaurant","kitchen","dining","dining room"]},{"name":"mdi:table-check","tags":[]},{"name":"mdi:table-clock","tags":["date / time"]},{"name":"mdi:table-cog","tags":["settings","table settings"]},{"name":"mdi:table-column","tags":["text / content / format"]},{"name":"mdi:table-column-plus-after","tags":["text / content / format","table column add after"]},{"name":"mdi:table-column-plus-before","tags":["text / content / format","table column add before"]},{"name":"mdi:table-column-remove","tags":["text / content / format"]},{"name":"mdi:table-column-width","tags":["text / content / format"]},{"name":"mdi:table-edit","tags":["edit / modify","text / content / format"]},{"name":"mdi:table-eye","tags":[]},{"name":"mdi:table-eye-off","tags":[]},{"name":"mdi:table-filter","tags":[]},{"name":"mdi:table-furniture","tags":["home automation","kitchen","dining room"]},{"name":"mdi:table-headers-eye","tags":[]},{"name":"mdi:table-headers-eye-off","tags":[]},{"name":"mdi:table-heart","tags":["table favorite"]},{"name":"mdi:table-key","tags":[]},{"name":"mdi:table-large","tags":["text / content / format","geographic information system"]},{"name":"mdi:table-large-plus","tags":["text / content / format","geographic information system","table large add"]},{"name":"mdi:table-large-remove","tags":["text / content / format","geographic information system"]},{"name":"mdi:table-lock","tags":["lock"]},{"name":"mdi:table-minus","tags":[]},{"name":"mdi:table-multiple","tags":[]},{"name":"mdi:table-network","tags":[]},{"name":"mdi:table-off","tags":[]},{"name":"mdi:table-picnic","tags":[]},{"name":"mdi:table-pivot","tags":["text / content / format"]},{"name":"mdi:table-plus","tags":["text / content / format","table add"]},{"name":"mdi:table-question","tags":["table help"]},{"name":"mdi:table-refresh","tags":[]},{"name":"mdi:table-remove","tags":["text / content / format"]},{"name":"mdi:table-row","tags":["text / content / format"]},{"name":"mdi:table-row-height","tags":["text / content / format"]},{"name":"mdi:table-row-plus-after","tags":["text / content / format","table row add after"]},{"name":"mdi:table-row-plus-before","tags":["text / content / format","table row add before"]},{"name":"mdi:table-row-remove","tags":["text / content / format"]},{"name":"mdi:table-search","tags":[]},{"name":"mdi:table-settings","tags":["settings"]},{"name":"mdi:table-split-cell","tags":["text / content / format"]},{"name":"mdi:table-star","tags":["table favorite"]},{"name":"mdi:table-sync","tags":[]},{"name":"mdi:tablet-dashboard","tags":["device / tech"]},{"name":"mdi:taco","tags":["food / drink"]},{"name":"mdi:tag-arrow-down","tags":[]},{"name":"mdi:tag-arrow-down-outline","tags":[]},{"name":"mdi:tag-arrow-left","tags":[]},{"name":"mdi:tag-arrow-left-outline","tags":[]},{"name":"mdi:tag-arrow-right","tags":[]},{"name":"mdi:tag-arrow-right-outline","tags":[]},{"name":"mdi:tag-arrow-up","tags":[]},{"name":"mdi:tag-arrow-up-outline","tags":[]},{"name":"mdi:tag-check","tags":["tag approve"]},{"name":"mdi:tag-check-outline","tags":["tag approve outline"]},{"name":"mdi:tag-hidden","tags":[]},{"name":"mdi:tag-minus","tags":[]},{"name":"mdi:tag-minus-outline","tags":[]},{"name":"mdi:tag-multiple","tags":["tags"]},{"name":"mdi:tag-multiple-outline","tags":[]},{"name":"mdi:tag-off","tags":[]},{"name":"mdi:tag-off-outline","tags":[]},{"name":"mdi:tag-plus","tags":["tag add"]},{"name":"mdi:tag-plus-outline","tags":[]},{"name":"mdi:tag-remove","tags":[]},{"name":"mdi:tag-remove-outline","tags":[]},{"name":"mdi:tag-search","tags":["tag find"]},{"name":"mdi:tag-search-outline","tags":["tag find outline"]},{"name":"mdi:tag-text","tags":[]},{"name":"mdi:tag-text-outline","tags":[]},{"name":"mdi:tally-mark-1","tags":["math","counting 1","one"]},{"name":"mdi:tally-mark-2","tags":["math","counting 2","two"]},{"name":"mdi:tally-mark-3","tags":["math","counting 3","three"]},{"name":"mdi:tally-mark-4","tags":["math","counting 4","four"]},{"name":"mdi:tally-mark-5","tags":["math","counting 5","five"]},{"name":"mdi:tangram","tags":["gaming / rpg","puzzle"]},{"name":"mdi:tank","tags":[]},{"name":"mdi:tanker-truck","tags":["transportation + road","fuel truck","oil truck","water truck","tanker"]},{"name":"mdi:tape-drive","tags":[]},{"name":"mdi:tape-measure","tags":["hardware / tools","measuring tape"]},{"name":"mdi:target","tags":["registration mark"]},{"name":"mdi:target-account","tags":["account / user","crosshairs account","target user"]},{"name":"mdi:target-variant","tags":["registration mark"]},{"name":"mdi:tea-outline","tags":["food / drink"]},{"name":"mdi:teddy-bear","tags":["holiday","home automation","child toy","children toy","kids room","childrens room","play room"]},{"name":"mdi:telescope","tags":["science"]},{"name":"mdi:television-ambient-light","tags":["home automation"]},{"name":"mdi:television-classic","tags":["device / tech","home automation","tv classic"]},{"name":"mdi:television-classic-off","tags":["device / tech","home automation","tv classic off"]},{"name":"mdi:television-guide","tags":["device / tech","home automation"]},{"name":"mdi:television-off","tags":["device / tech","home automation","tv off"]},{"name":"mdi:television-pause","tags":["device / tech"]},{"name":"mdi:television-shimmer","tags":["device / tech","television clean"]},{"name":"mdi:television-speaker","tags":["audio","video / movie"]},{"name":"mdi:television-speaker-off","tags":["audio","video / movie"]},{"name":"mdi:television-stop","tags":["device / tech"]},{"name":"mdi:temperature-celsius","tags":["weather","temperature centigrade"]},{"name":"mdi:temperature-fahrenheit","tags":["weather"]},{"name":"mdi:temperature-kelvin","tags":["weather"]},{"name":"mdi:tennis-ball-outline","tags":["sport"]},{"name":"mdi:tent","tags":["camping"]},{"name":"mdi:test-tube","tags":["science"]},{"name":"mdi:test-tube-empty","tags":["science"]},{"name":"mdi:test-tube-off","tags":["science"]},{"name":"mdi:text-account","tags":["account / user","biography","text user"]},{"name":"mdi:text-box-check","tags":["files / folders","file document box tick","file document box check"]},{"name":"mdi:text-box-check-outline","tags":["files / folders","file document box tick outline","file document box check outline"]},{"name":"mdi:text-box-edit","tags":["files / folders","edit / modify"]},{"name":"mdi:text-box-edit-outline","tags":["files / folders","edit / modify"]},{"name":"mdi:text-box-minus","tags":["files / folders","file document box minus"]},{"name":"mdi:text-box-minus-outline","tags":["files / folders","file document box minus outline"]},{"name":"mdi:text-box-multiple","tags":["files / folders","file document boxes","file document box multiple"]},{"name":"mdi:text-box-multiple-outline","tags":["files / folders","file document boxes outline","file document box multiple outline"]},{"name":"mdi:text-box-outline","tags":["files / folders","file document box outline"]},{"name":"mdi:text-box-plus","tags":["files / folders","file document box plus"]},{"name":"mdi:text-box-plus-outline","tags":["files / folders","file document box plus outline"]},{"name":"mdi:text-box-remove","tags":["files / folders","file document box remove"]},{"name":"mdi:text-box-remove-outline","tags":["files / folders","file document box remove outline"]},{"name":"mdi:text-box-search","tags":["files / folders","file document box search"]},{"name":"mdi:text-box-search-outline","tags":["files / folders","file document box search outline"]},{"name":"mdi:text-recognition","tags":[]},{"name":"mdi:text-search","tags":["notes search"]},{"name":"mdi:text-search-variant","tags":["notes search variant"]},{"name":"mdi:text-shadow","tags":[]},{"name":"mdi:texture-box","tags":["math","surface area"]},{"name":"mdi:theater","tags":["places","home automation","cinema","theatre"]},{"name":"mdi:theme-light-dark","tags":["weather","sun moon stars"]},{"name":"mdi:thermometer","tags":["weather","home automation","automotive","temperature"]},{"name":"mdi:thermometer-alert","tags":["home automation","weather","alert / error","thermometer warning","temperature alert","temperature warning"]},{"name":"mdi:thermometer-auto","tags":["home automation","weather","temperature auto"]},{"name":"mdi:thermometer-bluetooth","tags":["weather","home automation","automotive","temperature bluetooth"]},{"name":"mdi:thermometer-check","tags":["weather","home automation","thermometer approve","temperature check","temperature approve"]},{"name":"mdi:thermometer-chevron-down","tags":["home automation","weather","temperature chevron down","temperature decrease","thermometer decrease"]},{"name":"mdi:thermometer-chevron-up","tags":["home automation","weather","temperature chevron up","temperature increase","thermometer increase"]},{"name":"mdi:thermometer-high","tags":["home automation","weather","temperature high"]},{"name":"mdi:thermometer-lines","tags":["weather","home automation","temperature lines"]},{"name":"mdi:thermometer-low","tags":["home automation","weather","temperature low"]},{"name":"mdi:thermometer-minus","tags":["home automation","weather","temperature minus","thermometer decrease","temperature decrease"]},{"name":"mdi:thermometer-off","tags":["weather","home automation","temperature off"]},{"name":"mdi:thermometer-plus","tags":["home automation","weather","thermometer add","thermometer increase","temperature plus","temperature add","temperature increase"]},{"name":"mdi:thermometer-probe","tags":[]},{"name":"mdi:thermometer-probe-off","tags":[]},{"name":"mdi:thermometer-water","tags":["weather","home automation","dew point","water temperature","boiling point"]},{"name":"mdi:thermostat-auto","tags":["home automation"]},{"name":"mdi:thermostat-box","tags":["home automation","device / tech"]},{"name":"mdi:thermostat-box-auto","tags":["home automation"]},{"name":"mdi:thermostat-cog","tags":[]},{"name":"mdi:thought-bubble","tags":["comic bubble","thinking"]},{"name":"mdi:thought-bubble-outline","tags":["comic thought bubble outline","thinking outline","think outline"]},{"name":"mdi:ticket-account","tags":["account / user","ticket user"]},{"name":"mdi:ticket-outline","tags":[]},{"name":"mdi:ticket-percent","tags":["coupon","voucher"]},{"name":"mdi:ticket-percent-outline","tags":["coupon outline","voucher outline"]},{"name":"mdi:tie","tags":["clothing"]},{"name":"mdi:tilde","tags":[]},{"name":"mdi:tilde-off","tags":[]},{"name":"mdi:timeline","tags":[]},{"name":"mdi:timeline-alert","tags":["alert / error"]},{"name":"mdi:timeline-alert-outline","tags":["alert / error"]},{"name":"mdi:timeline-check","tags":[]},{"name":"mdi:timeline-check-outline","tags":[]},{"name":"mdi:timeline-clock","tags":["date / time"]},{"name":"mdi:timeline-clock-outline","tags":["date / time"]},{"name":"mdi:timeline-minus","tags":[]},{"name":"mdi:timeline-minus-outline","tags":[]},{"name":"mdi:timeline-outline","tags":[]},{"name":"mdi:timeline-plus","tags":[]},{"name":"mdi:timeline-plus-outline","tags":[]},{"name":"mdi:timeline-question","tags":["timeline help"]},{"name":"mdi:timeline-question-outline","tags":["timeline help outline"]},{"name":"mdi:timeline-remove","tags":[]},{"name":"mdi:timeline-remove-outline","tags":[]},{"name":"mdi:timeline-text","tags":[]},{"name":"mdi:timeline-text-outline","tags":[]},{"name":"mdi:timer","tags":["sport","date / time","stopwatch"]},{"name":"mdi:timer-alert","tags":["date / time","alert / error","stopwatch alert"]},{"name":"mdi:timer-alert-outline","tags":["date / time","alert / error","stopwatch alert outline"]},{"name":"mdi:timer-cancel","tags":["date / time","stopwatch cancel"]},{"name":"mdi:timer-cancel-outline","tags":["date / time","stopwatch cancel outline"]},{"name":"mdi:timer-check","tags":["date / time","stopwatch check","timer tick","stopwatch tick"]},{"name":"mdi:timer-check-outline","tags":["date / time","timer tick outline","stopwatch check outline","stopwatch tick outline"]},{"name":"mdi:timer-cog","tags":["date / time","settings","timer settings"]},{"name":"mdi:timer-cog-outline","tags":["date / time","settings","timer settings outline"]},{"name":"mdi:timer-edit","tags":["date / time","edit / modify","stopwatch edit"]},{"name":"mdi:timer-edit-outline","tags":["date / time","edit / modify","stopwatch edit outline"]},{"name":"mdi:timer-lock","tags":["date / time","lock","stopwatch lock","timer secure","stopwatch secure"]},{"name":"mdi:timer-lock-open","tags":["date / time","lock","stopwatch lock open"]},{"name":"mdi:timer-lock-open-outline","tags":["date / time","lock","stopwatch lock open outline"]},{"name":"mdi:timer-lock-outline","tags":["date / time","lock","stopwatch lock outline","stopwatch secure outline","timer secure outline"]},{"name":"mdi:timer-marker","tags":["date / time","navigation","stopwatch marker","timer location","stopwatch location"]},{"name":"mdi:timer-marker-outline","tags":["date / time","navigation","stopwatch marker outline","timer location outline","stopwatch location outline"]},{"name":"mdi:timer-minus","tags":["date / time","timer subtract","stopwatch minus","stopwatch subtract"]},{"name":"mdi:timer-minus-outline","tags":["date / time","timer subtract outline","stopwatch minus outline","stopwatch subtract outline"]},{"name":"mdi:timer-music","tags":["date / time","music","stopwatch music"]},{"name":"mdi:timer-music-outline","tags":["date / time","music","stopwatch music outline"]},{"name":"mdi:timer-off","tags":["date / time","stopwatch off"]},{"name":"mdi:timer-pause","tags":["date / time","stopwatch pause"]},{"name":"mdi:timer-pause-outline","tags":["date / time","stopwatch pause outline"]},{"name":"mdi:timer-play","tags":["date / time","timer start","stopwatch play","stopwatch start"]},{"name":"mdi:timer-play-outline","tags":["date / time","timer start outline","stopwatch play outline","stopwatch start outline"]},{"name":"mdi:timer-plus","tags":["date / time","timer add","stopwatch plus","stopwatch add"]},{"name":"mdi:timer-plus-outline","tags":["date / time","timer add outline","stopwatch plus outline","stopwatch add outline"]},{"name":"mdi:timer-refresh","tags":["date / time","stopwatch refresh"]},{"name":"mdi:timer-refresh-outline","tags":["date / time","stopwatch refresh outline"]},{"name":"mdi:timer-remove","tags":["date / time","stopwatch remove"]},{"name":"mdi:timer-remove-outline","tags":["date / time","stopwatch remove outline"]},{"name":"mdi:timer-sand","tags":["date / time","hourglass"]},{"name":"mdi:timer-sand-complete","tags":["date / time","hourglass complete"]},{"name":"mdi:timer-sand-paused","tags":["date / time","hourglass paused"]},{"name":"mdi:timer-settings","tags":["date / time","settings"]},{"name":"mdi:timer-settings-outline","tags":["date / time","settings"]},{"name":"mdi:timer-star","tags":["date / time","timer favorite","stopwatch star","stopwatch favorite"]},{"name":"mdi:timer-star-outline","tags":["date / time","timer favorite outline","stopwatch star outline","stopwatch favorite outline"]},{"name":"mdi:timer-stop","tags":["date / time","stopwatch stop"]},{"name":"mdi:timer-stop-outline","tags":["date / time","stopwatch stop outline"]},{"name":"mdi:timer-sync","tags":["date / time","stopwatch sync"]},{"name":"mdi:timer-sync-outline","tags":["date / time","stopwatch sync outline"]},{"name":"mdi:timetable","tags":["date / time"]},{"name":"mdi:tire","tags":["automotive","agriculture","tyre","wheel"]},{"name":"mdi:toaster","tags":["home automation"]},{"name":"mdi:toaster-off","tags":["home automation"]},{"name":"mdi:toaster-oven","tags":["home automation","food / drink"]},{"name":"mdi:toggle-switch-variant","tags":["home automation","light switch on"]},{"name":"mdi:toggle-switch-variant-off","tags":["home automation","light switch off","rocker switch off"]},{"name":"mdi:toilet","tags":["home automation","bathroom","lavatory","bidet"]},{"name":"mdi:tools","tags":["hardware / tools","wrench","screwdriver"]},{"name":"mdi:tooltip","tags":["tooltip"]},{"name":"mdi:tooltip-cellphone","tags":["cellphone / phone","tooltip","cellphone location","cellphone gps","find my phone"]},{"name":"mdi:tooltip-check","tags":["tooltip"]},{"name":"mdi:tooltip-check-outline","tags":["tooltip"]},{"name":"mdi:tooltip-edit","tags":["tooltip","edit / modify"]},{"name":"mdi:tooltip-edit-outline","tags":["edit / modify","tooltip"]},{"name":"mdi:tooltip-image","tags":["tooltip"]},{"name":"mdi:tooltip-image-outline","tags":["tooltip"]},{"name":"mdi:tooltip-minus","tags":["tooltip"]},{"name":"mdi:tooltip-minus-outline","tags":["tooltip"]},{"name":"mdi:tooltip-outline","tags":["tooltip"]},{"name":"mdi:tooltip-plus","tags":["tooltip","tooltip add"]},{"name":"mdi:tooltip-plus-outline","tags":["tooltip","tooltip outline plus","tooltip add outline"]},{"name":"mdi:tooltip-question","tags":["tooltip","tooltip help"]},{"name":"mdi:tooltip-question-outline","tags":["tooltip","tooltip help outline"]},{"name":"mdi:tooltip-remove","tags":["tooltip"]},{"name":"mdi:tooltip-remove-outline","tags":["tooltip"]},{"name":"mdi:tooltip-text","tags":["tooltip"]},{"name":"mdi:tooltip-text-outline","tags":["tooltip"]},{"name":"mdi:tooth","tags":["medical / hospital","dentist"]},{"name":"mdi:tooth-outline","tags":["medical / hospital"]},{"name":"mdi:toothbrush","tags":["medical / hospital","dentist","oral hygiene"]},{"name":"mdi:toothbrush-electric","tags":["medical / hospital","dentist","oral hygiene"]},{"name":"mdi:toothbrush-paste","tags":["medical / hospital","dentist","oral hygiene"]},{"name":"mdi:torch","tags":["sport","olympics"]},{"name":"mdi:tortoise","tags":["animal","turtle","reptile"]},{"name":"mdi:toslink","tags":["audio","optical audio"]},{"name":"mdi:touch-text-outline","tags":[]},{"name":"mdi:tournament","tags":["gaming / rpg","sport","bracket"]},{"name":"mdi:tower-beach","tags":[]},{"name":"mdi:tower-fire","tags":[]},{"name":"mdi:town-hall","tags":["places","school"]},{"name":"mdi:toy-brick","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-marker","tags":["navigation","lego","plugin","extension","lego location","toy brick location"]},{"name":"mdi:toy-brick-marker-outline","tags":["navigation","extension outline","lego location outline","toy brick location outline","plugin outline","lego outline"]},{"name":"mdi:toy-brick-minus","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-minus-outline","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-outline","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-plus","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-plus-outline","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-remove","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-remove-outline","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-search","tags":["lego","plugin","extension"]},{"name":"mdi:toy-brick-search-outline","tags":["lego","plugin","extension"]},{"name":"mdi:track-light","tags":["home automation"]},{"name":"mdi:track-light-off","tags":[]},{"name":"mdi:trackpad","tags":[]},{"name":"mdi:trackpad-lock","tags":["lock"]},{"name":"mdi:tractor","tags":["agriculture","transportation + road","farm"]},{"name":"mdi:trademark","tags":["tm"]},{"name":"mdi:traffic-cone","tags":["transportation + road"]},{"name":"mdi:train-car-autorack","tags":["transportation + other"]},{"name":"mdi:train-car-box","tags":["transportation + other"]},{"name":"mdi:train-car-box-full","tags":["transportation + other"]},{"name":"mdi:train-car-box-open","tags":["transportation + other"]},{"name":"mdi:train-car-caboose","tags":["transportation + other"]},{"name":"mdi:train-car-centerbeam","tags":["transportation + other"]},{"name":"mdi:train-car-centerbeam-full","tags":["transportation + other"]},{"name":"mdi:train-car-container","tags":["transportation + other"]},{"name":"mdi:train-car-flatbed","tags":["transportation + other"]},{"name":"mdi:train-car-flatbed-car","tags":["transportation + other"]},{"name":"mdi:train-car-flatbed-tank","tags":["transportation + other"]},{"name":"mdi:train-car-gondola","tags":["transportation + other"]},{"name":"mdi:train-car-gondola-full","tags":["transportation + other"]},{"name":"mdi:train-car-hopper","tags":["transportation + other"]},{"name":"mdi:train-car-hopper-covered","tags":["transportation + other"]},{"name":"mdi:train-car-hopper-full","tags":["transportation + other"]},{"name":"mdi:train-car-intermodal","tags":["transportation + other"]},{"name":"mdi:train-car-passenger","tags":["transportation + other"]},{"name":"mdi:train-car-passenger-door","tags":["transportation + other"]},{"name":"mdi:train-car-passenger-door-open","tags":["transportation + other"]},{"name":"mdi:train-car-passenger-variant","tags":["transportation + other"]},{"name":"mdi:train-car-tank","tags":["transportation + other"]},{"name":"mdi:transcribe","tags":[]},{"name":"mdi:transcribe-close","tags":[]},{"name":"mdi:transfer","tags":[]},{"name":"mdi:transfer-down","tags":["arrow"]},{"name":"mdi:transfer-left","tags":["arrow"]},{"name":"mdi:transfer-right","tags":["arrow"]},{"name":"mdi:transfer-up","tags":["arrow"]},{"name":"mdi:transit-connection","tags":["transportation + other","navigation"]},{"name":"mdi:transit-connection-horizontal","tags":["transportation + other"]},{"name":"mdi:transit-connection-variant","tags":["transportation + other","navigation"]},{"name":"mdi:transit-detour","tags":["transportation + other","navigation"]},{"name":"mdi:transit-skip","tags":["transportation + other"]},{"name":"mdi:translate-off","tags":[]},{"name":"mdi:translate-variant","tags":["developer / languages","spoken language"]},{"name":"mdi:transmission-tower","tags":["home automation","pylon","powerline","electricity","energy","power","grid"]},{"name":"mdi:transmission-tower-export","tags":["home automation","power from grid","energy from grid","electricity from grid"]},{"name":"mdi:transmission-tower-import","tags":["home automation","power to grid","energy to grid","electricity to grid","return to grid"]},{"name":"mdi:transmission-tower-off","tags":["home automation","powerline off","pylon off","grid off"]},{"name":"mdi:trash-can","tags":["delete","rubbish bin","trashcan","garbage can"]},{"name":"mdi:trash-can-outline","tags":["delete outline","rubbish bin outline","trashcan outline","garbage can outline"]},{"name":"mdi:tray","tags":["queue","printer","inbox"]},{"name":"mdi:tray-alert","tags":["alert / error","queue","printer","inbox"]},{"name":"mdi:tray-arrow-down","tags":["arrow","tray download"]},{"name":"mdi:tray-arrow-up","tags":["arrow","tray upload"]},{"name":"mdi:tray-full","tags":["queue","printer","inbox"]},{"name":"mdi:tray-minus","tags":["queue","printer","inbox"]},{"name":"mdi:tray-plus","tags":["queue","printer","inbox"]},{"name":"mdi:tray-remove","tags":["queue","printer","inbox"]},{"name":"mdi:treasure-chest","tags":["gaming / rpg","shopping","lock","jewelry box","jewel case"]},{"name":"mdi:treasure-chest-outline","tags":["gaming / rpg","lock","shopping","jewel case outline","jewelry box outline"]},{"name":"mdi:tree","tags":["nature","agriculture","plant"]},{"name":"mdi:tree-outline","tags":["nature","agriculture","plant"]},{"name":"mdi:triangle","tags":["shape"]},{"name":"mdi:triangle-down","tags":["shape"]},{"name":"mdi:triangle-down-outline","tags":["shape"]},{"name":"mdi:triangle-outline","tags":["shape"]},{"name":"mdi:triangle-small-down","tags":["shape","trending down variant"]},{"name":"mdi:triangle-small-up","tags":["shape","trending up variant"]},{"name":"mdi:triangle-wave","tags":["audio"]},{"name":"mdi:triforce","tags":["gaming / rpg","zelda"]},{"name":"mdi:trophy","tags":["sport","achievement"]},{"name":"mdi:trophy-award","tags":["sport","achievement award"]},{"name":"mdi:trophy-broken","tags":["sport"]},{"name":"mdi:trophy-outline","tags":["sport","achievement outline"]},{"name":"mdi:trophy-variant","tags":["sport","achievement variant"]},{"name":"mdi:trophy-variant-outline","tags":["sport","achievement variant outline"]},{"name":"mdi:truck-alert","tags":["transportation + road","alert / error","truck error"]},{"name":"mdi:truck-alert-outline","tags":["transportation + road","alert / error","truck error outline"]},{"name":"mdi:truck-cargo-container","tags":["transportation + road","truck shipping"]},{"name":"mdi:truck-check","tags":["transportation + road","truck tick","lorry check","courier check"]},{"name":"mdi:truck-check-outline","tags":["transportation + road"]},{"name":"mdi:truck-delivery","tags":["transportation + road","lorry delivery"]},{"name":"mdi:truck-delivery-outline","tags":["transportation + road"]},{"name":"mdi:truck-fast","tags":["transportation + road","lorry fast","courier fast"]},{"name":"mdi:truck-fast-outline","tags":["transportation + road"]},{"name":"mdi:truck-flatbed","tags":["automotive","transportation + road","truck flatbed tow"]},{"name":"mdi:truck-minus","tags":["transportation + road","truck subtract"]},{"name":"mdi:truck-minus-outline","tags":["transportation + road","truck subtract outline"]},{"name":"mdi:truck-plus","tags":["transportation + road","medical / hospital","truck add"]},{"name":"mdi:truck-plus-outline","tags":["transportation + road","medical / hospital","truck add outline"]},{"name":"mdi:truck-remove","tags":["transportation + road"]},{"name":"mdi:truck-remove-outline","tags":["transportation + road"]},{"name":"mdi:truck-snowflake","tags":["transportation + road","truck refrigerator","truck freezer"]},{"name":"mdi:truck-trailer","tags":["transportation + road"]},{"name":"mdi:trumpet","tags":["music"]},{"name":"mdi:tshirt-crew","tags":["clothing","t shirt crew"]},{"name":"mdi:tshirt-crew-outline","tags":["clothing","t shirt crew outline"]},{"name":"mdi:tshirt-v","tags":["clothing","t shirt v"]},{"name":"mdi:tshirt-v-outline","tags":["clothing","t shirt v outline"]},{"name":"mdi:tumble-dryer","tags":["home automation","laundry room"]},{"name":"mdi:tumble-dryer-alert","tags":["home automation","alert / error","laundry room alert"]},{"name":"mdi:tumble-dryer-off","tags":["home automation","laundry room off"]},{"name":"mdi:tune-variant","tags":["audio","settings","settings","equalizer"]},{"name":"mdi:tune-vertical-variant","tags":["audio","settings","settings vertical","equalizer vertical"]},{"name":"mdi:tunnel","tags":["transportation + road","transportation + other"]},{"name":"mdi:tunnel-outline","tags":["transportation + road","transportation + other"]},{"name":"mdi:turbine","tags":["transportation + flying","jet engine","wind turbine"]},{"name":"mdi:turkey","tags":["animal","holiday","agriculture","thanksgiving"]},{"name":"mdi:turnstile","tags":[]},{"name":"mdi:turnstile-outline","tags":[]},{"name":"mdi:turtle","tags":["animal","reptile"]},{"name":"mdi:two-factor-authentication","tags":[]},{"name":"mdi:typewriter","tags":[]},{"name":"mdi:ufo","tags":["unidentified flying object","alien"]},{"name":"mdi:ufo-outline","tags":["unidentified flying object outline","alien"]},{"name":"mdi:ultra-high-definition","tags":["video / movie","uhd"]},{"name":"mdi:umbrella","tags":["weather"]},{"name":"mdi:umbrella-closed","tags":["weather"]},{"name":"mdi:umbrella-closed-outline","tags":["weather"]},{"name":"mdi:umbrella-closed-variant","tags":["weather"]},{"name":"mdi:umbrella-outline","tags":["weather"]},{"name":"mdi:undo-variant","tags":["arrow"]},{"name":"mdi:unfold-less-vertical","tags":["chevron right left","collapse vertical"]},{"name":"mdi:unfold-more-vertical","tags":["chevron left right","expand vertical"]},{"name":"mdi:ungroup","tags":[]},{"name":"mdi:unicorn","tags":["animal","fantasy"]},{"name":"mdi:unicorn-variant","tags":["animal","fantasy variant"]},{"name":"mdi:unicycle","tags":["sport","transportation + other"]},{"name":"mdi:upload-lock","tags":["lock"]},{"name":"mdi:upload-lock-outline","tags":["lock"]},{"name":"mdi:upload-multiple","tags":["uploads"]},{"name":"mdi:upload-network","tags":[]},{"name":"mdi:upload-network-outline","tags":[]},{"name":"mdi:upload-off","tags":[]},{"name":"mdi:upload-off-outline","tags":[]},{"name":"mdi:upload-outline","tags":["file upload outline"]},{"name":"mdi:usb-flash-drive","tags":[]},{"name":"mdi:usb-flash-drive-outline","tags":[]},{"name":"mdi:usb-port","tags":[]},{"name":"mdi:valve","tags":["home automation"]},{"name":"mdi:valve-closed","tags":["home automation"]},{"name":"mdi:valve-open","tags":["home automation"]},{"name":"mdi:van-passenger","tags":["transportation + road"]},{"name":"mdi:van-utility","tags":["transportation + road","van candy"]},{"name":"mdi:vanish","tags":[]},{"name":"mdi:vanish-quarter","tags":[]},{"name":"mdi:vanity-light","tags":["home automation"]},{"name":"mdi:variable","tags":["developer / languages","math"]},{"name":"mdi:variable-box","tags":["developer / languages"]},{"name":"mdi:vector-arrange-above","tags":["vector","arrange","geographic information system"]},{"name":"mdi:vector-arrange-below","tags":["vector","arrange","geographic information system"]},{"name":"mdi:vector-bezier","tags":["vector"]},{"name":"mdi:vector-circle","tags":["vector","geographic information system"]},{"name":"mdi:vector-circle-variant","tags":["vector"]},{"name":"mdi:vector-combine","tags":["vector","geographic information system"]},{"name":"mdi:vector-curve","tags":["vector","geographic information system","bezier"]},{"name":"mdi:vector-difference","tags":["vector","geographic information system"]},{"name":"mdi:vector-difference-ab","tags":["vector","geographic information system"]},{"name":"mdi:vector-difference-ba","tags":["vector","geographic information system"]},{"name":"mdi:vector-ellipse","tags":["vector","geographic information system"]},{"name":"mdi:vector-intersection","tags":["vector","geographic information system"]},{"name":"mdi:vector-line","tags":["vector","geographic information system"]},{"name":"mdi:vector-link","tags":["vector","geographic information system"]},{"name":"mdi:vector-point","tags":["vector"]},{"name":"mdi:vector-point-edit","tags":["vector","edit / modify"]},{"name":"mdi:vector-point-minus","tags":["vector"]},{"name":"mdi:vector-point-plus","tags":["vector","vector point add"]},{"name":"mdi:vector-point-select","tags":["vector","geographic information system"]},{"name":"mdi:vector-polygon","tags":["vector","geographic information system"]},{"name":"mdi:vector-polygon-variant","tags":["vector"]},{"name":"mdi:vector-polyline","tags":["vector","geographic information system"]},{"name":"mdi:vector-polyline-edit","tags":["edit / modify"]},{"name":"mdi:vector-polyline-minus","tags":[]},{"name":"mdi:vector-polyline-plus","tags":[]},{"name":"mdi:vector-polyline-remove","tags":[]},{"name":"mdi:vector-radius","tags":["vector","geographic information system"]},{"name":"mdi:vector-rectangle","tags":["vector","geographic information system"]},{"name":"mdi:vector-selection","tags":["vector","geographic information system"]},{"name":"mdi:vector-square","tags":["vector","geographic information system","mdi"]},{"name":"mdi:vector-square-close","tags":["vector"]},{"name":"mdi:vector-square-edit","tags":["vector","edit / modify"]},{"name":"mdi:vector-square-minus","tags":["vector","vector square subtract"]},{"name":"mdi:vector-square-open","tags":["vector"]},{"name":"mdi:vector-square-plus","tags":["vector","vector square add"]},{"name":"mdi:vector-square-remove","tags":["vector","vector square delete"]},{"name":"mdi:vector-triangle","tags":["vector","geographic information system"]},{"name":"mdi:vector-union","tags":["vector","geographic information system"]},{"name":"mdi:vhs","tags":["video / movie","video home system","vhs cassette","vhs tape"]},{"name":"mdi:vibrate-off","tags":[]},{"name":"mdi:video-2d","tags":["video / movie"]},{"name":"mdi:video-3d","tags":["video / movie"]},{"name":"mdi:video-3d-off","tags":["video / movie"]},{"name":"mdi:video-3d-variant","tags":["video / movie"]},{"name":"mdi:video-check","tags":["video / movie"]},{"name":"mdi:video-check-outline","tags":["video / movie"]},{"name":"mdi:video-high-definition","tags":["video / movie"]},{"name":"mdi:video-input-scart","tags":["video / movie"]},{"name":"mdi:video-marker","tags":["video / movie","navigation","video location"]},{"name":"mdi:video-marker-outline","tags":["video / movie","navigation","video location outline"]},{"name":"mdi:video-minus-outline","tags":["video / movie"]},{"name":"mdi:video-plus-outline","tags":["video / movie"]},{"name":"mdi:video-vintage","tags":["video / movie","video film","video classic"]},{"name":"mdi:video-wireless","tags":["video / movie"]},{"name":"mdi:video-wireless-outline","tags":["video / movie"]},{"name":"mdi:view-dashboard-edit","tags":["view","edit / modify"]},{"name":"mdi:view-dashboard-edit-outline","tags":["view","edit / modify"]},{"name":"mdi:view-dashboard-variant-outline","tags":["view"]},{"name":"mdi:view-gallery","tags":["view"]},{"name":"mdi:view-gallery-outline","tags":["view"]},{"name":"mdi:view-grid","tags":["view"]},{"name":"mdi:view-grid-compact","tags":[]},{"name":"mdi:view-grid-outline","tags":["view"]},{"name":"mdi:view-grid-plus-outline","tags":["view"]},{"name":"mdi:view-parallel","tags":["view"]},{"name":"mdi:view-parallel-outline","tags":["view"]},{"name":"mdi:view-sequential","tags":["view"]},{"name":"mdi:view-sequential-outline","tags":["view"]},{"name":"mdi:virtual-reality","tags":["vr"]},{"name":"mdi:virus","tags":["science","medical / hospital"]},{"name":"mdi:virus-off","tags":["science"]},{"name":"mdi:virus-off-outline","tags":["science"]},{"name":"mdi:virus-outline","tags":["science","medical / hospital"]},{"name":"mdi:volume-equal","tags":["audio"]},{"name":"mdi:volume-minus","tags":["audio","home automation","cellphone / phone","volume decrease"]},{"name":"mdi:volume-mute","tags":["audio","cellphone / phone"]},{"name":"mdi:volume-plus","tags":["audio","home automation","cellphone / phone","volume increase"]},{"name":"mdi:volume-variant-off","tags":["audio","cellphone / phone"]},{"name":"mdi:volume-vibrate","tags":["cellphone / phone","audio"]},{"name":"mdi:vpn","tags":["virtual private network"]},{"name":"mdi:wall","tags":["bricks"]},{"name":"mdi:wall-fire","tags":["device / tech","firewall"]},{"name":"mdi:wall-sconce","tags":["home automation"]},{"name":"mdi:wall-sconce-flat","tags":["home automation","ceiling light flat","pot light flat"]},{"name":"mdi:wall-sconce-flat-outline","tags":["home automation"]},{"name":"mdi:wall-sconce-flat-variant","tags":["home automation","pot light flat variant"]},{"name":"mdi:wall-sconce-flat-variant-outline","tags":["home automation"]},{"name":"mdi:wall-sconce-outline","tags":["home automation"]},{"name":"mdi:wall-sconce-round","tags":["home automation","pot light round"]},{"name":"mdi:wall-sconce-round-outline","tags":["home automation"]},{"name":"mdi:wall-sconce-round-variant","tags":["home automation","pot light round variant"]},{"name":"mdi:wall-sconce-round-variant-outline","tags":["home automation"]},{"name":"mdi:wallet-bifold","tags":["currency","banking"]},{"name":"mdi:wallet-bifold-outline","tags":["banking","currency"]},{"name":"mdi:wallet-plus","tags":["banking","wallet add"]},{"name":"mdi:wallet-plus-outline","tags":["banking","wallet add outline"]},{"name":"mdi:wan","tags":["wide area network"]},{"name":"mdi:wardrobe","tags":["home automation","closet"]},{"name":"mdi:wardrobe-outline","tags":["home automation","closet outline"]},{"name":"mdi:warehouse","tags":["places"]},{"name":"mdi:washing-machine-alert","tags":["home automation","alert / error","laundry room alert"]},{"name":"mdi:washing-machine-off","tags":["home automation","laundry room off"]},{"name":"mdi:watch-export","tags":["device / tech"]},{"name":"mdi:watch-export-variant","tags":["device / tech"]},{"name":"mdi:watch-import","tags":["device / tech"]},{"name":"mdi:watch-import-variant","tags":["device / tech"]},{"name":"mdi:watch-variant","tags":["device / tech"]},{"name":"mdi:watch-vibrate","tags":["device / tech"]},{"name":"mdi:watch-vibrate-off","tags":["device / tech"]},{"name":"mdi:water-alert","tags":["alert / error","agriculture","drop alert","blood alert","ink alert"]},{"name":"mdi:water-alert-outline","tags":["alert / error","agriculture","drop alert outline","blood alert outline","ink alert outline"]},{"name":"mdi:water-boiler","tags":["home automation","water heater","gas water boiler","electric water boiler","gas water heater","electric water heater"]},{"name":"mdi:water-boiler-alert","tags":["home automation","alert / error","water heater alert","water boiler error","water heater error"]},{"name":"mdi:water-boiler-auto","tags":["home automation","water heater auto"]},{"name":"mdi:water-boiler-off","tags":["home automation","water heater off"]},{"name":"mdi:water-check","tags":["drop check","blood check","ink check"]},{"name":"mdi:water-check-outline","tags":["drop check outline","blood check outline","ink check outline"]},{"name":"mdi:water-circle","tags":["home automation","drop circle","blood circle","ink circle"]},{"name":"mdi:water-minus","tags":["drop minus","blood minus","ink minus"]},{"name":"mdi:water-minus-outline","tags":["drop minus outline","blood minus outline","ink minus outline"]},{"name":"mdi:water-off-outline","tags":["drop off outline","blood off outline","trans fat off outline","ink off outline"]},{"name":"mdi:water-opacity","tags":["home automation","drawing / art","weather","water transparent","water saver","blood saver","blood transparent","oil saver","oil transparent","drop transparent","drop saver"]},{"name":"mdi:water-outline","tags":["home automation","weather","drop outline","blood outline","water drop outline","ink outline"]},{"name":"mdi:water-percent","tags":["weather","home automation","nature","humidity","ink percent"]},{"name":"mdi:water-percent-alert","tags":["alert / error","nature","humidity alert","ink percent alert"]},{"name":"mdi:water-plus","tags":["drop plus","blood plus","ink plus"]},{"name":"mdi:water-plus-outline","tags":["drop plus outline","blood plus outline","ink plus outline"]},{"name":"mdi:water-polo","tags":["sport"]},{"name":"mdi:water-pump","tags":["agriculture","home automation","tap","kitchen tap","faucet"]},{"name":"mdi:water-pump-off","tags":["agriculture","home automation","tap off","kitchen tap off","faucet off"]},{"name":"mdi:water-remove","tags":["drop remove","blood remove","ink remove"]},{"name":"mdi:water-remove-outline","tags":["drop remove outline","blood remove outline","ink remove outline"]},{"name":"mdi:water-sync","tags":["agriculture","water recycle","water reuse"]},{"name":"mdi:water-thermometer","tags":["weather","home automation","boil point","water temperature","dew point"]},{"name":"mdi:water-thermometer-outline","tags":["weather","home automation","dew point outline","water temperature outline","boil point outline"]},{"name":"mdi:water-well","tags":[]},{"name":"mdi:water-well-outline","tags":[]},{"name":"mdi:waterfall","tags":["home automation","nature"]},{"name":"mdi:watering-can","tags":["agriculture","watering pot"]},{"name":"mdi:watering-can-outline","tags":["agriculture","watering pot outline"]},{"name":"mdi:wave","tags":["transportation + water","water"]},{"name":"mdi:waveform","tags":["audio"]},{"name":"mdi:waves","tags":["weather","transportation + water","agriculture","ocean","lake","flood","water"]},{"name":"mdi:waves-arrow-left","tags":["nature","weather","tide in","water flow"]},{"name":"mdi:waves-arrow-right","tags":["nature","weather","tide out","water flow"]},{"name":"mdi:waves-arrow-up","tags":["nature","weather","water evaporation","humidity","sea level rise","ocean level rise","climate change"]},{"name":"mdi:weather-cloudy","tags":["weather","cloud","agriculture"]},{"name":"mdi:weather-cloudy-alert","tags":["weather","alert / error","cloud"]},{"name":"mdi:weather-cloudy-arrow-right","tags":["weather","cloud"]},{"name":"mdi:weather-cloudy-clock","tags":["weather","cloud","weather history","weather time","weather date"]},{"name":"mdi:weather-dust","tags":["weather","agriculture","dust storm","windy"]},{"name":"mdi:weather-fog","tags":["weather","agriculture","weather mist"]},{"name":"mdi:weather-hail","tags":["weather","agriculture"]},{"name":"mdi:weather-hazy","tags":["weather","agriculture"]},{"name":"mdi:weather-hurricane","tags":["weather","nature","agriculture","cyclone"]},{"name":"mdi:weather-hurricane-outline","tags":["weather","nature","agriculture","cyclone outline"]},{"name":"mdi:weather-lightning","tags":["weather","agriculture","weather storm","weather thunder","weather flash"]},{"name":"mdi:weather-lightning-rainy","tags":["weather","weather thunder rainy","weather storm"]},{"name":"mdi:weather-night","tags":["weather","holiday","moon and stars","night sky"]},{"name":"mdi:weather-night-partly-cloudy","tags":["weather","cloud"]},{"name":"mdi:weather-partly-cloudy","tags":["weather","cloud","weather partlycloudy"]},{"name":"mdi:weather-partly-lightning","tags":["weather"]},{"name":"mdi:weather-partly-rainy","tags":["weather"]},{"name":"mdi:weather-partly-snowy","tags":["weather"]},{"name":"mdi:weather-partly-snowy-rainy","tags":["weather"]},{"name":"mdi:weather-pouring","tags":["weather","agriculture","weather heavy rain"]},{"name":"mdi:weather-rainy","tags":["weather","agriculture","weather drizzle","weather spitting"]},{"name":"mdi:weather-snowy","tags":["weather"]},{"name":"mdi:weather-snowy-heavy","tags":["weather","flurries"]},{"name":"mdi:weather-snowy-rainy","tags":["weather","weather sleet"]},{"name":"mdi:weather-sunny","tags":["weather"]},{"name":"mdi:weather-sunny-alert","tags":["weather","alert / error","home automation","heat alert","heat advisory","sun advisory"]},{"name":"mdi:weather-sunny-off","tags":["weather"]},{"name":"mdi:weather-sunset","tags":["weather"]},{"name":"mdi:weather-sunset-down","tags":["weather"]},{"name":"mdi:weather-sunset-up","tags":["weather","sunrise"]},{"name":"mdi:weather-tornado","tags":["weather"]},{"name":"mdi:weather-windy","tags":["weather"]},{"name":"mdi:weather-windy-variant","tags":["weather"]},{"name":"mdi:web-box","tags":["geographic information system","language box","globe box","internet box"]},{"name":"mdi:web-cancel","tags":[]},{"name":"mdi:web-check","tags":[]},{"name":"mdi:web-clock","tags":["date / time"]},{"name":"mdi:web-minus","tags":[]},{"name":"mdi:web-off","tags":[]},{"name":"mdi:web-plus","tags":[]},{"name":"mdi:web-refresh","tags":[]},{"name":"mdi:web-remove","tags":[]},{"name":"mdi:web-sync","tags":[]},{"name":"mdi:webcam","tags":["video / movie","home automation","web camera"]},{"name":"mdi:webcam-off","tags":[]},{"name":"mdi:webhook","tags":[]},{"name":"mdi:weight","tags":[]},{"name":"mdi:weight-gram","tags":[]},{"name":"mdi:weight-kilogram","tags":["weight kg"]},{"name":"mdi:weight-lifter","tags":["sport","people / family","crossfit","gym","fitness center","human barbell"]},{"name":"mdi:weight-pound","tags":["weight lb"]},{"name":"mdi:wheel-barrow","tags":["hardware / tools"]},{"name":"mdi:wheelchair","tags":["medical / hospital","people / family","accessible","isa","international symbol of access"]},{"name":"mdi:wheelchair-accessibility","tags":["medical / hospital","accessible"]},{"name":"mdi:whistle","tags":["sport"]},{"name":"mdi:whistle-outline","tags":["sport"]},{"name":"mdi:wifi","tags":[]},{"name":"mdi:wifi-alert","tags":["alert / error"]},{"name":"mdi:wifi-arrow-down","tags":[]},{"name":"mdi:wifi-arrow-left","tags":[]},{"name":"mdi:wifi-arrow-left-right","tags":[]},{"name":"mdi:wifi-arrow-right","tags":[]},{"name":"mdi:wifi-arrow-up","tags":[]},{"name":"mdi:wifi-arrow-up-down","tags":[]},{"name":"mdi:wifi-cancel","tags":[]},{"name":"mdi:wifi-check","tags":[]},{"name":"mdi:wifi-cog","tags":["settings"]},{"name":"mdi:wifi-lock","tags":["lock"]},{"name":"mdi:wifi-lock-open","tags":["lock"]},{"name":"mdi:wifi-marker","tags":["navigation","wifi location"]},{"name":"mdi:wifi-minus","tags":[]},{"name":"mdi:wifi-off","tags":[]},{"name":"mdi:wifi-plus","tags":[]},{"name":"mdi:wifi-refresh","tags":[]},{"name":"mdi:wifi-remove","tags":[]},{"name":"mdi:wifi-settings","tags":["settings"]},{"name":"mdi:wifi-star","tags":["wifi favourite","network favourite","wifi favorite","network favorite"]},{"name":"mdi:wifi-strength-1","tags":[]},{"name":"mdi:wifi-strength-1-alert","tags":["alert / error","wifi strength 1 warning"]},{"name":"mdi:wifi-strength-1-lock","tags":["lock"]},{"name":"mdi:wifi-strength-1-lock-open","tags":["lock"]},{"name":"mdi:wifi-strength-2","tags":[]},{"name":"mdi:wifi-strength-2-alert","tags":["alert / error","wifi strength 2 warning"]},{"name":"mdi:wifi-strength-2-lock","tags":["lock"]},{"name":"mdi:wifi-strength-2-lock-open","tags":["lock"]},{"name":"mdi:wifi-strength-3","tags":[]},{"name":"mdi:wifi-strength-3-alert","tags":["alert / error","wifi strength 3 warning"]},{"name":"mdi:wifi-strength-3-lock","tags":["lock"]},{"name":"mdi:wifi-strength-3-lock-open","tags":["lock"]},{"name":"mdi:wifi-strength-4","tags":[]},{"name":"mdi:wifi-strength-4-alert","tags":["alert / error","wifi strength 4 warning"]},{"name":"mdi:wifi-strength-4-lock","tags":["lock"]},{"name":"mdi:wifi-strength-4-lock-open","tags":["lock"]},{"name":"mdi:wifi-strength-alert-outline","tags":["alert / error","wifi strength warning outline","wifi strength 0 alert","wifi strength 0 warning"]},{"name":"mdi:wifi-strength-lock-open-outline","tags":["lock"]},{"name":"mdi:wifi-strength-lock-outline","tags":["lock","wifi strength 0 lock"]},{"name":"mdi:wifi-strength-off","tags":[]},{"name":"mdi:wifi-strength-off-outline","tags":[]},{"name":"mdi:wifi-strength-outline","tags":["wifi strength 0"]},{"name":"mdi:wifi-sync","tags":[]},{"name":"mdi:wind-turbine-alert","tags":["home automation","alert / error","wind power alert","wind turbine warning"]},{"name":"mdi:wind-turbine-check","tags":["home automation","wind power check","wind turbine success","wind power success"]},{"name":"mdi:window-close","tags":["cancel","close"]},{"name":"mdi:window-closed","tags":["home automation"]},{"name":"mdi:window-closed-variant","tags":["home automation"]},{"name":"mdi:window-maximize","tags":[]},{"name":"mdi:window-minimize","tags":[]},{"name":"mdi:window-open","tags":["home automation"]},{"name":"mdi:window-open-variant","tags":["home automation"]},{"name":"mdi:window-restore","tags":[]},{"name":"mdi:window-shutter","tags":["home automation"]},{"name":"mdi:window-shutter-alert","tags":["home automation","alert / error"]},{"name":"mdi:window-shutter-auto","tags":["home automation"]},{"name":"mdi:window-shutter-cog","tags":["home automation","settings","window shutter settings"]},{"name":"mdi:window-shutter-open","tags":["home automation"]},{"name":"mdi:window-shutter-settings","tags":["home automation","settings"]},{"name":"mdi:windsock","tags":["weather"]},{"name":"mdi:wiper","tags":[]},{"name":"mdi:wiper-wash","tags":["automotive","wiper fluid","washer fluid"]},{"name":"mdi:wiper-wash-alert","tags":["alert / error","automotive","wiper fluid alert","washer fluid alert","wiper fluid low","washer fluid low"]},{"name":"mdi:wizard-hat","tags":["clothing","gaming / rpg"]},{"name":"mdi:wrap","tags":[]},{"name":"mdi:wrap-disabled","tags":["unwrap"]},{"name":"mdi:wrench-check","tags":[]},{"name":"mdi:wrench-check-outline","tags":[]},{"name":"mdi:wrench-clock","tags":["date / time","hardware / tools","scheduled maintenance","wrench time","tool time","tool clock"]},{"name":"mdi:wrench-clock-outline","tags":["date / time"]},{"name":"mdi:wrench-cog","tags":["settings","wrench settings"]},{"name":"mdi:wrench-cog-outline","tags":["settings","wrench settings outline"]},{"name":"mdi:xml","tags":["developer / languages","code"]},{"name":"mdi:yeast","tags":[]},{"name":"mdi:yin-yang","tags":["taoism"]},{"name":"mdi:yoga","tags":["sport"]},{"name":"mdi:yurt","tags":[]},{"name":"mdi:zip-box-outline","tags":["files / folders","compressed file outline"]},{"name":"mdi:zip-disk","tags":[]},{"name":"mdi:zodiac-aquarius","tags":["horoscope aquarius"]},{"name":"mdi:zodiac-aries","tags":["horoscope aries"]},{"name":"mdi:zodiac-cancer","tags":["horoscope cancer"]},{"name":"mdi:zodiac-capricorn","tags":["horoscope capricorn"]},{"name":"mdi:zodiac-gemini","tags":["horoscope gemini"]},{"name":"mdi:zodiac-leo","tags":["horoscope leo"]},{"name":"mdi:zodiac-libra","tags":["horoscope libra"]},{"name":"mdi:zodiac-pisces","tags":["horoscope pisces"]},{"name":"mdi:zodiac-sagittarius","tags":["horoscope sagittarius"]},{"name":"mdi:zodiac-scorpio","tags":["horoscope scorpio"]},{"name":"mdi:zodiac-taurus","tags":["horoscope taurus"]},{"name":"mdi:zodiac-virgo","tags":["horoscope virgo"]}] \ No newline at end of file diff --git a/ui-ngx/src/assets/widget/value-card/centered-layout.svg b/ui-ngx/src/assets/widget/value-card/centered-layout.svg new file mode 100644 index 0000000000..9c8d5f38ae --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/centered-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/horizontal-layout.svg b/ui-ngx/src/assets/widget/value-card/horizontal-layout.svg new file mode 100644 index 0000000000..283ddd461d --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/horizontal-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/horizontal-reversed-layout.svg b/ui-ngx/src/assets/widget/value-card/horizontal-reversed-layout.svg new file mode 100644 index 0000000000..275f45fab9 --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/horizontal-reversed-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/simplified-layout.svg b/ui-ngx/src/assets/widget/value-card/simplified-layout.svg new file mode 100644 index 0000000000..9488bc78e5 --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/simplified-layout.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/square-layout.svg b/ui-ngx/src/assets/widget/value-card/square-layout.svg new file mode 100644 index 0000000000..87b087cdad --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/square-layout.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-card/vertical-layout.svg b/ui-ngx/src/assets/widget/value-card/vertical-layout.svg new file mode 100644 index 0000000000..e2baba8ce4 --- /dev/null +++ b/ui-ngx/src/assets/widget/value-card/vertical-layout.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 2753fc745d..4a4c018549 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -66,6 +66,7 @@ overflow: visible; } > .mat-expansion-panel-header { + user-select: none; font-weight: 500; font-size: 16px; line-height: 24px; @@ -138,6 +139,13 @@ padding: 7px 7px 7px 16px; border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 6px; + &.no-border { + border: none; + border-radius: 0; + } + &.no-padding { + padding: 0; + } &.same-padding { padding-right: 16px; } @@ -154,9 +162,18 @@ &.medium-width { width: 220px; } + @media #{$mat-xs} { + width: auto; + &.medium-width { + width: auto; + } + } } .fixed-title-width { min-width: 200px; + @media #{$mat-xs} { + min-width: 0; + } } .mat-slide:only-child { margin: 8px 0; @@ -193,7 +210,7 @@ } .mat-mdc-text-field-wrapper { &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { - &:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(:hover) { + &:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(.mdc-text-field--invalid):not(:hover) { .mdc-notched-outline__leading, .mdc-notched-outline__trailing { border-color: rgba(0, 0, 0, 0.12); } @@ -416,4 +433,27 @@ line-height: 16px; } } + + button.mat-mdc-button-base.tb-box-button { + width: 40px; + min-width: 40px; + height: 40px; + padding: 7px; + .mat-mdc-button-touch-target { + width: 40px; + height: 40px; + } + &:not(:disabled) { + color: rgba(0, 0, 0, 0.54); + } + &:disabled { + color: rgba(0, 0, 0, 0.12); + } + > .mat-icon { + width: 24px; + height: 24px; + font-size: 24px; + margin: 0; + } + } } diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index 127d60e3e5..d8bbdf743d 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -624,7 +624,7 @@ mat-label { .mat-toolbar.mat-primary { button.mat-mdc-icon-button { - mat-icon { + .mat-icon { color: white; } } @@ -648,11 +648,11 @@ mat-label { mat-toolbar.mat-mdc-table-toolbar:not(.mat-primary), .mat-mdc-cell, .mat-expansion-panel-header { button.mat-mdc-icon-button { - mat-icon { + .mat-icon { color: rgba(0, 0, 0, .54); } &[disabled][disabled] { - mat-icon { + .mat-icon { color: rgba(0, 0, 0, .26); } } @@ -791,7 +791,7 @@ mat-label { &.mat-number-cell { text-align: end; } - mat-icon { + .mat-icon { color: rgba(0, 0, 0, .54); } } @@ -951,7 +951,7 @@ mat-label { padding: 0 6px; min-width: 88px; } - mat-icon { + .mat-icon { margin-right: 5px; } } @@ -1051,7 +1051,7 @@ mat-label { background: #ccc; opacity: .85; - mat-icon { + .mat-icon { color: #666; } } @@ -1094,7 +1094,17 @@ mat-label { box-shadow: none; border-radius: 4px; .tb-color-result { - border: 1px solid rgba(0, 0, 0, 0.12); + position: relative; + &:after { + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + border-radius: 4px; + border: 1px solid rgba(0, 0, 0, 0.12); + } } &.disabled { cursor: initial; @@ -1155,7 +1165,7 @@ mat-label { .tb-drag-handle { cursor: move; - mat-icon { + .mat-icon { pointer-events: none; } } From 03b49f1ddd57419a68b7cdd7ad86659a65db1dfc Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 21 Jul 2023 18:56:06 +0300 Subject: [PATCH 304/421] Clear code --- .../DeviceConnectivityController.java | 1 - .../server/controller/DeviceController.java | 1 - .../DeviceConnectivityControllerTest.java | 41 ------------------- .../controller/DeviceControllerTest.java | 1 + .../dao/device/DeviceConnectivityService.java | 1 - ...e-check-connectivity-dialog.component.html | 32 +++++++-------- 6 files changed, 17 insertions(+), 60 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java index bf745a2033..abd45e0ca3 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java @@ -42,7 +42,6 @@ import org.thingsboard.server.service.security.system.SystemSecurityService; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URISyntaxException; -import java.util.Map; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION; diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java index 3eb6202aea..d73915b617 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java @@ -134,7 +134,6 @@ public class DeviceController extends BaseController { private final TbDeviceService tbDeviceService; - @ApiOperation(value = "Get Device (getDeviceById)", notes = "Fetch the Device object based on the provided Device Id. " + "If the user has the authority of 'TENANT_ADMIN', the server checks that the device is owned by the same tenant. " + diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index b138778025..9fd8990a40 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -15,84 +15,43 @@ */ package org.thingsboard.server.controller; -import com.datastax.oss.driver.api.core.uuid.Uuids; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.mockito.AdditionalAnswers; import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; -import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.DeviceInfo; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.EntitySubtype; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.OtaPackageInfo; -import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; -import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; -import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.DeviceCredentialsId; -import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.relation.EntityRelation; -import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; -import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType; -import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest; -import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult; import org.thingsboard.server.dao.device.DeviceDao; -import org.thingsboard.server.dao.exception.DataValidationException; -import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; -import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.service.DaoSqlTest; -import org.thingsboard.server.service.gateway_device.GatewayNotificationsService; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; -import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; -import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAP; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER; diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java index 9ab5f7fde8..1c952bd549 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java @@ -84,6 +84,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; + @ContextConfiguration(classes = {DeviceControllerTest.Config.class}) @DaoSqlTest public class DeviceControllerTest extends AbstractControllerTest { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java index 83f35d5566..51643fa1d4 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java @@ -20,7 +20,6 @@ import org.thingsboard.server.common.data.Device; import java.io.IOException; import java.net.URISyntaxException; -import java.util.Map; public interface DeviceConnectivityService { diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html index a595487521..01d2330aa3 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html @@ -144,8 +144,8 @@
@@ -165,8 +165,8 @@
@@ -186,14 +186,14 @@
- + Docker @@ -202,8 +202,8 @@
@@ -228,8 +228,8 @@
@@ -249,14 +249,14 @@
- + Docker @@ -265,8 +265,8 @@
From 8b19b5d1695c58ea958fbadd43b59dadf278c41f Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Fri, 21 Jul 2023 18:56:52 +0300 Subject: [PATCH 305/421] added curl command for mqtts --- .../ThingsboardSecurityConfiguration.java | 5 +- .../DeviceConnectivityController.java | 1 - .../DeviceConnectivityControllerTest.java | 51 +++++----- .../DeviceСonnectivityServiceImpl.java | 99 +++++++++++-------- .../dao/util/DeviceConnectivityUtil.java | 16 ++- 5 files changed, 100 insertions(+), 72 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java index 793670f0ab..56a687be21 100644 --- a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java @@ -78,6 +78,7 @@ public class ThingsboardSecurityConfiguration { public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; public static final String MAIL_OAUTH2_PROCESSING_ENTRY_POINT = "/api/admin/mail/oauth2/code"; + public static final String DEVICE_CONNECTIVITY_CERTIFICATE_DOWNLOAD_ENTRY_POINT = "/api/device-connectivity/mqtts/certificate/download"; @Autowired private ThingsboardErrorResponseHandler restAccessDeniedHandler; @@ -136,7 +137,8 @@ public class ThingsboardSecurityConfiguration { protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception { List pathsToSkip = new ArrayList<>(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, - PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT, MAIL_OAUTH2_PROCESSING_ENTRY_POINT)); + PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT, MAIL_OAUTH2_PROCESSING_ENTRY_POINT, + DEVICE_CONNECTIVITY_CERTIFICATE_DOWNLOAD_ENTRY_POINT)); SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT); JwtTokenAuthenticationProcessingFilter filter = new JwtTokenAuthenticationProcessingFilter(failureHandler, jwtHeaderTokenExtractor, matcher); @@ -204,6 +206,7 @@ public class ThingsboardSecurityConfiguration { .antMatchers(PUBLIC_LOGIN_ENTRY_POINT).permitAll() // Public login end-point .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point .antMatchers(MAIL_OAUTH2_PROCESSING_ENTRY_POINT).permitAll() // Mail oauth2 code processing url + .antMatchers(DEVICE_CONNECTIVITY_CERTIFICATE_DOWNLOAD_ENTRY_POINT).permitAll() // Mail oauth2 code processing url .antMatchers(NON_TOKEN_BASED_AUTH_ENTRY_POINTS).permitAll() // static resources, user activation and password reset end-points .and() .authorizeRequests() diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java index bf745a2033..c11efc05a4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java @@ -89,7 +89,6 @@ public class DeviceConnectivityController extends BaseController { } @ApiOperation(value = "Download mqtt ssl certificate using file path defined in device.connectivity properties (downloadMqttServerCertificate)", notes = "Download Mqtt server certificate." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @RequestMapping(value = "/device-connectivity/{protocol}/certificate/download", method = RequestMethod.GET) @ResponseBody public ResponseEntity downloadMqttServerCertificate(@ApiParam(value = PROTOCOL_PARAM_DESCRIPTION) diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index b138778025..05c14dbb8b 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -217,17 +217,17 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + "-u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); - assertThat(mqttCommands.get(MQTTS).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile pathToFile/tb-server-chain.pem -h localhost -p 8883 " + - "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", - credentials.getCredentialsId())); - + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl http://localhost:80/api/device-connectivity/mqtts/certificate/download -o /tmp/tb-server-chain.pem"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tmp/tb-server-chain.pem -h localhost -p 8883 " + + "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + " -p 1883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); - assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --volume pathToFile/tb-server-chain.pem:/tmp/tb-server-chain.pem " + - "-it --rm thingsboard/mosquitto-clients pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients " + + "/bin/sh -c \"curl -o /tmp/tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"\"", credentials.getCredentialsId())); JsonNode linuxCoapCommands = commands.get(COAP); @@ -251,21 +251,20 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId() , new TypeReference<>() {}); assertThat(commands).hasSize(1); - JsonNode linuxMqttCommands = commands.get(MQTT); - assertThat(linuxMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + - "-u %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - assertThat(linuxMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile pathToFile/tb-server-chain.pem -h localhost -p 8883 " + - "-t %s -u %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - + JsonNode mqttCommands = commands.get(MQTT); + assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + + "-u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl http://localhost:80/api/device-connectivity/mqtts/certificate/download -o /tmp/tb-server-chain.pem"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tmp/tb-server-chain.pem -h localhost -p 8883 " + + "-t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + " -p 1883 -t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --volume pathToFile/tb-server-chain.pem:/tmp/tb-server-chain.pem " + - "-it --rm thingsboard/mosquitto-clients pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"", + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients " + + "/bin/sh -c \"curl -o /tmp/tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); } @@ -295,20 +294,20 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId() , new TypeReference<>() {}); assertThat(commands).hasSize(1); - JsonNode linuxMqttCommands = commands.get(MQTT); - assertThat(linuxMqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + - "-i %s -u %s -P %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - assertThat(linuxMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile pathToFile/tb-server-chain.pem -h localhost -p 8883 " + - "-t %s -i %s -u %s -P %s -m \"{temperature:25}\"", - DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + JsonNode mqttCommands = commands.get(MQTT); + assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + + "-i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl http://localhost:80/api/device-connectivity/mqtts/certificate/download -o /tmp/tb-server-chain.pem"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tmp/tb-server-chain.pem -h localhost -p 8883 " + + "-t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + " -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --volume pathToFile/tb-server-chain.pem:/tmp/tb-server-chain.pem " + - "-it --rm thingsboard/mosquitto-clients pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients " + + "/bin/sh -c \"curl -o /tmp/tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); } @@ -330,7 +329,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { JsonNode commands = doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); assertThat(commands).hasSize(1); - assertThat(commands.get(MQTT).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); + assertThat(commands.get(MQTT).get(MQTTS).get(0).asText()).isEqualTo(CHECK_DOCUMENTATION); assertThat(commands.get(MQTT).get(DOCKER)).isNull(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java index 284115ffb2..e15056a2a6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.device; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; @@ -36,6 +37,9 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -48,7 +52,6 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.LINUX; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.WINDOWS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getCoapClientCommand; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getCurlCommand; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getDockerMosquittoClientsPublishCommand; @@ -77,7 +80,6 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService log.trace("Executing findDevicePublishTelemetryCommands [{}]", deviceId); validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); - String defaultHostname = new URI(baseUrl).getHost(); DeviceCredentials creds = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), deviceId); DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); DeviceTransportType transportType = deviceProfile.getTransportType(); @@ -85,11 +87,11 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService ObjectNode commands = JacksonUtil.newObjectNode(); switch (transportType) { case DEFAULT: - Optional.ofNullable(getHttpTransportPublishCommands(defaultHostname, creds)) + Optional.ofNullable(getHttpTransportPublishCommands(baseUrl, creds)) .ifPresent(v -> commands.set(HTTP, v)); - Optional.ofNullable(getMqttTransportPublishCommands(defaultHostname, creds)) + Optional.ofNullable(getMqttTransportPublishCommands(baseUrl, creds)) .ifPresent(v -> commands.set(MQTT, v)); - Optional.ofNullable(getCoapTransportPublishCommands(defaultHostname, creds)) + Optional.ofNullable(getCoapTransportPublishCommands(baseUrl, creds)) .ifPresent(v -> commands.set(COAP, v)); break; case MQTT: @@ -97,11 +99,11 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService (MqttDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); String topicName = transportConfiguration.getDeviceTelemetryTopic(); - Optional.ofNullable(getMqttTransportPublishCommands(defaultHostname, topicName, creds)) + Optional.ofNullable(getMqttTransportPublishCommands(baseUrl, topicName, creds)) .ifPresent(v -> commands.set(MQTT, v)); break; case COAP: - Optional.ofNullable(getCoapTransportPublishCommands(defaultHostname, creds)) + Optional.ofNullable(getCoapTransportPublishCommands(baseUrl, creds)) .ifPresent(v -> commands.set(COAP, v)); break; default: @@ -122,7 +124,7 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService } } - private JsonNode getHttpTransportPublishCommands(String defaultHostname, DeviceCredentials deviceCredentials) { + private JsonNode getHttpTransportPublishCommands(String defaultHostname, DeviceCredentials deviceCredentials) throws URISyntaxException { ObjectNode httpCommands = JacksonUtil.newObjectNode(); Optional.ofNullable(getHttpPublishCommand(HTTP, defaultHostname, deviceCredentials)) .ifPresent(v -> httpCommands.put(HTTP, v)); @@ -131,34 +133,37 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService return httpCommands.isEmpty() ? null : httpCommands; } - private String getHttpPublishCommand(String protocol, String defaultHostname, DeviceCredentials deviceCredentials) { + private String getHttpPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { DeviceConnectivityInfo httpProps = deviceConnectivityConfiguration.getConnectivity().get(protocol); if (httpProps == null || !httpProps.getEnabled() || deviceCredentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) { return null; } - String hostName = httpProps.getHost().isEmpty() ? defaultHostname : httpProps.getHost(); + String hostName = httpProps.getHost().isEmpty() ? new URI(baseUrl).getHost() : httpProps.getHost(); String port = httpProps.getPort().isEmpty() ? "" : ":" + httpProps.getPort(); return getCurlCommand(protocol, hostName, port, deviceCredentials); } - private JsonNode getMqttTransportPublishCommands(String defaultHostname, DeviceCredentials deviceCredentials) { - return getMqttTransportPublishCommands(defaultHostname, DEFAULT_DEVICE_TELEMETRY_TOPIC, deviceCredentials); + private JsonNode getMqttTransportPublishCommands(String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { + return getMqttTransportPublishCommands(baseUrl, DEFAULT_DEVICE_TELEMETRY_TOPIC, deviceCredentials); } - private JsonNode getMqttTransportPublishCommands(String defaultHostname, String topic, DeviceCredentials deviceCredentials) { + private JsonNode getMqttTransportPublishCommands(String baseUrl, String topic, DeviceCredentials deviceCredentials) throws URISyntaxException { ObjectNode mqttCommands = JacksonUtil.newObjectNode(); - Optional.ofNullable(getMqttPublishCommand(MQTT, defaultHostname, topic, deviceCredentials)) + Optional.ofNullable(getMqttPublishCommand(baseUrl, topic, deviceCredentials)) .ifPresent(v -> mqttCommands.put(MQTT, v)); - Optional.ofNullable(getMqttPublishCommand(MQTTS, defaultHostname, topic, deviceCredentials)) - .ifPresent(v -> mqttCommands.put(MQTTS, v)); + List mqttsPublishCommand = getMqttsPublishCommand(baseUrl, topic, deviceCredentials); + if (mqttsPublishCommand != null){ + ArrayNode arrayNode = mqttCommands.putArray(MQTTS); + mqttsPublishCommand.forEach(arrayNode::add); + } ObjectNode dockerMqttCommands = JacksonUtil.newObjectNode(); - Optional.ofNullable(getDockerMqttPublishCommand(MQTT, defaultHostname, topic, deviceCredentials)) + Optional.ofNullable(getDockerMqttPublishCommand(MQTT,baseUrl, topic, deviceCredentials)) .ifPresent(v -> dockerMqttCommands.put(MQTT, v)); - Optional.ofNullable(getDockerMqttPublishCommand(MQTTS, defaultHostname, topic, deviceCredentials)) + Optional.ofNullable(getDockerMqttPublishCommand(MQTTS, baseUrl, topic, deviceCredentials)) .ifPresent(v -> dockerMqttCommands.put(MQTTS, v)); if (!dockerMqttCommands.isEmpty()) { @@ -167,41 +172,62 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService return mqttCommands.isEmpty() ? null : mqttCommands; } - private String getMqttPublishCommand(String protocol, String defaultHostname, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { - if (MQTTS.equals(protocol) && deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { - return CHECK_DOCUMENTATION; - } - DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + private String getMqttPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(MQTT); if (properties == null || !properties.getEnabled()) { return null; } - String mqttHost = properties.getHost().isEmpty() ? defaultHostname : properties.getHost(); + String mqttHost = properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); - return getMosquittoPubPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + return getMosquittoPubPublishCommand(MQTT, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); } - private String getDockerMqttPublishCommand(String protocol, String defaultHostname, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { + private List getMqttsPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { + String pubCommand; + if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { + return List.of(CHECK_DOCUMENTATION); + } else { + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(MQTTS); + if (properties == null || !properties.getEnabled()) { + return null; + } + String mqttHost = properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); + String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); + pubCommand = getMosquittoPubPublishCommand(MQTTS, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + } + + ArrayList commands = new ArrayList<>(); + if (pubCommand != null) { + commands.add("curl " + baseUrl + "/api/device-connectivity/mqtts/certificate/download -o /tmp/tb-server-chain.pem"); + commands.add(pubCommand); + return commands; + } + return null; + } + + + private String getDockerMqttPublishCommand(String protocol, String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); if (properties == null || !properties.getEnabled()) { return null; } - String mqttHost = properties.getHost().isEmpty() ? defaultHostname : properties.getHost(); + String mqttHost = properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); - return getDockerMosquittoClientsPublishCommand(protocol, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + return getDockerMosquittoClientsPublishCommand(protocol, baseUrl, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); } - private JsonNode getCoapTransportPublishCommands(String defaultHostname, DeviceCredentials deviceCredentials) { + private JsonNode getCoapTransportPublishCommands(String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { ObjectNode coapCommands = JacksonUtil.newObjectNode(); - Optional.ofNullable(getCoapPublishCommand(LINUX, COAP, defaultHostname, deviceCredentials)) + Optional.ofNullable(getCoapPublishCommand(COAP, baseUrl, deviceCredentials)) .ifPresent(v -> coapCommands.put(COAP, v)); - Optional.ofNullable(getCoapPublishCommand(LINUX, COAPS, defaultHostname, deviceCredentials)) + Optional.ofNullable(getCoapPublishCommand(COAPS, baseUrl, deviceCredentials)) .ifPresent(v -> coapCommands.put(COAPS, v)); return coapCommands.isEmpty() ? null : coapCommands; } - private String getCoapPublishCommand(String os, String protocol, String defaultHostname, DeviceCredentials deviceCredentials) { + private String getCoapPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { if (COAPS.equals(protocol) && deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { return CHECK_DOCUMENTATION; } @@ -209,14 +235,9 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService if (properties == null || !properties.getEnabled()) { return null; } - String hostName = properties.getHost().isEmpty() ? defaultHostname : properties.getHost(); + String hostName = properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); - switch (os) { - case LINUX: - return getCoapClientCommand(protocol, hostName, port, deviceCredentials); - default: - throw new IllegalArgumentException("Unsupported operating system: " + os); - } + return getCoapClientCommand(protocol, hostName, port, deviceCredentials); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java index 72eac8bdea..e99df56e64 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java @@ -19,6 +19,9 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials; +import java.util.ArrayList; +import java.util.List; + public class DeviceConnectivityUtil { public static final String HTTP = "http"; @@ -42,7 +45,7 @@ public class DeviceConnectivityUtil { public static String getMosquittoPubPublishCommand(String protocol, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { StringBuilder command = new StringBuilder("mosquitto_pub -d -q 1"); if (MQTTS.equals(protocol)) { - command.append(" --cafile pathToFile/" + MQTT_SSL_PEM_FILE_NAME); + command.append(" --cafile tmp/" + MQTT_SSL_PEM_FILE_NAME); } command.append(" -h ").append(host).append(port == null ? "" : " -p " + port); command.append(" -t ").append(deviceTelemetryTopic); @@ -75,12 +78,12 @@ public class DeviceConnectivityUtil { return command.toString(); } - public static String getDockerMosquittoClientsPublishCommand(String protocol, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { - StringBuilder command = new StringBuilder("docker run"); + public static String getDockerMosquittoClientsPublishCommand(String protocol, String baseUrl, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { + StringBuilder command = new StringBuilder("docker run -it --rm thingsboard/mosquitto-clients "); if (MQTTS.equals(protocol)) { - command.append(" --volume pathToFile/" + MQTT_SSL_PEM_FILE_NAME + ":/tmp/" + MQTT_SSL_PEM_FILE_NAME); + command.append("/bin/sh -c \"curl -o /tmp/tb-server-chain.pem ").append(baseUrl).append("/api/device-connectivity/mqtts/certificate/download && "); } - command.append(" -it --rm thingsboard/mosquitto-clients pub"); + command.append("pub"); if (MQTTS.equals(protocol)) { command.append(" --cafile tmp/" + MQTT_SSL_PEM_FILE_NAME); } @@ -112,6 +115,9 @@ public class DeviceConnectivityUtil { return null; } command.append(" -m " + JSON_EXAMPLE_PAYLOAD); + if (MQTTS.equals(protocol)) { + command.append("\""); + } return command.toString(); } From 6a3be7fbaa61093409cb65a92446e9992823f6f3 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 24 Jul 2023 10:55:11 +0300 Subject: [PATCH 306/421] UI: fixed show commands in mqtt --- .../server/dao/device/DeviceСonnectivityServiceImpl.java | 8 ++++++-- .../server/dao/util/DeviceConnectivityUtil.java | 3 --- .../device-check-connectivity-dialog.component.scss | 1 + .../device/device-check-connectivity-dialog.component.ts | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java index e15056a2a6..e7bfefabbd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java @@ -156,8 +156,12 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService .ifPresent(v -> mqttCommands.put(MQTT, v)); List mqttsPublishCommand = getMqttsPublishCommand(baseUrl, topic, deviceCredentials); if (mqttsPublishCommand != null){ - ArrayNode arrayNode = mqttCommands.putArray(MQTTS); - mqttsPublishCommand.forEach(arrayNode::add); + if (mqttsPublishCommand.size() > 1) { + ArrayNode arrayNode = mqttCommands.putArray(MQTTS); + mqttsPublishCommand.forEach(arrayNode::add); + } else { + mqttCommands.put(MQTTS, mqttsPublishCommand.get(0)); + } } ObjectNode dockerMqttCommands = JacksonUtil.newObjectNode(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java index e99df56e64..dad405b093 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java @@ -19,9 +19,6 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials; -import java.util.ArrayList; -import java.util.List; - public class DeviceConnectivityUtil { public static final String HTTP = "http"; diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss index 1a95da0a14..e50b46d9fc 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.scss @@ -123,6 +123,7 @@ margin: 0; background: #F3F6FA; border-color: #305680; + padding-right: 38px; } } button.clipboard-btn { diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts index f185d88c6a..07da1a43ed 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts @@ -171,7 +171,7 @@ export class DeviceCheckConnectivityDialogComponent extends if (Array.isArray(commands)) { const formatCommands: Array = []; commands.forEach(command => formatCommands.push(this.createMarkDownSingleCommand(command))); - return formatCommands.join('
\n'); + return formatCommands.join(`\n
\n\n`); } else { return this.createMarkDownSingleCommand(commands); } From ce6046844ac13dee2f01a8f376f49e5ef65bc76a Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 24 Jul 2023 12:16:19 +0300 Subject: [PATCH 307/421] UI: Hide edit button if entity not selected --- .../profile/asset-profile-autocomplete.component.html | 2 +- .../profile/device-profile-autocomplete.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.html b/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.html index 87ee2a7fa1..5244cf9101 100644 --- a/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.html @@ -35,7 +35,7 @@ (click)="clear()"> close - -
+
+ + {{ 'widgets.value-card.icon' | translate }} + +
+ + + + + + + + +
+
+
+
widgets.value-card.value
+
+ + + +
widget-config.decimals-suffix
+
+ + + + +
+
+
+
+ + {{ 'widgets.value-card.date' | translate }} + +
+ + + + + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts index 9cf918905c..762b26ac42 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component } from '@angular/core'; +import { ChangeDetectorRef, Component, Injector } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -28,8 +28,13 @@ import { import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; -import { isDefinedAndNotNull, isUndefined } from '@core/utils'; -import { getLabel, setLabel } from '@home/components/widget/config/widget-settings.models'; +import { formatValue, isDefinedAndNotNull, isUndefined } from '@core/utils'; +import { + DateFormatProcessor, + DateFormatSettings, + getLabel, + setLabel +} from '@home/components/widget/config/widget-settings.models'; import { valueCardDefaultSettings, ValueCardLayout, @@ -65,9 +70,14 @@ export class ValueCardBasicConfigComponent extends BasicWidgetConfigComponent { valueCardWidgetConfigForm: UntypedFormGroup; + valuePreviewFn = this._valuePreviewFn.bind(this); + + datePreviewFn = this._datePreviewFn.bind(this); + constructor(protected store: Store, protected widgetConfigComponent: WidgetConfigComponent, private cd: ChangeDetectorRef, + private $injector: Injector, private fb: UntypedFormBuilder) { super(store, widgetConfigComponent); } @@ -251,4 +261,16 @@ export class ValueCardBasicConfigComponent extends BasicWidgetConfigComponent { config.enableFullscreen = buttons.includes('fullscreen'); } + private _valuePreviewFn(): string { + const units: string = this.valueCardWidgetConfigForm.get('units').value; + const decimals: number = this.valueCardWidgetConfigForm.get('decimals').value; + return formatValue(22, decimals, units, true); + } + + private _datePreviewFn(): string { + const dateFormat: DateFormatSettings = this.valueCardWidgetConfigForm.get('dateFormat').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/config/widget-settings.models.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts index 222c031cfb..34f2ac464b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts @@ -16,6 +16,10 @@ import { isDefinedAndNotNull, isNumber, isNumeric, parseFunction } from '@core/utils'; import { DataKey, Datasource, DatasourceData } from '@shared/models/widget.models'; +import { Injector } from '@angular/core'; +import { DatePipe, formatDate } from '@angular/common'; +import { DateAgoPipe } from '@shared/pipe/date-ago.pipe'; +import { TranslateService } from '@ngx-translate/core'; export type ComponentStyle = {[klass: string]: any}; @@ -168,6 +172,104 @@ class FunctionColorProcessor extends ColorProcessor { } } +export interface DateFormatSettings { + format?: string; + lastUpdateAgo?: boolean; + custom?: boolean; +} + +export const simpleDateFormat = (format: string): DateFormatSettings => ({ + format, + lastUpdateAgo: false, + custom: false +}); + +export const lastUpdateAgoDateFormat = (): DateFormatSettings => ({ + format: null, + lastUpdateAgo: true, + custom: false +}); + +export const customDateFormat = (format: string): DateFormatSettings => ({ + format, + lastUpdateAgo: false, + custom: true +}); + +export const dateFormats = ['MMM dd yyyy HH:mm', 'dd MMM yyyy HH:mm', 'yyyy MMM dd HH:mm', + 'MM/dd/yyyy HH:mm', 'dd/MM/yyyy HH:mm', 'yyyy/MM/dd HH:mm:ss'] + .map(f => simpleDateFormat(f)).concat([lastUpdateAgoDateFormat(), customDateFormat('EEE, MMMM dd, yyyy')]); + +export const compareDateFormats = (df1: DateFormatSettings, df2: DateFormatSettings): boolean => { + if (df1 === df2) { + return true; + } else if (df1 && df2) { + if (df1.lastUpdateAgo && df2.lastUpdateAgo) { + return true; + } else if (df1.custom && df2.custom) { + return true; + } else if (!df1.lastUpdateAgo && !df2.lastUpdateAgo && !df1.custom && !df2.custom) { + return df1.format === df2.format; + } + } + return false; +}; + +export abstract class DateFormatProcessor { + + static fromSettings($injector: Injector, settings: DateFormatSettings): DateFormatProcessor { + if (settings.lastUpdateAgo) { + return new LastUpdateAgoDateFormatProcessor($injector, settings); + } else { + return new SimpleDateFormatProcessor($injector, settings); + } + } + + formatted = ''; + + protected constructor(protected $injector: Injector, + protected settings: DateFormatSettings) { + } + + abstract update(ts: string | number | Date): void; + +} + +export class SimpleDateFormatProcessor extends DateFormatProcessor { + + private datePipe: DatePipe; + + constructor(protected $injector: Injector, + protected settings: DateFormatSettings) { + super($injector, settings); + this.datePipe = $injector.get(DatePipe); + } + + update(ts: string| number | Date): void { + this.formatted = this.datePipe.transform(ts, this.settings.format); + } + +} + +export class LastUpdateAgoDateFormatProcessor extends DateFormatProcessor { + + private dateAgoPipe: DateAgoPipe; + private translate: TranslateService; + + constructor(protected $injector: Injector, + protected settings: DateFormatSettings) { + super($injector, settings); + this.dateAgoPipe = $injector.get(DateAgoPipe); + this.translate = $injector.get(TranslateService); + } + + update(ts: string| number | Date): void { + this.formatted = this.translate.instant('date.last-update-n-ago-text', + {agoText: this.dateAgoPipe.transform(ts, {applyAgo: true, short: true, textPart: true})}); + } + +} + export enum BackgroundType { image = 'image', imageUrl = 'imageUrl', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html index e76ff0b36a..8c79c0e1e7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html @@ -63,7 +63,7 @@
{{ label }}
-
{{ dateText }}
+
{{ dateFormat.formatted }}
{{ valueText }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts index 787888d1c8..f495581571 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts @@ -21,7 +21,7 @@ import { DatePipe } from '@angular/common'; import { backgroundStyle, ColorProcessor, - ComponentStyle, + ComponentStyle, DateFormatProcessor, getDataKey, getLabel, getSingleTsValue, @@ -62,7 +62,7 @@ export class ValueCardWidgetComponent implements OnInit { valueColor: ColorProcessor; showDate = true; - dateText = ''; + dateFormat: DateFormatProcessor; dateStyle: ComponentStyle = {}; dateColor: ColorProcessor; @@ -70,7 +70,6 @@ export class ValueCardWidgetComponent implements OnInit { overlayStyle: ComponentStyle = {}; private horizontal = false; - private dateFormat: string; private decimals = 0; private units = ''; @@ -110,7 +109,7 @@ export class ValueCardWidgetComponent implements OnInit { this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); this.showDate = this.settings.showDate; - this.dateFormat = this.settings.dateFormat; + this.dateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.dateFormat); this.dateStyle = textStyle(this.settings.dateFont, '1.33', '0.25px'); this.dateColor = ColorProcessor.fromSettings(this.settings.dateColor); @@ -126,15 +125,16 @@ export class ValueCardWidgetComponent implements OnInit { public onDataUpdated() { const tsValue = getSingleTsValue(this.ctx.data); + let ts; let value; if (tsValue) { + ts = tsValue[0]; value = tsValue[1]; this.valueText = formatValue(value, this.decimals, this.units, true); - this.dateText = this.date.transform(tsValue[0], this.dateFormat); } else { this.valueText = 'N/A'; - this.dateText = ''; } + this.dateFormat.update(ts); this.iconColor.update(value); this.labelColor.update(value); this.valueColor.update(value); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts index 5a54264bd0..23d9a30329 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts @@ -19,8 +19,8 @@ import { BackgroundType, ColorSettings, constantColor, - cssUnit, - Font + cssUnit, DateFormatSettings, + Font, lastUpdateAgoDateFormat } from '@home/components/widget/config/widget-settings.models'; export enum ValueCardLayout { @@ -75,7 +75,7 @@ export interface ValueCardWidgetSettings { valueFont: Font; valueColor: ColorSettings; showDate: boolean; - dateFormat: string; + dateFormat: DateFormatSettings; dateFont: Font; dateColor: ColorSettings; background: BackgroundSettings; @@ -106,7 +106,7 @@ export const valueCardDefaultSettings = (horizontal: boolean): ValueCardWidgetSe }, valueColor: constantColor('rgba(0, 0, 0, 0.87)'), showDate: true, - dateFormat: 'yyyy-MM-dd HH:mm:ss', + dateFormat: lastUpdateAgoDateFormat(), dateFont: { family: 'Roboto', size: 12, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts index c20abd8d84..2118bde6df 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts @@ -108,6 +108,7 @@ export class ColorSettingsPanelComponent extends PageComponent implements OnInit removeRange(index: number) { this.rangeListFormArray.removeAt(index); + this.colorSettingsFormGroup.markAsDirty(); setTimeout(() => {this.popover?.updatePosition();}, 0); } @@ -115,7 +116,8 @@ export class ColorSettingsPanelComponent extends PageComponent implements OnInit const newRange: ColorRange = { color: 'rgba(0,0,0,0.87)' }; - this.rangeListFormArray.push(this.colorRangeControl(newRange), {emitEvent: true}); + this.rangeListFormArray.push(this.colorRangeControl(newRange)); + this.colorSettingsFormGroup.markAsDirty(); setTimeout(() => {this.popover?.updatePosition();}, 0); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html new file mode 100644 index 0000000000..eaca1b6d40 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html @@ -0,0 +1,22 @@ + + + + {{ cssUnit }} + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts new file mode 100644 index 0000000000..dc593e9564 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts @@ -0,0 +1,82 @@ +/// +/// Copyright © 2016-2023 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, forwardRef, Input, OnInit } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; +import { cssUnit, cssUnits } from '@home/components/widget/config/widget-settings.models'; + +@Component({ + selector: 'tb-css-unit-select', + templateUrl: './css-unit-select.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CssUnitSelectComponent), + multi: true + } + ] +}) +export class CssUnitSelectComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + cssUnitsList = cssUnits; + + cssUnitFormControl: UntypedFormControl; + + modelValue: cssUnit; + + private propagateChange = null; + + constructor() {} + + ngOnInit(): void { + this.cssUnitFormControl = new UntypedFormControl(); + this.cssUnitFormControl.valueChanges.subscribe((value: cssUnit) => { + this.updateModel(value); + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.cssUnitFormControl.disable(); + } else { + this.cssUnitFormControl.enable(); + } + } + + writeValue(value: cssUnit): void { + this.modelValue = value; + this.cssUnitFormControl.patchValue(this.modelValue, {emitEvent: false}); + } + + updateModel(value: cssUnit): void { + if (this.modelValue !== value) { + this.modelValue = value; + this.propagateChange(this.modelValue); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.html new file mode 100644 index 0000000000..7310d0c403 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.html @@ -0,0 +1,26 @@ + + + + {{ dateFormatDisplayValue(dateFormat) }} + + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts new file mode 100644 index 0000000000..413111ad1e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts @@ -0,0 +1,148 @@ +/// +/// Copyright © 2016-2023 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, forwardRef, Input, OnInit, Renderer2, ViewChild, ViewContainerRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; +import { + compareDateFormats, + dateFormats, + DateFormatSettings +} from '@home/components/widget/config/widget-settings.models'; +import { TranslateService } from '@ngx-translate/core'; +import { DatePipe } from '@angular/common'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { deepClone } from '@core/utils'; +import { + DateFormatSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/date-format-settings-panel.component'; + +@Component({ + selector: 'tb-date-format-select', + templateUrl: './date-format-select.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => DateFormatSelectComponent), + multi: true + } + ] +}) +export class DateFormatSelectComponent implements OnInit, ControlValueAccessor { + + @ViewChild('customFormatButton', {static: false}) + customFormatButton: MatButton; + + @Input() + disabled: boolean; + + dateFormatList = dateFormats; + + dateFormatsCompare = compareDateFormats; + + dateFormatFormControl: UntypedFormControl; + + modelValue: DateFormatSettings; + + private propagateChange = null; + + private formatCache: {[format: string]: string} = {}; + + constructor(private translate: TranslateService, + private date: DatePipe, + private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void { + this.dateFormatFormControl = new UntypedFormControl(); + this.dateFormatFormControl.valueChanges.subscribe((value: DateFormatSettings) => { + this.updateModel(value); + if (value?.custom) { + setTimeout(() => { + this.openDateFormatSettingsPopup(null, this.customFormatButton); + }, 0); + } + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.dateFormatFormControl.disable(); + } else { + this.dateFormatFormControl.enable(); + } + } + + writeValue(value: DateFormatSettings): void { + this.modelValue = value; + this.dateFormatFormControl.patchValue(this.modelValue, {emitEvent: false}); + } + + updateModel(value: DateFormatSettings): void { + if (!compareDateFormats(this.modelValue, value)) { + this.modelValue = value; + this.propagateChange(this.modelValue); + } + } + + dateFormatDisplayValue(value: DateFormatSettings): string { + if (value.custom) { + return this.translate.instant('date.custom-date'); + } else if (value.lastUpdateAgo) { + return this.translate.instant('date.last-update-n-ago'); + } else { + if (!this.formatCache[value.format]) { + this.formatCache[value.format] = this.date.transform(Date.now(), value.format); + } + return this.formatCache[value.format]; + } + } + + openDateFormatSettingsPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + dateFormat: deepClone(this.modelValue) + }; + const dateFormatSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, DateFormatSettingsPanelComponent, 'top', true, null, + ctx, + {}, + {}, {}, true); + dateFormatSettingsPanelPopover.tbComponentRef.instance.popover = dateFormatSettingsPanelPopover; + dateFormatSettingsPanelPopover.tbComponentRef.instance.dateFormatApplied.subscribe((dateFormat) => { + dateFormatSettingsPanelPopover.hide(); + this.modelValue = dateFormat; + this.propagateChange(this.modelValue); + }); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html new file mode 100644 index 0000000000..ee332924f0 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html @@ -0,0 +1,47 @@ + +
+
date.custom-date
+
+
date.format
+ + +
+
+
+ +
+
date.preview
+
{{ previewText }}
+
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss new file mode 100644 index 0000000000..ec6a762966 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss @@ -0,0 +1,67 @@ +/** + * Copyright © 2016-2023 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-date-format-settings-panel { + width: 500px; + display: flex; + flex-direction: column; + gap: 16px; + @media #{$mat-xs} { + width: 90vw; + } + .tb-date-format-settings-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-form-row { + .fixed-title-width { + min-width: 120px; + } + &.date-format-preview { + align-items: flex-start; + .preview-text { + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; + letter-spacing: 0.2px; + color: rgba(0, 0, 0, 0.38); + } + } + .mat-mdc-form-field.tb-date-format-input { + .mat-mdc-text-field-wrapper.mdc-text-field--outlined { + .mat-mdc-form-field-icon-suffix { + display: flex; + align-items: center; + line-height: normal; + } + } + } + } + .tb-date-format-settings-panel-buttons { + height: 60px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts new file mode 100644 index 0000000000..47f54fd5d5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts @@ -0,0 +1,70 @@ +/// +/// Copyright © 2016-2023 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, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { DateFormatSettings } from '@home/components/widget/config/widget-settings.models'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { UntypedFormControl, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { DatePipe } from '@angular/common'; + +@Component({ + selector: 'tb-date-format-settings-panel', + templateUrl: './date-format-settings-panel.component.html', + providers: [], + styleUrls: ['./date-format-settings-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class DateFormatSettingsPanelComponent extends PageComponent implements OnInit { + + @Input() + dateFormat: DateFormatSettings; + + @Input() + popover: TbPopoverComponent; + + @Output() + dateFormatApplied = new EventEmitter(); + + dateFormatFormControl: UntypedFormControl; + + previewText = ''; + + constructor(private date: DatePipe, + protected store: Store) { + super(store); + } + + ngOnInit(): void { + this.dateFormatFormControl = new UntypedFormControl(this.dateFormat.format, [Validators.required]); + this.dateFormatFormControl.valueChanges.subscribe((value: string) => { + this.previewText = this.date.transform(Date.now(), value); + }); + this.previewText = this.date.transform(Date.now(), this.dateFormat.format); + } + + cancel() { + this.popover?.hide(); + } + + applyDateFormat() { + this.dateFormat.format = this.dateFormatFormControl.value; + this.dateFormatApplied.emit(this.dateFormat); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html index 8cf2e4e9e3..140c525ac2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html @@ -23,11 +23,7 @@ - - - {{ cssUnit }} - - +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts index 9369167746..91a71bc8d7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts @@ -28,7 +28,6 @@ import { PageComponent } from '@shared/components/page.component'; import { commonFonts, ComponentStyle, - cssUnits, Font, fontStyles, fontStyleTranslations, @@ -66,8 +65,6 @@ export class FontSettingsPanelComponent extends PageComponent implements OnInit @ViewChild('familyInput', {static: true}) familyInput: ElementRef; - cssUnitsList = cssUnits; - fontWeightsList = fontWeights; fontWeightTranslationsMap = fontWeightTranslations; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index 1a9834dd91..68b84578c1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -276,6 +276,11 @@ import { ColorSettingsComponent } from '@home/components/widget/lib/settings/com import { ColorSettingsPanelComponent } from '@home/components/widget/lib/settings/common/color-settings-panel.component'; +import { CssUnitSelectComponent } from '@home/components/widget/lib/settings/common/css-unit-select.component'; +import { DateFormatSelectComponent } from '@home/components/widget/lib/settings/common/date-format-select.component'; +import { + DateFormatSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/date-format-settings-panel.component'; @NgModule({ declarations: [ @@ -383,7 +388,10 @@ import { FontSettingsComponent, FontSettingsPanelComponent, ColorSettingsComponent, - ColorSettingsPanelComponent + ColorSettingsPanelComponent, + CssUnitSelectComponent, + DateFormatSelectComponent, + DateFormatSettingsPanelComponent ], imports: [ CommonModule, @@ -495,7 +503,10 @@ import { FontSettingsComponent, FontSettingsPanelComponent, ColorSettingsComponent, - ColorSettingsPanelComponent + ColorSettingsPanelComponent, + CssUnitSelectComponent, + DateFormatSelectComponent, + DateFormatSettingsPanelComponent ] }) export class WidgetSettingsModule { diff --git a/ui-ngx/src/app/shared/components/help-markdown.component.ts b/ui-ngx/src/app/shared/components/help-markdown.component.ts index 97bd326b46..90ac325c55 100644 --- a/ui-ngx/src/app/shared/components/help-markdown.component.ts +++ b/ui-ngx/src/app/shared/components/help-markdown.component.ts @@ -24,6 +24,7 @@ import { import { BehaviorSubject } from 'rxjs'; import { share } from 'rxjs/operators'; import { HelpService } from '@core/services/help.service'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-help-markdown', @@ -36,7 +37,9 @@ export class HelpMarkdownComponent implements OnDestroy, OnInit, OnChanges { @Input() helpContent: string; - @Input() visible: boolean; + @Input() + @coerceBoolean() + visible: boolean; @Input() style: { [klass: string]: any } = {}; diff --git a/ui-ngx/src/app/shared/components/unit-input.component.html b/ui-ngx/src/app/shared/components/unit-input.component.html index 3686796dbf..d001a43ef2 100644 --- a/ui-ngx/src/app/shared/components/unit-input.component.html +++ b/ui-ngx/src/app/shared/components/unit-input.component.html @@ -15,7 +15,7 @@ limitations under the License. --> - + 0) { - let res = this.translate.instant(`timewindow.${i}`, {[i]: counter}); + let res = this.translate.instant(`timewindow.${i+(short ? '-short' : '')}`, {[i]: counter}); if (applyAgo) { res += ' ' + this.translate.instant('timewindow.ago'); } diff --git a/ui-ngx/src/assets/help/en_US/date/date-format.md b/ui-ngx/src/assets/help/en_US/date/date-format.md new file mode 100644 index 0000000000..502ab7d4f7 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/date/date-format.md @@ -0,0 +1,88 @@ +#### Pre-defined format options + +| Option | Equivalent to | Examples (given in `en-US` locale) | +|------------|---------------------------------|-----------------------------------------------| +| short | M/d/yy, h:mm a | 6/15/15, 9:03 AM | +| medium | MMM d, y, h:mm:ss a | Jun 15, 2015, 9:03:01 AM | +| long | MMMM d, y, h:mm:ss a z | June 15, 2015 at 9:03:01 AM GMT+1 | +| full | EEEE, MMMM d, y, h:mm:ss a zzzz | Monday, June 15, 2015 at 9:03:01 AM GMT+01:00 | +| shortDate | M/d/yy | 6/15/15 | +| mediumDate | MMM d, y | Jun 15, 2015 | +| longDate | MMMM d, y | June 15, 2015 | +| fullDate | EEEE, MMMM d, y | Monday, June 15, 2015 | +| shortTime | h:mm a | 9:03 AM | +| mediumTime | h:mm:ss a | 9:03:01 AM | +| longTime | h:mm:ss a z | 9:03:01 AM GMT+1 | +| fullTime | h:mm:ss a zzzz | 9:03:01 AM GMT+01:00 | + +#### Custom format options + +You can construct a format string using symbols to specify the components +of a date-time value, as described in the following table. +Format details depend on the locale. +Fields marked with (*) are only available in the extra data set for the given locale. + +| Field type | Format | Description | Example Value | +|---------------------|-------------|--------------------------------------------------------------|------------------------------------------------------------| +| Era | G, GG & GGG | Abbreviated | AD | +| | GGGG | Wide | Anno Domini | +| | GGGGG | Narrow | A | +| Year | y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 | +| | yy | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | +| | yyy | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | +| | yyyy | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | +| Week-numbering year | Y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 | +| | YY | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | +| | YYY | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | +| | YYYY | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | +| Month | M | Numeric: 1 digit | 9, 12 | +| | MM | Numeric: 2 digits + zero padded | 09, 12 | +| | MMM | Abbreviated | Sep | +| | MMMM | Wide | September | +| | MMMMM | Narrow | S | +| Month standalone | L | Numeric: 1 digit | 9, 12 | +| | LL | Numeric: 2 digits + zero padded | 09, 12 | +| | LLL | Abbreviated | Sep | +| | LLLL | Wide | September | +| | LLLLL | Narrow | S | +| Week of year | w | Numeric: minimum digits | 1... 53 | +| | ww | Numeric: 2 digits + zero padded | 01... 53 | +| Week of month | W | Numeric: 1 digit | 1... 5 | +| Day of month | d | Numeric: minimum digits | 1 | +| | dd | Numeric: 2 digits + zero padded | 01 | +| Week day | E, EE & EEE | Abbreviated | Tue | +| | EEEE | Wide | Tuesday | +| | EEEEE | Narrow | T | +| | EEEEEE | Short | Tu | +| Week day standalone | c, cc | Numeric: 1 digit | 2 | +| | ccc | Abbreviated | Tue | +| | cccc | Wide | Tuesday | +| | ccccc | Narrow | T | +| | cccccc | Short | Tu | +| Period | a, aa & aaa | Abbreviated | am/pm or AM/PM | +| | aaaa | Wide (fallback to `a` when missing) | ante meridiem/post meridiem | +| | aaaaa | Narrow | a/p | +| Period* | B, BB & BBB | Abbreviated | mid. | +| | BBBB | Wide | am, pm, midnight, noon, morning, afternoon, evening, night | +| | BBBBB | Narrow | md | +| Period standalone* | b, bb & bbb | Abbreviated | mid. | +| | bbbb | Wide | am, pm, midnight, noon, morning, afternoon, evening, night | +| | bbbbb | Narrow | md | +| Hour 1-12 | h | Numeric: minimum digits | 1, 12 | +| | hh | Numeric: 2 digits + zero padded | 01, 12 | +| Hour 0-23 | H | Numeric: minimum digits | 0, 23 | +| | HH | Numeric: 2 digits + zero padded | 00, 23 | +| Minute | m | Numeric: minimum digits | 8, 59 | +| | mm | Numeric: 2 digits + zero padded | 08, 59 | +| Second | s | Numeric: minimum digits | 0... 59 | +| | ss | Numeric: 2 digits + zero padded | 00... 59 | +| Fractional seconds | S | Numeric: 1 digit | 0... 9 | +| | SS | Numeric: 2 digits + zero padded | 00... 99 | +| | SSS | Numeric: 3 digits + zero padded (= milliseconds) | 000... 999 | +| Zone | z, zz & zzz | Short specific non location format (fallback to O) | GMT-8 | +| | zzzz | Long specific non location format (fallback to OOOO) | GMT-08:00 | +| | Z, ZZ & ZZZ | ISO8601 basic format | -0800 | +| | ZZZZ | Long localized GMT format | GMT-8:00 | +| | ZZZZZ | ISO8601 extended format + Z indicator for offset 0 (= XXXXX) | -08:00 | +| | O, OO & OOO | Short localized GMT format | GMT-8 | +| | OOOO | Long localized GMT format | GMT-08:00 | 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 1a93bf03db..291fe0cda0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -940,6 +940,13 @@ "edges": "Customer edge instances", "manage-edges": "Manage edges" }, + "date": { + "last-update-n-ago": "Last update N ago", + "last-update-n-ago-text": "Last update {{ agoText }}", + "custom-date": "Custom date", + "format": "Format", + "preview": "Preview" + }, "datetime": { "date-from": "Date from", "time-from": "Time from", @@ -3832,15 +3839,22 @@ "timewindow": { "timewindow": "Timewindow", "years": "{ years, plural, =1 { year } other {# years } }", + "years-short": "{{ years }}y", "months": "{ months, plural, =1 { month } other {# months } }", + "months-short": "{{ months }}M", "weeks": "{ weeks, plural, =1 { week } other {# weeks } }", + "weeks-short": "{{ weeks }}w", "days": "{ days, plural, =1 { day } other {# days } }", + "days-short": "{{ days }}d", "hours": "{ hours, plural, =0 { hour } =1 {1 hour } other {# hours } }", "hr": "{{ hr }} hr", + "hr-short": "{{ hr }}h", "minutes": "{ minutes, plural, =0 { minute } =1 {1 minute } other {# minutes } }", "min": "{{ min }} min", + "min-short": "{{ min }}m", "seconds": "{ seconds, plural, =0 { second } =1 {1 second } other {# seconds } }", "sec": "{{ sec }} sec", + "sec-short": "{{ sec }}s", "short": { "days": "{ days, plural, =1 {1 day } other {# days } }", "hours": "{ hours, plural, =1 {1 hour } other {# hours } }", @@ -3859,6 +3873,7 @@ "hide": "Hide", "interval": "Interval", "just-now": "Just now", + "just-now-lower": "just now", "ago": "ago" }, "unit": { @@ -4208,6 +4223,7 @@ "decimals": "Number of digits after floating point", "units-short": "Units", "decimals-short": "Decimals", + "decimals-suffix": "decimals", "timewindow": "Timewindow", "use-dashboard-timewindow": "Use dashboard timewindow", "use-widget-timewindow": "Use widget timewindow", @@ -5235,7 +5251,10 @@ "layout-simplified": "Simplified", "layout-horizontal": "Horizontal", "layout-horizontal-reversed": "Horizontal reversed", - "label": "Label" + "label": "Label", + "icon": "Icon", + "value": "Value", + "date": "Date" }, "table": { "common-table-settings": "Common Table Settings", From 3b8a9d94ecfffeb3813bcc75d203c568be4ab567 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 24 Jul 2023 22:57:52 +0200 Subject: [PATCH 311/421] Lwm2m transport - merge non-unique endpoints for models fetched from cache --- .../model/LwM2MModelConfigServiceImpl.java | 8 +- .../LwM2MModelConfigServiceImplTest.java | 73 +++++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.java diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java index 302bd20c8b..eef9a53024 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImpl.java @@ -52,7 +52,7 @@ import java.util.stream.Collectors; public class LwM2MModelConfigServiceImpl implements LwM2MModelConfigService { @Autowired - private TbLwM2MModelConfigStore modelStore; + TbLwM2MModelConfigStore modelStore; @Autowired @Lazy @@ -67,14 +67,14 @@ public class LwM2MModelConfigServiceImpl implements LwM2MModelConfigService { @Autowired private LwM2MTelemetryLogService logService; - private ConcurrentMap currentModelConfigs; + ConcurrentMap currentModelConfigs; @AfterStartUp(order = AfterStartUp.BEFORE_TRANSPORT_SERVICE) - private void init() { + public void init() { List models = modelStore.getAll(); log.debug("Fetched model configs: {}", models); currentModelConfigs = models.stream() - .collect(Collectors.toConcurrentMap(LwM2MModelConfig::getEndpoint, m -> m)); + .collect(Collectors.toConcurrentMap(LwM2MModelConfig::getEndpoint, m -> m, (existing, replacement) -> existing)); } @Override diff --git a/common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.java b/common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.java new file mode 100644 index 0000000000..fc54ca9e0b --- /dev/null +++ b/common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/model/LwM2MModelConfigServiceImplTest.java @@ -0,0 +1,73 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.lwm2m.server.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MModelConfigStore; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.willReturn; +import static org.mockito.Mockito.mock; + +class LwM2MModelConfigServiceImplTest { + + LwM2MModelConfigServiceImpl service; + TbLwM2MModelConfigStore modelStore; + + @BeforeEach + void setUp() { + service = new LwM2MModelConfigServiceImpl(); + modelStore = mock(TbLwM2MModelConfigStore.class); + service.modelStore = modelStore; + } + + @Test + void testInitWithDuplicatedModels() { + LwM2MModelConfig config = new LwM2MModelConfig("urn:imei:951358811362976"); + List models = List.of(config, config); + willReturn(models).given(modelStore).getAll(); + service.init(); + assertThat(service.currentModelConfigs).containsExactlyEntriesOf(Map.of(config.getEndpoint(), config)); + } + + @Test + void testInitWithNonUniqueEndpoints() { + LwM2MModelConfig configAlfa = new LwM2MModelConfig("urn:imei:951358811362976"); + LwM2MModelConfig configBravo = new LwM2MModelConfig("urn:imei:151358811362976"); + LwM2MModelConfig configDelta = new LwM2MModelConfig("urn:imei:151358811362976"); + assertThat(configBravo.getEndpoint()).as("non-unique endpoints provided").isEqualTo(configDelta.getEndpoint()); + List models = List.of(configAlfa, configBravo, configDelta); + willReturn(models).given(modelStore).getAll(); + service.init(); + assertThat(service.currentModelConfigs).containsExactlyInAnyOrderEntriesOf(Map.of( + configAlfa.getEndpoint(), configAlfa, + configBravo.getEndpoint(), configBravo + )); + } + + @Test + void testInitWithEmptyModels() { + willReturn(Collections.emptyList()).given(modelStore).getAll(); + service.init(); + assertThat(service.currentModelConfigs).isEmpty(); + } + +} From 152e2200f017cb1ea13627c9d6212ab7ce0e0f6d Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 25 Jul 2023 10:11:04 +0300 Subject: [PATCH 312/421] UI: Clear code after merge --- ui-ngx/src/app/modules/home/components/router-tabs.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/router-tabs.component.ts b/ui-ngx/src/app/modules/home/components/router-tabs.component.ts index 2cc6b0da81..c5ffb11908 100644 --- a/ui-ngx/src/app/modules/home/components/router-tabs.component.ts +++ b/ui-ngx/src/app/modules/home/components/router-tabs.component.ts @@ -96,7 +96,6 @@ export class RouterTabsComponent extends PageComponent implements OnInit { type: 'link', name: tab.data?.breadcrumb?.label ?? '', icon: tab.data?.breadcrumb?.icon ?? '', - isMdiIcon: tab.data?.breadcrumb?.icon.startsWith('mdi:') ?? false, path: `${sectionPath}/${tab.path}` })); } else { From 83d525aa92e3a16903ca0067fc9b7795aa0a032d Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 25 Jul 2023 10:35:14 +0300 Subject: [PATCH 313/421] UI: Clear code after merge --- ui-ngx/src/app/app.component.ts | 9 ++++----- ui-ngx/src/app/shared/models/icon.models.ts | 9 ++++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/app.component.ts b/ui-ngx/src/app/app.component.ts index 8f6ab35590..a3b4657120 100644 --- a/ui-ngx/src/app/app.component.ts +++ b/ui-ngx/src/app/app.component.ts @@ -30,7 +30,7 @@ import { combineLatest } from 'rxjs'; import { selectIsAuthenticated, selectIsUserLoaded } from '@core/auth/auth.selectors'; import { distinctUntilChanged, filter, map, skip } from 'rxjs/operators'; import { AuthService } from '@core/auth/auth.service'; -import { svgIcons } from '@shared/models/icon.models'; +import { svgIcons, svgIconsUrl } from '@shared/models/icon.models'; @Component({ selector: 'tb-root', @@ -65,10 +65,9 @@ export class AppComponent implements OnInit { ); } - this.matIconRegistry.addSvgIcon('windows', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/windows.svg')); - this.matIconRegistry.addSvgIcon('macos', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/macos.svg')); - this.matIconRegistry.addSvgIcon('linux', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/linux.svg')); - this.matIconRegistry.addSvgIcon('docker', this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/docker.svg')); + for (const svgIcon of Object.keys(svgIconsUrl)) { + this.matIconRegistry.addSvgIcon(svgIcon, this.domSanitizer.bypassSecurityTrustResourceUrl(svgIcons[svgIcon])); + } this.storageService.testLocalStorage(); diff --git a/ui-ngx/src/app/shared/models/icon.models.ts b/ui-ngx/src/app/shared/models/icon.models.ts index 8d7d4f65bd..85c6617aa1 100644 --- a/ui-ngx/src/app/shared/models/icon.models.ts +++ b/ui-ngx/src/app/shared/models/icon.models.ts @@ -56,8 +56,15 @@ export const svgIcons: {[key: string]: string} = { '' }; +export const svgIconsUrl: { [key: string]: string } = { + windows: '/assets/windows.svg', + macos: '/assets/macos.svg', + linux: '/assets/linux.svg', + docker: '/assets/docker.svg' +}; + const svgIconNamespaces: string[] = ['mdi']; -const svgIconNames = Object.keys(svgIcons); +const svgIconNames = [...Object.keys(svgIcons), ...Object.keys(svgIconsUrl)]; export const splitIconName = (iconName: string): [string, string] => { if (!iconName) { From 08fb544b7fc29877373b2f135dacbc9ccb5fd2f9 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 25 Jul 2023 15:22:18 +0300 Subject: [PATCH 314/421] UI: Fixed alarm filter panel --- .../alarm/alarm-filter-config.component.html | 22 +++++++++++-------- .../alarm/alarm-filter-config.component.scss | 20 ++++++++++++++++- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html index c5ed4fe52a..cbbcc2ccb9 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.html @@ -56,25 +56,28 @@
-
-
alarm.alarm-status-list
+
+
alarm.alarm-status-list
{{ alarmSearchStatusTranslationMap.get(searchStatus) | translate }}
-
-
alarm.alarm-severity-list
+
+
alarm.alarm-severity-list
{{ alarmSeverityTranslationMap.get(alarmSeverityEnum[alarmSeverity]) | translate }}
-
-
alarm.alarm-type-list
- +
+
alarm.alarm-type-list
+ @@ -89,9 +92,10 @@
-
-
alarm.assignee
+
+
alarm.assignee
diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.scss b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.scss index 1c10e244b5..95f78f8fde 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.scss +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-filter-config.component.scss @@ -15,11 +15,24 @@ */ :host { display: block; - overflow: hidden; + overflow: scroll; max-width: 100%; .mdc-button { max-width: 100%; } + + .filters-row-mobile { + flex-direction: column; + align-items: start; + border: none; + padding: 0; + } + .filters-title-mobile { + font-size: 14px; + } + .filters-fields-width-mobile { + width: 100%; + } } :host ::ng-deep { @@ -32,4 +45,9 @@ text-overflow: ellipsis; } } + .mat-mdc-chip { + .mdc-evolution-chip__cell, .mat-mdc-chip-action, .mat-mdc-chip-action-label { + overflow: hidden; + } + } } From bab3eef8d73552d10be83012e48e12ec9fba6e00 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 26 Jul 2023 10:19:45 +0300 Subject: [PATCH 315/421] UI: Fix install command in device connectivity --- ui-ngx/src/app/app.component.ts | 2 +- .../device/device-check-connectivity-dialog.component.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/app.component.ts b/ui-ngx/src/app/app.component.ts index a3b4657120..67e2fd7b42 100644 --- a/ui-ngx/src/app/app.component.ts +++ b/ui-ngx/src/app/app.component.ts @@ -66,7 +66,7 @@ export class AppComponent implements OnInit { } for (const svgIcon of Object.keys(svgIconsUrl)) { - this.matIconRegistry.addSvgIcon(svgIcon, this.domSanitizer.bypassSecurityTrustResourceUrl(svgIcons[svgIcon])); + this.matIconRegistry.addSvgIcon(svgIcon, this.domSanitizer.bypassSecurityTrustResourceUrl(svgIconsUrl[svgIcon])); } this.storageService.testLocalStorage(); diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html index 11e1435119..0f9c6dc055 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html @@ -94,7 +94,7 @@
device.connectivity.install-necessary-client-tools
+ [data]='createMarkDownCommand("brew install curl")'>
device.connectivity.install-necessary-client-tools
+ [data]='createMarkDownCommand("sudo apt-get install curl")'>
downloadMqttServerCertificate(@ApiParam(value = PROTOCOL_PARAM_DESCRIPTION) - @PathVariable(PROTOCOL) String protocol) throws ThingsboardException, IOException { - String certificate = checkSslServerPemFile(protocol); + @PathVariable(PROTOCOL) String protocol) throws ThingsboardException, IOException { + checkParameter(PROTOCOL, protocol); + var pemCert = + checkNotNull(deviceConnectivityService.getPemCertFile(protocol), protocol + " pem cert file is not found!"); - ByteArrayResource cert = new ByteArrayResource(certificate.getBytes()); return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + MQTT_SSL_PEM_FILE_NAME) - .header("x-filename", MQTT_SSL_PEM_FILE_NAME) - .contentLength(cert.contentLength()) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + PEM_CERT_FILE_NAME) + .header("x-filename", PEM_CERT_FILE_NAME) + .contentLength(pemCert.contentLength()) .contentType(MediaType.APPLICATION_OCTET_STREAM) - .body(cert); + .body(pemCert); } } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 5886e74ce4..86e7ec0ffe 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1004,7 +1004,7 @@ device: enabled: "${DEVICE_CONNECTIVITY_MQTTS_ENABLED:false}" host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:}" port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" - ssl_server_pem_path: "${DEVICE_CONNECTIVITY_MQTTS_SERVER_CHAIN_PATH:}" + pem_cert_file: "${DEVICE_CONNECTIVITY_MQTT_SSL_PEM_CERT:mqttserver.pem}" coap: enabled: "${DEVICE_CONNECTIVITY_COAP_ENABLED:true}" host: "${DEVICE_CONNECTIVITY_COAP_HOST:}" diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java index 51643fa1d4..90355d885d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityService.java @@ -16,14 +16,14 @@ package org.thingsboard.server.dao.device; import com.fasterxml.jackson.databind.JsonNode; +import org.springframework.core.io.Resource; import org.thingsboard.server.common.data.Device; -import java.io.IOException; import java.net.URISyntaxException; public interface DeviceConnectivityService { JsonNode findDevicePublishTelemetryCommands(String baseUrl, Device device) throws URISyntaxException; - String getSslServerChain(String protocol) throws IOException; + Resource getPemCertFile(String protocol); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java index 454c795f12..033aa4e0bc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityConfiguration.java @@ -26,4 +26,9 @@ import java.util.Map; @Data public class DeviceConnectivityConfiguration { private Map connectivity; + + public boolean isEnabled(String protocol) { + var info = connectivity.get(protocol); + return info != null && info.isEnabled(); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java index fa5c61328b..b243be9995 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityInfo.java @@ -19,8 +19,8 @@ import lombok.Data; @Data public class DeviceConnectivityInfo { - private Boolean enabled; + private boolean enabled; private String host; private String port; - private String sslServerPemPath; + private String pemCertFile; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java similarity index 64% rename from dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java rename to dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java index e7bfefabbd..32a582ba07 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceСonnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java @@ -19,26 +19,25 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.ResourceUtils; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; +import org.thingsboard.server.dao.util.DeviceConnectivityUtil; -import java.io.File; -import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -49,17 +48,12 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.LINUX; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getCoapClientCommand; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getCurlCommand; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getDockerMosquittoClientsPublishCommand; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.getMosquittoPubPublishCommand; @Service("DeviceConnectivityDaoService") @Slf4j -public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService { +public class DeviceConnectivityServiceImpl implements DeviceConnectivityService { public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String INCORRECT_DEVICE_ID = "Incorrect deviceId "; @@ -113,12 +107,13 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService } @Override - public String getSslServerChain(String protocol) throws IOException { - String mqttSslPemPath = deviceConnectivityConfiguration.getConnectivity() + public Resource getPemCertFile(String protocol) { + String certFilePath = deviceConnectivityConfiguration.getConnectivity() .get(protocol) - .getSslServerPemPath(); - if (!mqttSslPemPath.isEmpty() && ResourceUtils.resourceExists(this, mqttSslPemPath)) { - return FileUtils.readFileToString(new File(mqttSslPemPath), StandardCharsets.UTF_8); + .getPemCertFile(); + + if (StringUtils.isNotBlank(certFilePath) && ResourceUtils.resourceExists(this, certFilePath)) { + return new ClassPathResource(certFilePath); } else { return null; } @@ -134,15 +129,15 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService } private String getHttpPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { - DeviceConnectivityInfo httpProps = deviceConnectivityConfiguration.getConnectivity().get(protocol); - if (httpProps == null || !httpProps.getEnabled() || + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + if (properties == null || !properties.isEnabled() || deviceCredentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) { return null; } - String hostName = httpProps.getHost().isEmpty() ? new URI(baseUrl).getHost() : httpProps.getHost(); - String port = httpProps.getPort().isEmpty() ? "" : ":" + httpProps.getPort(); + String hostName = getHost(baseUrl, properties); + String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); - return getCurlCommand(protocol, hostName, port, deviceCredentials); + return DeviceConnectivityUtil.getHttpPublishCommand(protocol, hostName, port, deviceCredentials); } private JsonNode getMqttTransportPublishCommands(String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { @@ -152,23 +147,31 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService private JsonNode getMqttTransportPublishCommands(String baseUrl, String topic, DeviceCredentials deviceCredentials) throws URISyntaxException { ObjectNode mqttCommands = JacksonUtil.newObjectNode(); - Optional.ofNullable(getMqttPublishCommand(baseUrl, topic, deviceCredentials)) - .ifPresent(v -> mqttCommands.put(MQTT, v)); - List mqttsPublishCommand = getMqttsPublishCommand(baseUrl, topic, deviceCredentials); - if (mqttsPublishCommand != null){ - if (mqttsPublishCommand.size() > 1) { + if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { + mqttCommands.put(MQTTS, CHECK_DOCUMENTATION); + return mqttCommands; + } + + ObjectNode dockerMqttCommands = JacksonUtil.newObjectNode(); + + if (deviceConnectivityConfiguration.isEnabled(MQTT)) { + Optional.ofNullable(getMqttPublishCommand(baseUrl, topic, deviceCredentials)). + ifPresent(v -> mqttCommands.put(MQTT, v)); + + Optional.ofNullable(getDockerMqttPublishCommand(MQTT, baseUrl, topic, deviceCredentials)) + .ifPresent(v -> dockerMqttCommands.put(MQTT, v)); + } + + if (deviceConnectivityConfiguration.isEnabled(MQTTS)) { + List mqttsPublishCommand = getMqttsPublishCommand(baseUrl, topic, deviceCredentials); + if (mqttsPublishCommand != null) { ArrayNode arrayNode = mqttCommands.putArray(MQTTS); mqttsPublishCommand.forEach(arrayNode::add); - } else { - mqttCommands.put(MQTTS, mqttsPublishCommand.get(0)); } - } - ObjectNode dockerMqttCommands = JacksonUtil.newObjectNode(); - Optional.ofNullable(getDockerMqttPublishCommand(MQTT,baseUrl, topic, deviceCredentials)) - .ifPresent(v -> dockerMqttCommands.put(MQTT, v)); - Optional.ofNullable(getDockerMqttPublishCommand(MQTTS, baseUrl, topic, deviceCredentials)) - .ifPresent(v -> dockerMqttCommands.put(MQTTS, v)); + Optional.ofNullable(getDockerMqttPublishCommand(MQTTS, baseUrl, topic, deviceCredentials)) + .ifPresent(v -> dockerMqttCommands.put(MQTTS, v)); + } if (!dockerMqttCommands.isEmpty()) { mqttCommands.set(DOCKER, dockerMqttCommands); @@ -178,70 +181,81 @@ public class DeviceСonnectivityServiceImpl implements DeviceConnectivityService private String getMqttPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(MQTT); - if (properties == null || !properties.getEnabled()) { - return null; - } - String mqttHost = properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); + String mqttHost = getHost(baseUrl, properties); String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); - return getMosquittoPubPublishCommand(MQTT, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + return DeviceConnectivityUtil.getMqttPublishCommand(MQTT, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); } private List getMqttsPublishCommand(String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { - String pubCommand; - if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { - return List.of(CHECK_DOCUMENTATION); - } else { - DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(MQTTS); - if (properties == null || !properties.getEnabled()) { - return null; - } - String mqttHost = properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); - String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); - pubCommand = getMosquittoPubPublishCommand(MQTTS, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); - } + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(MQTTS); + String mqttHost = getHost(baseUrl, properties); + String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); + String pubCommand = DeviceConnectivityUtil.getMqttPublishCommand(MQTTS, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); ArrayList commands = new ArrayList<>(); if (pubCommand != null) { - commands.add("curl " + baseUrl + "/api/device-connectivity/mqtts/certificate/download -o /tmp/tb-server-chain.pem"); + commands.add(DeviceConnectivityUtil.getCurlPemCertCommand(baseUrl, MQTTS)); commands.add(pubCommand); return commands; } return null; } - private String getDockerMqttPublishCommand(String protocol, String baseUrl, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) throws URISyntaxException { DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); - if (properties == null || !properties.getEnabled()) { - return null; - } - String mqttHost = properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); + String mqttHost = getHost(baseUrl, properties); String mqttPort = properties.getPort().isEmpty() ? null : properties.getPort(); - return getDockerMosquittoClientsPublishCommand(protocol, baseUrl, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); + return DeviceConnectivityUtil.getDockerMqttPublishCommand(protocol, baseUrl, mqttHost, mqttPort, deviceTelemetryTopic, deviceCredentials); } private JsonNode getCoapTransportPublishCommands(String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { ObjectNode coapCommands = JacksonUtil.newObjectNode(); - Optional.ofNullable(getCoapPublishCommand(COAP, baseUrl, deviceCredentials)) - .ifPresent(v -> coapCommands.put(COAP, v)); - Optional.ofNullable(getCoapPublishCommand(COAPS, baseUrl, deviceCredentials)) - .ifPresent(v -> coapCommands.put(COAPS, v)); + if (deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { + coapCommands.put(COAPS, CHECK_DOCUMENTATION); + return coapCommands; + } + + ObjectNode dockerCoapCommands = JacksonUtil.newObjectNode(); + + if (deviceConnectivityConfiguration.isEnabled(COAP)) { + Optional.ofNullable(getCoapPublishCommand(COAP, baseUrl, deviceCredentials)) + .ifPresent(v -> coapCommands.put(COAP, v)); + + Optional.ofNullable(getDockerCoapPublishCommand(COAP, baseUrl, deviceCredentials)) + .ifPresent(v -> dockerCoapCommands.put(COAP, v)); + } + + if (deviceConnectivityConfiguration.isEnabled(COAPS)) { + Optional.ofNullable(getCoapPublishCommand(COAPS, baseUrl, deviceCredentials)) + .ifPresent(v -> coapCommands.put(COAPS, v)); + + Optional.ofNullable(getDockerCoapPublishCommand(COAPS, baseUrl, deviceCredentials)) + .ifPresent(v -> dockerCoapCommands.put(COAPS, v)); + } + + if (!dockerCoapCommands.isEmpty()) { + coapCommands.set(DOCKER, dockerCoapCommands); + } return coapCommands.isEmpty() ? null : coapCommands; } private String getCoapPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { - if (COAPS.equals(protocol) && deviceCredentials.getCredentialsType() == DeviceCredentialsType.X509_CERTIFICATE) { - return CHECK_DOCUMENTATION; - } DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); - if (properties == null || !properties.getEnabled()) { - return null; - } - String hostName = properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); + String hostName = getHost(baseUrl, properties); String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); + return DeviceConnectivityUtil.getCoapPublishCommand(protocol, hostName, port, deviceCredentials); + } + + private String getDockerCoapPublishCommand(String protocol, String baseUrl, DeviceCredentials deviceCredentials) throws URISyntaxException { + DeviceConnectivityInfo properties = deviceConnectivityConfiguration.getConnectivity().get(protocol); + String host = getHost(baseUrl, properties); + String port = properties.getPort().isEmpty() ? "" : ":" + properties.getPort(); + return DeviceConnectivityUtil.getDockerCoapPublishCommand(protocol, host, port, deviceCredentials); + } - return getCoapClientCommand(protocol, hostName, port, deviceCredentials); + private String getHost(String baseUrl, DeviceConnectivityInfo properties) throws URISyntaxException { + return properties.getHost().isEmpty() ? new URI(baseUrl).getHost() : properties.getHost(); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java index dad405b093..1d20c62d70 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java @@ -30,19 +30,22 @@ public class DeviceConnectivityUtil { public static final String MQTTS = "mqtts"; public static final String COAP = "coap"; public static final String COAPS = "coaps"; - public static final String MQTT_SSL_PEM_FILE_NAME = "tb-server-chain.pem"; + public static final String PEM_CERT_FILE_NAME = "tb-server-chain.pem"; public static final String CHECK_DOCUMENTATION = "Check documentation"; public static final String JSON_EXAMPLE_PAYLOAD = "\"{temperature:25}\""; + public static final String DOCKER_RUN = "docker run --rm -it "; + public static final String MQTT_IMAGE = "thingsboard/mosquitto-clients "; + public static final String COAP_IMAGE = "thingsboard/coap-clients "; - public static String getCurlCommand(String protocol, String host, String port, DeviceCredentials deviceCredentials) { + public static String getHttpPublishCommand(String protocol, String host, String port, DeviceCredentials deviceCredentials) { return String.format("curl -v -X POST %s://%s%s/api/v1/%s/telemetry --header Content-Type:application/json --data " + JSON_EXAMPLE_PAYLOAD, protocol, host, port, deviceCredentials.getCredentialsId()); } - public static String getMosquittoPubPublishCommand(String protocol, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { + public static String getMqttPublishCommand(String protocol, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { StringBuilder command = new StringBuilder("mosquitto_pub -d -q 1"); if (MQTTS.equals(protocol)) { - command.append(" --cafile tmp/" + MQTT_SSL_PEM_FILE_NAME); + command.append(" --cafile ").append(PEM_CERT_FILE_NAME); } command.append(" -h ").append(host).append(port == null ? "" : " -p " + port); command.append(" -t ").append(deviceTelemetryTopic); @@ -75,50 +78,34 @@ public class DeviceConnectivityUtil { return command.toString(); } - public static String getDockerMosquittoClientsPublishCommand(String protocol, String baseUrl, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { - StringBuilder command = new StringBuilder("docker run -it --rm thingsboard/mosquitto-clients "); - if (MQTTS.equals(protocol)) { - command.append("/bin/sh -c \"curl -o /tmp/tb-server-chain.pem ").append(baseUrl).append("/api/device-connectivity/mqtts/certificate/download && "); - } - command.append("pub"); - if (MQTTS.equals(protocol)) { - command.append(" --cafile tmp/" + MQTT_SSL_PEM_FILE_NAME); - } - command.append(" -h ").append(host).append(port == null ? "" : " -p " + port); - command.append(" -t ").append(deviceTelemetryTopic); + public static String getDockerMqttPublishCommand(String protocol, String baseUrl, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { + String mqttCommand = getMqttPublishCommand(protocol, host, port, deviceTelemetryTopic, deviceCredentials); - switch (deviceCredentials.getCredentialsType()) { - case ACCESS_TOKEN: - command.append(" -u ").append(deviceCredentials.getCredentialsId()); - break; - case MQTT_BASIC: - BasicMqttCredentials credentials = JacksonUtil.fromString(deviceCredentials.getCredentialsValue(), - BasicMqttCredentials.class); - if (credentials != null) { - if (credentials.getClientId() != null) { - command.append(" -i ").append(credentials.getClientId()); - } - if (credentials.getUserName() != null) { - command.append(" -u ").append(credentials.getUserName()); - } - if (credentials.getPassword() != null) { - command.append(" -P ").append(credentials.getPassword()); - } - } else { - return null; - } - break; - default: - return null; + if (mqttCommand == null) { + return null; } - command.append(" -m " + JSON_EXAMPLE_PAYLOAD); + + StringBuilder mqttDockerCommand = new StringBuilder(); + mqttDockerCommand.append(DOCKER_RUN).append(MQTT_IMAGE); + if (MQTTS.equals(protocol)) { - command.append("\""); + mqttDockerCommand.append("/bin/sh -c \"") + .append(getCurlPemCertCommand(baseUrl, protocol)) + .append(" && ") + .append(mqttCommand) + .append("\""); + } else { + mqttDockerCommand.append(mqttCommand); } - return command.toString(); + + return mqttDockerCommand.toString(); } - public static String getCoapClientCommand(String protocol, String host, String port, DeviceCredentials deviceCredentials) { + public static String getCurlPemCertCommand(String baseUrl, String protocol) { + return String.format("curl -f -S -o %s %s/api/device-connectivity/%s/certificate/download", PEM_CERT_FILE_NAME, baseUrl, protocol); + } + + public static String getCoapPublishCommand(String protocol, String host, String port, DeviceCredentials deviceCredentials) { switch (deviceCredentials.getCredentialsType()) { case ACCESS_TOKEN: String client = COAPS.equals(protocol) ? "coap-client-openssl" : "coap-client"; @@ -128,4 +115,9 @@ public class DeviceConnectivityUtil { return null; } } + + public static String getDockerCoapPublishCommand(String protocol, String host, String port, DeviceCredentials deviceCredentials) { + String coapCommand = getCoapPublishCommand(protocol, host, port, deviceCredentials); + return coapCommand != null ? String.format("%s%s%s", DOCKER_RUN, COAP_IMAGE, coapCommand) : null; + } } From b8253b139b9c531b12bac74433665dc273ca88ab Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 26 Jul 2023 10:23:32 +0200 Subject: [PATCH 317/421] fixed tests --- .../DeviceConnectivityControllerTest.java | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index 5e40f3e993..7427ec1fc1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -57,10 +57,8 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.LINUX; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.WINDOWS; @TestPropertySource(properties = { "device.connectivity.https.enabled=true", @@ -157,7 +155,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { device.setType("default"); Device savedDevice = doPost("/api/device", device, Device.class); JsonNode commands = - doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); DeviceCredentials credentials = doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); @@ -176,24 +175,24 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + "-u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); - assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl http://localhost:80/api/device-connectivity/mqtts/certificate/download -o /tmp/tb-server-chain.pem"); - assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tmp/tb-server-chain.pem -h localhost -p 8883 " + - "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " + + "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); - assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + + assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients mosquitto_pub -d -q 1 -h localhost" + " -p 1883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); - assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients " + - "/bin/sh -c \"curl -o /tmp/tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + - "pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"\"", + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + + "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"\"", credentials.getCredentialsId())); JsonNode linuxCoapCommands = commands.get(COAP); assertThat(linuxCoapCommands.get(COAP).asText()).isEqualTo(String.format("coap-client -m POST coap://localhost:5683/api/v1/%s/telemetry " + - "-t json -e \"{temperature:25}\"", credentials.getCredentialsId())); + "-t json -e \"{temperature:25}\"", credentials.getCredentialsId())); assertThat(linuxCoapCommands.get(COAPS).asText()).isEqualTo(String.format("coap-client-openssl -m POST coaps://localhost:5684/api/v1/%s/telemetry" + - " -t json -e \"{temperature:25}\"", credentials.getCredentialsId())); + " -t json -e \"{temperature:25}\"", credentials.getCredentialsId())); } @Test @@ -207,23 +206,24 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); JsonNode commands = - doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId() , new TypeReference<>() {}); + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); assertThat(commands).hasSize(1); JsonNode mqttCommands = commands.get(MQTT); assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + - "-u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl http://localhost:80/api/device-connectivity/mqtts/certificate/download -o /tmp/tb-server-chain.pem"); - assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tmp/tb-server-chain.pem -h localhost -p 8883 " + + "-u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " + "-t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); - assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + + assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients mosquitto_pub -d -q 1 -h localhost" + " -p 1883 -t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients " + - "/bin/sh -c \"curl -o /tmp/tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + - "pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"\"", + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + + "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); } @@ -250,23 +250,24 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); JsonNode commands = - doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId() , new TypeReference<>() {}); + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); assertThat(commands).hasSize(1); JsonNode mqttCommands = commands.get(MQTT); assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + "-i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl http://localhost:80/api/device-connectivity/mqtts/certificate/download -o /tmp/tb-server-chain.pem"); - assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tmp/tb-server-chain.pem -h localhost -p 8883 " + + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " + "-t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); - assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients pub -h localhost" + + assertThat(dockerMqttCommands.get(MQTT).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients mosquitto_pub -d -q 1 -h localhost" + " -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run -it --rm thingsboard/mosquitto-clients " + - "/bin/sh -c \"curl -o /tmp/tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + - "pub --cafile tmp/tb-server-chain.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"\"", + assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + + "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); } @@ -286,9 +287,10 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); JsonNode commands = - doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); assertThat(commands).hasSize(1); - assertThat(commands.get(MQTT).get(MQTTS).get(0).asText()).isEqualTo(CHECK_DOCUMENTATION); + assertThat(commands.get(MQTT).get(MQTTS).asText()).isEqualTo(CHECK_DOCUMENTATION); assertThat(commands.get(MQTT).get(DOCKER)).isNull(); } @@ -303,7 +305,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); JsonNode commands = - doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); assertThat(commands).hasSize(1); JsonNode linuxCommands = commands.get(COAP); @@ -329,7 +332,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); JsonNode commands = - doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() {}); + doGetTyped("/api/device-connectivity/" + savedDevice.getId().getId(), new TypeReference<>() { + }); assertThat(commands).hasSize(1); assertThat(commands.get(COAP).get(COAPS).asText()).isEqualTo(CHECK_DOCUMENTATION); } From 329a24c019cba7f2df062306d0b95ea3311d4f63 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 26 Jul 2023 11:05:50 +0200 Subject: [PATCH 318/421] added sparkplug --- .../DeviceConnectivityControllerTest.java | 4 ++-- .../dao/device/DeviceConnectivityServiceImpl.java | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index 7427ec1fc1..36a4365544 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -295,7 +295,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { } @Test - public void testFetchPublishTelemetryCommandsForСoapDevice() throws Exception { + public void testFetchPublishTelemetryCommandsForCoapDevice() throws Exception { Device device = new Device(); device.setName("My device"); device.setDeviceProfileId(coapDeviceProfileId); @@ -317,7 +317,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { } @Test - public void testFetchPublishTelemetryCommandsForСoapDeviceWithX509Creds() throws Exception { + public void testFetchPublishTelemetryCommandsForCoapDeviceWithX509Creds() throws Exception { Device device = new Device(); device.setName("My device"); device.setDeviceProfileId(coapDeviceProfileId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java index 32a582ba07..c06103d8f3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceConnectivityServiceImpl.java @@ -91,10 +91,17 @@ public class DeviceConnectivityServiceImpl implements DeviceConnectivityService case MQTT: MqttDeviceProfileTransportConfiguration transportConfiguration = (MqttDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); - String topicName = transportConfiguration.getDeviceTelemetryTopic(); - - Optional.ofNullable(getMqttTransportPublishCommands(baseUrl, topicName, creds)) - .ifPresent(v -> commands.set(MQTT, v)); + //TODO: add sparkplug command with emulator (check SSL) + if (transportConfiguration.isSparkplug()) { + ObjectNode sparkplug = JacksonUtil.newObjectNode(); + sparkplug.put("sparkplug", CHECK_DOCUMENTATION); + commands.set(MQTT, sparkplug); + } else { + String topicName = transportConfiguration.getDeviceTelemetryTopic(); + + Optional.ofNullable(getMqttTransportPublishCommands(baseUrl, topicName, creds)) + .ifPresent(v -> commands.set(MQTT, v)); + } break; case COAP: Optional.ofNullable(getCoapTransportPublishCommands(baseUrl, creds)) From 7e27c5b6833a725c4d0c4e524b3c483d95001451 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 13 Jun 2023 18:17:25 +0200 Subject: [PATCH 319/421] mqtt-client: messages processing moved from netty event loop pool and to the handlerExecutor to make netty handlers non-blocking --- .../msa/connectivity/MqttClientTest.java | 16 ++- .../connectivity/MqttGatewayClientTest.java | 16 ++- netty-mqtt/pom.xml | 4 + .../thingsboard/mqtt/MqttChannelHandler.java | 113 +++++++++++++----- .../java/org/thingsboard/mqtt/MqttClient.java | 7 +- .../org/thingsboard/mqtt/MqttClientImpl.java | 15 ++- .../thingsboard/mqtt/MqttSubscription.java | 2 +- .../mqtt/integration/MqttIntegrationTest.java | 16 ++- .../rule/engine/mqtt/TbMqttNode.java | 2 +- 9 files changed, 153 insertions(+), 38 deletions(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java index 893c8b565c..96e57549a8 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java @@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import org.thingsboard.common.util.AbstractListeningExecutor; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.mqtt.MqttClient; import org.thingsboard.mqtt.MqttClientConfig; @@ -74,8 +75,18 @@ import static org.thingsboard.server.msa.prototypes.DevicePrototypes.defaultDevi public class MqttClientTest extends AbstractContainerTest { private Device device; + AbstractListeningExecutor handlerExecutor; + @BeforeMethod public void setUp() throws Exception { + this.handlerExecutor = new AbstractListeningExecutor() { + @Override + protected int getThreadPollSize() { + return 4; + } + }; + handlerExecutor.init(); + testRestClient.login("tenant@thingsboard.org", "tenant"); device = testRestClient.postDevice("", defaultDevicePrototype("http_")); } @@ -83,6 +94,9 @@ public class MqttClientTest extends AbstractContainerTest { @AfterMethod public void tearDown() { testRestClient.deleteDeviceIfExists(device.getId()); + if (handlerExecutor != null) { + handlerExecutor.destroy(); + } } @Test public void telemetryUpload() throws Exception { @@ -465,7 +479,7 @@ public class MqttClientTest extends AbstractContainerTest { MqttClientConfig clientConfig = new MqttClientConfig(); clientConfig.setClientId("MQTT client from test"); clientConfig.setUsername(username); - MqttClient mqttClient = MqttClient.create(clientConfig, listener); + MqttClient mqttClient = MqttClient.create(clientConfig, listener, handlerExecutor); mqttClient.connect("localhost", 1883).get(); return mqttClient; } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java index a038d4cf50..8cddb69fa3 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java @@ -32,6 +32,7 @@ import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import org.thingsboard.common.util.AbstractListeningExecutor; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.mqtt.MqttClient; @@ -76,8 +77,18 @@ public class MqttGatewayClientTest extends AbstractContainerTest { private MqttMessageListener listener; private JsonParser jsonParser = new JsonParser(); + AbstractListeningExecutor handlerExecutor; + @BeforeMethod public void createGateway() throws Exception { + this.handlerExecutor = new AbstractListeningExecutor() { + @Override + protected int getThreadPollSize() { + return 4; + } + }; + handlerExecutor.init(); + testRestClient.login("tenant@thingsboard.org", "tenant"); gatewayDevice = testRestClient.postDevice("", defaultGatewayPrototype()); DeviceCredentials gatewayDeviceCredentials = testRestClient.getDeviceCredentialsByDeviceId(gatewayDevice.getId()); @@ -94,6 +105,9 @@ public class MqttGatewayClientTest extends AbstractContainerTest { this.listener = null; this.mqttClient = null; this.createdDevice = null; + if (handlerExecutor != null) { + handlerExecutor.destroy(); + } } @Test @@ -407,7 +421,7 @@ public class MqttGatewayClientTest extends AbstractContainerTest { MqttClientConfig clientConfig = new MqttClientConfig(); clientConfig.setClientId("MQTT client from test"); clientConfig.setUsername(deviceCredentials.getCredentialsId()); - MqttClient mqttClient = MqttClient.create(clientConfig, listener); + MqttClient mqttClient = MqttClient.create(clientConfig, listener, handlerExecutor); mqttClient.connect("localhost", 1883).get(); return mqttClient; } diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 60883f4b34..400b486e18 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -35,6 +35,10 @@ + + org.thingsboard.common + util + io.netty netty-codec-mqtt diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttChannelHandler.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttChannelHandler.java index e243f66633..6b3a4e009e 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttChannelHandler.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttChannelHandler.java @@ -16,6 +16,10 @@ package org.thingsboard.mqtt; import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; @@ -34,8 +38,15 @@ import io.netty.handler.codec.mqtt.MqttQoS; import io.netty.handler.codec.mqtt.MqttSubAckMessage; import io.netty.handler.codec.mqtt.MqttUnsubAckMessage; import io.netty.util.CharsetUtil; +import io.netty.util.ReferenceCountUtil; import io.netty.util.concurrent.Promise; +import lombok.extern.slf4j.Slf4j; +import org.checkerframework.checker.nullness.qual.Nullable; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; + +@Slf4j final class MqttChannelHandler extends SimpleChannelInboundHandler { private final MqttClientImpl client; @@ -110,27 +121,48 @@ final class MqttChannelHandler extends SimpleChannelInboundHandler super.channelInactive(ctx); } - private void invokeHandlersForIncomingPublish(MqttPublishMessage message) { - boolean handlerInvoked = false; - for (MqttSubscription subscription : ImmutableSet.copyOf(this.client.getSubscriptions().values())) { - if (subscription.matches(message.variableHeader().topicName())) { - if (subscription.isOnce() && subscription.isCalled()) { - continue; - } - message.payload().markReaderIndex(); - subscription.setCalled(true); - subscription.getHandler().onMessage(message.variableHeader().topicName(), message.payload()); - if (subscription.isOnce()) { - this.client.off(subscription.getTopic(), subscription.getHandler()); + ListenableFuture invokeHandlersForIncomingPublish(MqttPublishMessage message) { + var future = Futures.immediateVoidFuture(); + var handlerInvoked = new AtomicBoolean(); + try { + for (MqttSubscription subscription : ImmutableSet.copyOf(this.client.getSubscriptions().values())) { + if (subscription.matches(message.variableHeader().topicName())) { + future = Futures.transform(future, x -> { + if (subscription.isOnce() && subscription.isCalled()) { + return null; + } + message.payload().markReaderIndex(); + subscription.setCalled(true); + subscription.getHandler().onMessage(message.variableHeader().topicName(), message.payload()); + if (subscription.isOnce()) { + this.client.off(subscription.getTopic(), subscription.getHandler()); + } + message.payload().resetReaderIndex(); + handlerInvoked.set(true); + return null; + }, client.getHandlerExecutor()); } - message.payload().resetReaderIndex(); - handlerInvoked = true; } + future = Futures.transform(future, x -> { + if (!handlerInvoked.get() && client.getDefaultHandler() != null) { + client.getDefaultHandler().onMessage(message.variableHeader().topicName(), message.payload()); + } + return null; + }, client.getHandlerExecutor()); + } finally { + Futures.addCallback(future, new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void result) { + message.payload().release(); + } + + @Override + public void onFailure(Throwable t) { + message.payload().release(); + } + }, MoreExecutors.directExecutor()); } - if (!handlerInvoked && client.getDefaultHandler() != null) { - client.getDefaultHandler().onMessage(message.variableHeader().topicName(), message.payload()); - } - message.payload().release(); + return future; } private void handleConack(Channel channel, MqttConnAckMessage message) { @@ -197,11 +229,13 @@ final class MqttChannelHandler extends SimpleChannelInboundHandler break; case AT_LEAST_ONCE: - invokeHandlersForIncomingPublish(message); + var future = invokeHandlersForIncomingPublish(message); if (message.variableHeader().packetId() != -1) { - MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBACK, false, MqttQoS.AT_MOST_ONCE, false, 0); - MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(message.variableHeader().packetId()); - channel.writeAndFlush(new MqttPubAckMessage(fixedHeader, variableHeader)); + future.addListener(() -> { + MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBACK, false, MqttQoS.AT_MOST_ONCE, false, 0); + MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(message.variableHeader().packetId()); + channel.writeAndFlush(new MqttPubAckMessage(fixedHeader, variableHeader)); + }, MoreExecutors.directExecutor()); } break; @@ -256,14 +290,20 @@ final class MqttChannelHandler extends SimpleChannelInboundHandler } private void handlePubrel(Channel channel, MqttMessage message) { + var future = Futures.immediateVoidFuture(); if (this.client.getQos2PendingIncomingPublishes().containsKey(((MqttMessageIdVariableHeader) message.variableHeader()).messageId())) { MqttIncomingQos2Publish incomingQos2Publish = this.client.getQos2PendingIncomingPublishes().get(((MqttMessageIdVariableHeader) message.variableHeader()).messageId()); - this.invokeHandlersForIncomingPublish(incomingQos2Publish.getIncomingPublish()); - this.client.getQos2PendingIncomingPublishes().remove(incomingQos2Publish.getIncomingPublish().variableHeader().packetId()); + future = invokeHandlersForIncomingPublish(incomingQos2Publish.getIncomingPublish()); + future = Futures.transform(future, x -> { + this.client.getQos2PendingIncomingPublishes().remove(incomingQos2Publish.getIncomingPublish().variableHeader().packetId()); + return null; + }, MoreExecutors.directExecutor()); } - MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBCOMP, false, MqttQoS.AT_MOST_ONCE, false, 0); - MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(((MqttMessageIdVariableHeader) message.variableHeader()).messageId()); - channel.writeAndFlush(new MqttMessage(fixedHeader, variableHeader)); + future.addListener(() -> { + MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBCOMP, false, MqttQoS.AT_MOST_ONCE, false, 0); + MqttMessageIdVariableHeader variableHeader = MqttMessageIdVariableHeader.from(((MqttMessageIdVariableHeader) message.variableHeader()).messageId()); + channel.writeAndFlush(new MqttMessage(fixedHeader, variableHeader)); + }, MoreExecutors.directExecutor()); } private void handlePubcomp(MqttMessage message) { @@ -274,4 +314,23 @@ final class MqttChannelHandler extends SimpleChannelInboundHandler pendingPublish.getPayload().release(); pendingPublish.onPubcompReceived(); } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + try { + if (cause instanceof IOException) { + if (log.isDebugEnabled()) { + log.debug("[{}][{}][{}] IOException: ", client.getClientConfig().getClientId(), client.getClientConfig().getUsername() , ctx.channel().remoteAddress(), + cause); + } else if (log.isInfoEnabled()) { + log.info("[{}][{}][{}] IOException: {}", client.getClientConfig().getClientId(), client.getClientConfig().getUsername() , ctx.channel().remoteAddress(), + cause.getMessage()); + } + } else { + log.warn("exceptionCaught", cause); + } + } finally { + ReferenceCountUtil.release(cause); + } + } } diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClient.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClient.java index 2fe179de31..536a76119f 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClient.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClient.java @@ -21,6 +21,7 @@ import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.handler.codec.mqtt.MqttQoS; import io.netty.util.concurrent.Future; +import org.thingsboard.common.util.ListeningExecutor; public interface MqttClient { @@ -71,6 +72,8 @@ public interface MqttClient { */ void setEventLoop(EventLoopGroup eventLoop); + ListeningExecutor getHandlerExecutor(); + /** * Subscribe on the given topic. When a message is received, MqttClient will invoke the {@link MqttHandler#onMessage(String, ByteBuf)} function of the given handler * @@ -180,8 +183,8 @@ public interface MqttClient { * @param config The config object to use while looking for settings * @param defaultHandler The handler for incoming messages that do not match any topic subscriptions */ - static MqttClient create(MqttClientConfig config, MqttHandler defaultHandler){ - return new MqttClientImpl(config, defaultHandler); + static MqttClient create(MqttClientConfig config, MqttHandler defaultHandler, ListeningExecutor handlerExecutor){ + return new MqttClientImpl(config, defaultHandler, handlerExecutor); } /** diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java index f38a790be7..63d65a1cc2 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttClientImpl.java @@ -46,6 +46,7 @@ import io.netty.util.concurrent.DefaultPromise; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.ListeningExecutor; import java.util.Collections; import java.util.HashSet; @@ -88,13 +89,13 @@ final class MqttClientImpl implements MqttClient { private int port; private MqttClientCallback callback; + private final ListeningExecutor handlerExecutor; /** * Construct the MqttClientImpl with default config */ - public MqttClientImpl(MqttHandler defaultHandler) { - this.clientConfig = new MqttClientConfig(); - this.defaultHandler = defaultHandler; + public MqttClientImpl(MqttHandler defaultHandler, ListeningExecutor handlerExecutor) { + this(new MqttClientConfig(), defaultHandler, handlerExecutor); } /** @@ -103,9 +104,10 @@ final class MqttClientImpl implements MqttClient { * * @param clientConfig The config object to use while looking for settings */ - public MqttClientImpl(MqttClientConfig clientConfig, MqttHandler defaultHandler) { + public MqttClientImpl(MqttClientConfig clientConfig, MqttHandler defaultHandler, ListeningExecutor handlerExecutor) { this.clientConfig = clientConfig; this.defaultHandler = defaultHandler; + this.handlerExecutor = handlerExecutor; } /** @@ -227,6 +229,11 @@ final class MqttClientImpl implements MqttClient { this.eventLoop = eventLoop; } + @Override + public ListeningExecutor getHandlerExecutor() { + return this.handlerExecutor; + } + /** * Subscribe on the given topic. When a message is received, MqttClient will invoke the {@link MqttHandler#onMessage(String, ByteBuf)} function of the given handler * diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscription.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscription.java index 6c4abb4c5c..c4bc9e38c1 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscription.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttSubscription.java @@ -25,7 +25,7 @@ final class MqttSubscription { private final boolean once; - private boolean called; + private volatile boolean called; MqttSubscription(String topic, MqttHandler handler, boolean once) { if (topic == null) { diff --git a/netty-mqtt/src/test/java/org/thingsboard/mqtt/integration/MqttIntegrationTest.java b/netty-mqtt/src/test/java/org/thingsboard/mqtt/integration/MqttIntegrationTest.java index cb1b6b81fe..f39ca01110 100644 --- a/netty-mqtt/src/test/java/org/thingsboard/mqtt/integration/MqttIntegrationTest.java +++ b/netty-mqtt/src/test/java/org/thingsboard/mqtt/integration/MqttIntegrationTest.java @@ -26,6 +26,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.thingsboard.common.util.AbstractListeningExecutor; import org.thingsboard.mqtt.MqttClient; import org.thingsboard.mqtt.MqttClientConfig; import org.thingsboard.mqtt.MqttConnectResult; @@ -49,8 +50,18 @@ public class MqttIntegrationTest { MqttClient mqttClient; + AbstractListeningExecutor handlerExecutor; + @Before public void init() throws Exception { + this.handlerExecutor = new AbstractListeningExecutor() { + @Override + protected int getThreadPollSize() { + return 4; + } + }; + handlerExecutor.init(); + this.eventLoopGroup = new NioEventLoopGroup(); this.mqttServer = new MqttServer(); @@ -68,6 +79,9 @@ public class MqttIntegrationTest { if (this.eventLoopGroup != null) { this.eventLoopGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS); } + if (this.handlerExecutor != null) { + this.handlerExecutor.destroy(); + } } @Test @@ -110,7 +124,7 @@ public class MqttIntegrationTest { MqttClientConfig config = new MqttClientConfig(); config.setTimeoutSeconds(KEEPALIVE_TIMEOUT_SECONDS); config.setReconnectDelay(RECONNECT_DELAY_SECONDS); - MqttClient client = MqttClient.create(config, null); + MqttClient client = MqttClient.create(config, null, handlerExecutor); client.setEventLoop(this.eventLoopGroup); Future connectFuture = client.connect(MQTT_HOST, this.mqttServer.getMqttPort()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 121b9fb756..49b31cb33c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -114,7 +114,7 @@ public class TbMqttNode extends TbAbstractExternalNode { config.setCleanSession(this.mqttNodeConfiguration.isCleanSession()); prepareMqttClientConfig(config); - MqttClient client = MqttClient.create(config, null); + MqttClient client = MqttClient.create(config, null, ctx.getExternalCallExecutor()); client.setEventLoop(ctx.getSharedEventLoop()); Future connectFuture = client.connect(this.mqttNodeConfiguration.getHost(), this.mqttNodeConfiguration.getPort()); MqttConnectResult result; From d74e0c45df8442e709928c3c04efe36442782a07 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 20 Jun 2023 14:26:30 +0200 Subject: [PATCH 320/421] MqttHandler - processAsync (required for AbstractMqttIntegration) --- .../thingsboard/server/msa/connectivity/MqttClientTest.java | 4 +++- .../server/msa/connectivity/MqttGatewayClientTest.java | 4 +++- .../src/main/java/org/thingsboard/mqtt/MqttHandler.java | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java index 96e57549a8..940bd6777e 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttClientTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.msa.connectivity; import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; @@ -493,9 +494,10 @@ public class MqttClientTest extends AbstractContainerTest { } @Override - public void onMessage(String topic, ByteBuf message) { + public ListenableFuture onMessage(String topic, ByteBuf message) { log.info("MQTT message [{}], topic [{}]", message.toString(StandardCharsets.UTF_8), topic); events.add(new MqttEvent(topic, message.toString(StandardCharsets.UTF_8))); + return Futures.immediateVoidFuture(); } } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java index 8cddb69fa3..de11df2623 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.msa.connectivity; import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; @@ -435,9 +436,10 @@ public class MqttGatewayClientTest extends AbstractContainerTest { } @Override - public void onMessage(String topic, ByteBuf message) { + public ListenableFuture onMessage(String topic, ByteBuf message) { log.info("MQTT message [{}], topic [{}]", message.toString(StandardCharsets.UTF_8), topic); events.add(new MqttEvent(topic, message.toString(StandardCharsets.UTF_8))); + return Futures.immediateVoidFuture(); } } diff --git a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttHandler.java b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttHandler.java index 0ec03ff04b..21c07a17cd 100644 --- a/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttHandler.java +++ b/netty-mqtt/src/main/java/org/thingsboard/mqtt/MqttHandler.java @@ -15,9 +15,10 @@ */ package org.thingsboard.mqtt; +import com.google.common.util.concurrent.ListenableFuture; import io.netty.buffer.ByteBuf; public interface MqttHandler { - void onMessage(String topic, ByteBuf payload); + ListenableFuture onMessage(String topic, ByteBuf payload); } From 5e83b2b903d9a9be0d281a55c13fbe18f0f43698 Mon Sep 17 00:00:00 2001 From: rusikv Date: Wed, 26 Jul 2023 14:26:00 +0300 Subject: [PATCH 321/421] Add double quotes to highlight 'remove other entities' confirm phrase in version control dialog --- ui-ngx/src/assets/locale/locale.constant-ca_ES.json | 2 +- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- ui-ngx/src/assets/locale/locale.constant-es_ES.json | 2 +- ui-ngx/src/assets/locale/locale.constant-zh_CN.json | 2 +- ui-ngx/src/assets/locale/locale.constant-zh_TW.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) 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 349d13da2c..dbb54c2bea 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -4481,7 +4481,7 @@ "created": "{{created}} creades", "updated": "{{updated}} actualitzades", "deleted": "{{deleted}} esborrades", - "remove-other-entities-confirm-text": "Atenció! Aquesta acció esborrarà permanentment todas les entitats actuals
no presents a la versió a restaurar.

Escriu eliminar altres entitats per confirmar.", + "remove-other-entities-confirm-text": "Atenció! Aquesta acció esborrarà permanentment todas les entitats actuals
no presents a la versió a restaurar.

Escriu \"remove other entities\" per confirmar.", "auto-commit-to-branch": "autopublicar a la branca {{ branch }}", "default-create-entity-version-name": "{{entityName}} actualizació", "sync-strategy-merge-hint": "Crea o actualitza les entitats seleccionades al repositori. Les altres entitats no seran modificades.", 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 0f96a5f1dc..094ff2ed52 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4429,7 +4429,7 @@ "created": "{{created}} created", "updated": "{{updated}} updated", "deleted": "{{deleted}} deleted", - "remove-other-entities-confirm-text": "Be careful! This will permanently delete all current entities
not present in the version you want to restore.

Please type remove other entities to confirm.", + "remove-other-entities-confirm-text": "Be careful! This will permanently delete all current entities
not present in the version you want to restore.

Please type \"remove other entities\" to confirm.", "auto-commit-to-branch": "auto-commit to {{ branch }} branch", "default-create-entity-version-name": "{{entityName}} update", "sync-strategy-merge-hint": "Creates or updates selected entities in the repository. All other repository entities are not modified.", 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 6518e03f58..a2abda3b1e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -3907,7 +3907,7 @@ "created": "{{created}} creadas", "updated": "{{updated}} actualizadas", "deleted": "{{deleted}} borradas", - "remove-other-entities-confirm-text": "Atención! Esta acción borrará permanentemente todas las entidades actuales
no presentes en la versión a restaurar.

Escribe remove other entities para confirmar.", + "remove-other-entities-confirm-text": "Atención! Esta acción borrará permanentemente todas las entidades actuales
no presentes en la versión a restaurar.

Escribe \"remove other entities\" para confirmar.", "auto-commit-to-branch": "auto-publicar a la rama {{ branch }}", "default-create-entity-version-name": "{{entityName}} actualización", "sync-strategy-merge-hint": "Crea o actualiza las entidades seleccionadas en el repositorio. Las demás entidades no serán modificadas.", 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 b39e10e46c..401014aaca 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -3488,7 +3488,7 @@ "created": "{{created}} 创建", "updated": "{{updated}} 更新", "deleted": "{{deleted}} 删除", - "remove-other-entities-confirm-text": "请注意!在还原版本中不存在的当前实体
将被永久 删除

请输入 remove other entities 进行确认。", + "remove-other-entities-confirm-text": "请注意!在还原版本中不存在的当前实体
将被永久 删除

请输入 \"remove other entities\" 进行确认。", "auto-commit-to-branch": "自动提交到 {{ branch }} 分支", "default-create-entity-version-name": "{{entityName}} 更新", "sync-strategy-merge-hint": "创建或更新选定的实体,仓库其他实体均不修改。", 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 f2cce81824..0caea01b35 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -3338,7 +3338,7 @@ "created": "{{created}}已創建", "updated": "{{updated}}已更新", "deleted": "{{deleted}} 已刪除", - "remove-other-entities-confirm-text": "小心!這將永久刪除您要恢復的版本中不存在的所有當前實體。請鍵入刪除其他實體進行確認。", + "remove-other-entities-confirm-text": "小心!這將永久刪除所有在您要恢復的版本中不存在的當前實體。請輸入 \"remove other entities\" 進行確認。", "auto-commit-to-branch": "自動提交到{{ branch }}分支", "default-create-entity-version-name": "{{entityName}} 更新", "sync-strategy-merge-hint": "在存儲庫中創建或更新選定實體。所有其他存儲實體都不會被修改。", From c3e9ab59918f04c5eb9d79df47948c187d09e7cf Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Wed, 26 Jul 2023 20:38:22 +0200 Subject: [PATCH 322/421] TbKafkaProducerTemplate will add headers for each message when log level: DEBUG - producerId and thread name; TRACE - stacktrace first 10-2=8 lines --- .../queue/kafka/TbKafkaProducerTemplate.java | 28 +++++++++- .../kafka/TbKafkaProducerTemplateTest.java | 54 +++++++++++++++++++ .../queue/src/test/resources/logback-test.xml | 20 +++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 common/queue/src/test/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplateTest.java create mode 100644 common/queue/src/test/resources/logback-test.xml diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java index 15c2f04d17..7c1c28b9f5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java @@ -30,6 +30,9 @@ import org.thingsboard.server.queue.TbQueueCallback; import org.thingsboard.server.queue.TbQueueMsg; import org.thingsboard.server.queue.TbQueueProducer; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -53,10 +56,14 @@ public class TbKafkaProducerTemplate implements TbQueuePro private final Set topics; + @Getter + private final String clientId; + @Builder private TbKafkaProducerTemplate(TbKafkaSettings settings, String defaultTopic, String clientId, TbQueueAdmin admin) { Properties props = settings.toProducerProps(); + this.clientId = Objects.requireNonNull(clientId, "Kafka producer client.id is null"); if (!StringUtils.isEmpty(clientId)) { props.put(ProducerConfig.CLIENT_ID_CONFIG, clientId); } @@ -72,6 +79,24 @@ public class TbKafkaProducerTemplate implements TbQueuePro public void init() { } + void addAnalyticHeaders(List
headers) { + try { + if (log.isDebugEnabled()) { + headers.add(new RecordHeader("_producerId", getClientId().getBytes(StandardCharsets.UTF_8))); + headers.add(new RecordHeader("_threadName", Thread.currentThread().getName().getBytes(StandardCharsets.UTF_8))); + } + if (log.isTraceEnabled()) { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + int maxlevel = Math.min(stackTrace.length, 10); + for (int i = 2; i < maxlevel; i++) { // ignore two levels: getStackTrace and addAnalyticHeaders + headers.add(new RecordHeader("_stackTrace" + i, stackTrace[i].toString().getBytes(StandardCharsets.UTF_8))); + } + } + } catch (Throwable t) { + log.debug("Failed to add analytic header in Kafka producer {}", getClientId(), t); + } + } + @Override public void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback) { try { @@ -79,7 +104,8 @@ public class TbKafkaProducerTemplate implements TbQueuePro String key = msg.getKey().toString(); byte[] data = msg.getData(); ProducerRecord record; - Iterable
headers = msg.getHeaders().getData().entrySet().stream().map(e -> new RecordHeader(e.getKey(), e.getValue())).collect(Collectors.toList()); + List
headers = msg.getHeaders().getData().entrySet().stream().map(e -> new RecordHeader(e.getKey(), e.getValue())).collect(Collectors.toList()); + addAnalyticHeaders(headers); record = new ProducerRecord<>(tpi.getFullTopicName(), null, key, data, headers); producer.send(record, (metadata, exception) -> { if (exception == null) { diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplateTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplateTest.java new file mode 100644 index 0000000000..bfd3c4a6dc --- /dev/null +++ b/common/queue/src/test/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplateTest.java @@ -0,0 +1,54 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.queue.kafka; + +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.common.header.Header; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.thingsboard.server.queue.TbQueueMsg; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.willCallRealMethod; +import static org.mockito.BDDMockito.willReturn; +import static org.mockito.Mockito.mock; + +@Slf4j +class TbKafkaProducerTemplateTest { + + TbKafkaProducerTemplate producerTemplate; + + @BeforeEach + void setUp() { + producerTemplate = mock(TbKafkaProducerTemplate.class); + willCallRealMethod().given(producerTemplate).addAnalyticHeaders(any()); + willReturn("tb-core-to-core-notifications-tb-core-3").given(producerTemplate).getClientId(); + } + + @Test + void testAddAnalyticHeaders() { + List
headers = new ArrayList<>(); + producerTemplate.addAnalyticHeaders(headers); + assertThat(headers).isNotEmpty(); + headers.forEach(r -> log.info("RecordHeader key [{}] value [{}]", r.key(), new String(r.value(), StandardCharsets.UTF_8))); + } + +} diff --git a/common/queue/src/test/resources/logback-test.xml b/common/queue/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..f7053313d4 --- /dev/null +++ b/common/queue/src/test/resources/logback-test.xml @@ -0,0 +1,20 @@ + + + + + + %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + From 2d4fbd6833a65df07900f2249ad921abc77075a4 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 27 Jul 2023 14:48:53 +0300 Subject: [PATCH 323/421] added checkMsgType util method to TbMsg & resolved other review comments --- .../queue/DefaultTbClusterService.java | 4 +- .../state/DefaultDeviceStateService.java | 14 ++--- .../server/common/data/DataConstants.java | 44 +++++++++++++++ .../server/common/data/StringUtils.java | 6 +-- .../thingsboard/server/common/msg/TbMsg.java | 22 ++++++-- .../common/msg/session/SessionMsgType.java | 54 +++++++++++++++++++ .../engine/action/TbAbstractAlarmNode.java | 6 +-- .../TbCopyAttributesToEntityViewNode.java | 11 ++-- .../rule/engine/action/TbMsgCountNode.java | 2 +- .../rule/engine/aws/sns/TbSnsNode.java | 4 +- .../rule/engine/aws/sqs/TbSqsNode.java | 4 +- .../rule/engine/debug/TbMsgGeneratorNode.java | 4 +- .../deduplication/TbMsgDeduplicationNode.java | 6 +-- .../rule/engine/delay/TbMsgDelayNode.java | 2 +- .../engine/edge/AbstractTbMsgPushNode.java | 51 +++++++----------- .../engine/filter/TbAssetTypeSwitchNode.java | 2 +- .../engine/filter/TbCheckRelationNode.java | 4 +- .../engine/filter/TbDeviceTypeSwitchNode.java | 2 +- .../rule/engine/gcp/pubsub/TbPubSubNode.java | 4 +- .../rule/engine/kafka/TbKafkaNode.java | 4 +- .../rule/engine/mail/TbSendEmailNode.java | 7 +-- .../rule/engine/math/TbMathNode.java | 2 +- .../engine/metadata/CalculateDeltaNode.java | 4 +- .../metadata/TbAbstractNodeWithFetchTo.java | 2 +- .../engine/metadata/TbGetTelemetryNode.java | 2 +- .../rule/engine/mqtt/TbMqttNode.java | 2 +- .../notification/TbNotificationNode.java | 3 +- .../rule/engine/profile/DeviceState.java | 31 +++++++---- .../engine/profile/TbDeviceProfileNode.java | 10 ++-- .../rule/engine/rabbitmq/TbRabbitMqNode.java | 2 +- .../rule/engine/rest/TbHttpClient.java | 4 +- .../rule/engine/rpc/TbSendRPCRequestNode.java | 4 +- .../engine/telemetry/TbMsgAttributesNode.java | 2 +- .../engine/telemetry/TbMsgTimeseriesNode.java | 2 +- 34 files changed, 217 insertions(+), 110 deletions(-) create mode 100644 common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 76631aaa95..9154c32701 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -223,9 +223,9 @@ public class DefaultTbClusterService implements TbClusterService { if (isRuleChainTransform && isQueueTransform) { tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName); } else if (isRuleChainTransform) { - tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId); + tbMsg = TbMsg.transformMsgRuleChainId(tbMsg, targetRuleChainId); } else if (isQueueTransform) { - tbMsg = TbMsg.transformMsg(tbMsg, targetQueueName); + tbMsg = TbMsg.transformMsgQueueName(tbMsg, targetQueueName); } return tbMsg; } diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 05d71c4fca..8b09565ef9 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -36,7 +36,6 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.ApiUsageRecordKey; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceIdInfo; import org.thingsboard.server.common.data.EntityType; @@ -103,6 +102,9 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import static org.thingsboard.server.common.data.DataConstants.SCOPE; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; + /** * Created by ashvayka on 01.05.18. */ @@ -575,7 +577,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService> tsData = tsService.findLatest(TenantId.SYS_TENANT_ID, device.getId(), PERSISTENT_ATTRIBUTES); future = Futures.transform(tsData, extractDeviceStateData(device), deviceStateExecutor); } else { - ListenableFuture> attrData = attributesService.find(TenantId.SYS_TENANT_ID, device.getId(), DataConstants.SERVER_SCOPE, PERSISTENT_ATTRIBUTES); + ListenableFuture> attrData = attributesService.find(TenantId.SYS_TENANT_ID, device.getId(), SERVER_SCOPE, PERSISTENT_ATTRIBUTES); future = Futures.transform(attrData, extractDeviceStateData(device), deviceStateExecutor); } return transformInactivityTimeout(future); @@ -586,7 +588,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService { attributes.flatMap(KvEntry::getLongValue).ifPresent((inactivityTimeout) -> { if (inactivityTimeout > 0) { @@ -779,7 +781,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService(deviceId, key, value)); } else { - tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value)); + tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value)); } } @@ -806,7 +808,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService(deviceId, key, value)); } else { - tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value)); + tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value)); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java index ed4431f445..02871a59b6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java @@ -54,9 +54,53 @@ public class DataConstants { return new String[]{CLIENT_SCOPE, SHARED_SCOPE, SERVER_SCOPE}; } + public static final String ALARM = "ALARM"; public static final String IN = "IN"; public static final String OUT = "OUT"; + public static final String INACTIVITY_EVENT = "INACTIVITY_EVENT"; + public static final String CONNECT_EVENT = "CONNECT_EVENT"; + public static final String DISCONNECT_EVENT = "DISCONNECT_EVENT"; + public static final String ACTIVITY_EVENT = "ACTIVITY_EVENT"; + + public static final String ENTITY_CREATED = "ENTITY_CREATED"; + public static final String ENTITY_UPDATED = "ENTITY_UPDATED"; + public static final String ENTITY_DELETED = "ENTITY_DELETED"; + public static final String ENTITY_ASSIGNED = "ENTITY_ASSIGNED"; + public static final String ENTITY_UNASSIGNED = "ENTITY_UNASSIGNED"; + public static final String ATTRIBUTES_UPDATED = "ATTRIBUTES_UPDATED"; + public static final String ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED"; + public static final String TIMESERIES_UPDATED = "TIMESERIES_UPDATED"; + public static final String TIMESERIES_DELETED = "TIMESERIES_DELETED"; + public static final String ALARM_ACK = "ALARM_ACK"; + public static final String ALARM_CLEAR = "ALARM_CLEAR"; + public static final String ALARM_ASSIGNED = "ALARM_ASSIGNED"; + public static final String ALARM_UNASSIGNED = "ALARM_UNASSIGNED"; + public static final String ALARM_DELETE = "ALARM_DELETE"; + public static final String COMMENT_CREATED = "COMMENT_CREATED"; + public static final String COMMENT_UPDATED = "COMMENT_UPDATED"; + public static final String ENTITY_ASSIGNED_FROM_TENANT = "ENTITY_ASSIGNED_FROM_TENANT"; + public static final String ENTITY_ASSIGNED_TO_TENANT = "ENTITY_ASSIGNED_TO_TENANT"; + public static final String PROVISION_SUCCESS = "PROVISION_SUCCESS"; + public static final String PROVISION_FAILURE = "PROVISION_FAILURE"; + public static final String ENTITY_ASSIGNED_TO_EDGE = "ENTITY_ASSIGNED_TO_EDGE"; + public static final String ENTITY_UNASSIGNED_FROM_EDGE = "ENTITY_UNASSIGNED_FROM_EDGE"; + + public static final String RELATION_ADD_OR_UPDATE = "RELATION_ADD_OR_UPDATE"; + public static final String RELATION_DELETED = "RELATION_DELETED"; + public static final String RELATIONS_DELETED = "RELATIONS_DELETED"; + + public static final String RPC_CALL_FROM_SERVER_TO_DEVICE = "RPC_CALL_FROM_SERVER_TO_DEVICE"; + + public static final String RPC_QUEUED = "RPC_QUEUED"; + public static final String RPC_SENT = "RPC_SENT"; + public static final String RPC_DELIVERED = "RPC_DELIVERED"; + public static final String RPC_SUCCESSFUL = "RPC_SUCCESSFUL"; + public static final String RPC_TIMEOUT = "RPC_TIMEOUT"; + public static final String RPC_EXPIRED = "RPC_EXPIRED"; + public static final String RPC_FAILED = "RPC_FAILED"; + public static final String RPC_DELETED = "RPC_DELETED"; + public static final String DEFAULT_SECRET_KEY = ""; public static final String SECRET_KEY_FIELD_NAME = "secretKey"; public static final String DURATION_MS_FIELD_NAME = "durationMs"; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java index 1e818ac8ef..a7671f4327 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/StringUtils.java @@ -38,15 +38,15 @@ public class StringUtils { } public static boolean isBlank(String source) { - return isEmpty(source) || source.trim().isEmpty(); + return source == null || source.isEmpty() || source.trim().isEmpty(); } public static boolean isNotEmpty(String source) { - return !isEmpty(source); + return source != null && !source.isEmpty(); } public static boolean isNotBlank(String source) { - return !isBlank(source); + return source != null && !source.isEmpty() && !source.trim().isEmpty(); } public static String notBlankOrDefault(String src, String def) { diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index 125260def5..bec094b804 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -279,7 +279,7 @@ public final class TbMsg implements Serializable { data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } - public static TbMsg transformMsg(TbMsg tbMsg, TbMsgMetaData metadata) { + public static TbMsg transformMsgMetadata(TbMsg tbMsg, TbMsgMetaData metadata) { return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata.copy(), tbMsg.dataType, tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } @@ -289,17 +289,17 @@ public final class TbMsg implements Serializable { data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } - public static TbMsg transformMsg(TbMsg tbMsg, CustomerId customerId) { + public static TbMsg transformMsgCustomerId(TbMsg tbMsg, CustomerId customerId) { return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } - public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId) { + public static TbMsg transformMsgRuleChainId(TbMsg tbMsg, RuleChainId ruleChainId) { return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback()); } - public static TbMsg transformMsg(TbMsg tbMsg, String queueName) { + public static TbMsg transformMsgQueueName(TbMsg tbMsg, String queueName) { return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ctx.copy(), tbMsg.getCallback()); } @@ -467,4 +467,18 @@ public final class TbMsg implements Serializable { } return ts; } + + public boolean checkType(TbMsgType tbMsgType) { + return tbMsgType != null && tbMsgType.name().equals(this.type); + } + + public boolean checkTypeOneOf(TbMsgType... types) { + for (TbMsgType type : types) { + if (checkType(type)) { + return true; + } + } + return false; + } + } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java b/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java new file mode 100644 index 0000000000..ca7c94e9ce --- /dev/null +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java @@ -0,0 +1,54 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.msg.session; + +/** + * @deprecated This enum is deprecated and will be removed in a future version. + * Note: This enum was originally part of the public API but is now specific to CoAP transport only. + * Please use {@link org.thingsboard.server.transport.coap.CoapSessionMsgType} instead. + */ +@Deprecated(since="3.5.2", forRemoval = true) +public enum SessionMsgType { + GET_ATTRIBUTES_REQUEST(true), POST_ATTRIBUTES_REQUEST(true), GET_ATTRIBUTES_RESPONSE, + SUBSCRIBE_ATTRIBUTES_REQUEST, UNSUBSCRIBE_ATTRIBUTES_REQUEST, ATTRIBUTES_UPDATE_NOTIFICATION, + + POST_TELEMETRY_REQUEST(true), STATUS_CODE_RESPONSE, + + SUBSCRIBE_RPC_COMMANDS_REQUEST, UNSUBSCRIBE_RPC_COMMANDS_REQUEST, + TO_DEVICE_RPC_REQUEST, TO_DEVICE_RPC_RESPONSE, TO_DEVICE_RPC_RESPONSE_ACK, + + TO_SERVER_RPC_REQUEST(true), TO_SERVER_RPC_RESPONSE, + + RULE_ENGINE_ERROR, + + SESSION_OPEN, SESSION_CLOSE, + + CLAIM_REQUEST(); + + private final boolean requiresRulesProcessing; + + SessionMsgType() { + this(false); + } + + SessionMsgType(boolean requiresRulesProcessing) { + this.requiresRulesProcessing = requiresRulesProcessing; + } + + public boolean requiresRulesProcessing() { + return requiresRulesProcessing; + } +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java index 18317481bd..57871c91ff 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java @@ -24,10 +24,10 @@ import org.thingsboard.rule.engine.api.ScriptEngine; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; -import org.thingsboard.server.common.data.msg.TbMsgType; -import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.script.ScriptLanguage; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -79,7 +79,7 @@ public abstract class TbAbstractAlarmNode> entityViewsFuture = @@ -94,7 +91,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { long startTime = entityView.getStartTimeMs(); long endTime = entityView.getEndTimeMs(); if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) { - if (ATTRIBUTES_DELETED.name().equals(msg.getType())) { + if (msg.checkType(ATTRIBUTES_DELETED)) { List attributes = new ArrayList<>(); for (JsonElement element : JsonParser.parseString(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray()) { if (element.isJsonPrimitive()) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java index 0fd99651a1..e43caf6bb8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java @@ -65,7 +65,7 @@ public class TbMsgCountNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (msg.getType().equals(TbMsgType.MSG_COUNT_SELF_MSG.name()) && msg.getId().equals(nextTickId)) { + if (msg.checkType(TbMsgType.MSG_COUNT_SELF_MSG) && msg.getId().equals(nextTickId)) { JsonObject telemetryJson = new JsonObject(); telemetryJson.addProperty(this.telemetryPrefix + "_" + ctx.getServiceId(), messagesProcessed.longValue()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java index 00d84d3b5f..e24c73f9d3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java @@ -105,13 +105,13 @@ public class TbSnsNode extends TbAbstractExternalNode { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(MESSAGE_ID, result.getMessageId()); metaData.putValue(REQUEST_ID, result.getSdkResponseMetadata().getRequestId()); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } private TbMsg processException(TbContext ctx, TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java index d99827f466..34072fbb8a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java @@ -134,13 +134,13 @@ public class TbSqsNode extends TbAbstractExternalNode { if (!StringUtils.isEmpty(result.getSequenceNumber())) { metaData.putValue(SEQUENCE_NUMBER, result.getSequenceNumber()); } - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java index febb2c1067..cd32a44ea0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java @@ -107,7 +107,7 @@ public class TbMsgGeneratorNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { log.trace("onMsg, config {}, msg {}", config, msg); - if (initialized.get() && msg.getType().equals(TbMsgType.GENERATOR_NODE_SELF_MSG.name()) && msg.getId().equals(nextTickId)) { + if (initialized.get() && msg.checkType(TbMsgType.GENERATOR_NODE_SELF_MSG) && msg.getId().equals(nextTickId)) { TbStopWatch sw = TbStopWatch.create(); withCallback(generate(ctx, msg), m -> { @@ -146,7 +146,7 @@ public class TbMsgGeneratorNode implements TbNode { private ListenableFuture generate(TbContext ctx, TbMsg msg) { log.trace("generate, config {}", config); if (prevMsg == null) { - prevMsg = ctx.newMsg(config.getQueueName(), "", originatorId, msg.getCustomerId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); + prevMsg = ctx.newMsg(config.getQueueName(), TbMsg.EMPTY_STRING, originatorId, msg.getCustomerId(), TbMsgMetaData.EMPTY, TbMsg.EMPTY_JSON_OBJECT); } if (initialized.get()) { ctx.logJsEvalRequest(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java index fae40ff5f5..1c0803770b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java @@ -24,10 +24,10 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.server.common.data.msg.TbMsgType; -import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; @@ -80,7 +80,7 @@ public class TbMsgDeduplicationNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { - if (TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG.name().equals(msg.getType())) { + if (msg.checkType(TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG)) { processDeduplication(ctx, msg.getOriginator()); } else { processOnRegularMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index dabba5970a..d17415c1a6 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -61,7 +61,7 @@ public class TbMsgDelayNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (msg.getType().equals(TbMsgType.DELAY_TIMEOUT_SELF_MSG.name())) { + if (msg.checkType(TbMsgType.DELAY_TIMEOUT_SELF_MSG)) { TbMsg pendingMsg = pendingMsgs.remove(UUID.fromString(msg.getData())); if (pendingMsg != null) { ctx.enqueueForTellNext( diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java index bbec000077..3472ea011b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java @@ -67,7 +67,7 @@ public abstract class AbstractTbMsgPushNode metadata = msg.getMetaData().getData(); - EdgeEventActionType actionType = getEdgeEventActionTypeByMsgType(msgType, metadata); + EdgeEventActionType actionType = getEdgeEventActionTypeByMsgType(msg); Map entityBody = new HashMap<>(); JsonNode dataJson = JacksonUtil.toJsonNode(msg.getData()); switch (actionType) { @@ -158,45 +157,31 @@ public abstract class AbstractTbMsgPushNode metadata) { + protected EdgeEventActionType getEdgeEventActionTypeByMsgType(TbMsg msg) { EdgeEventActionType actionType; - if (POST_TELEMETRY_REQUEST.name().equals(msgType) - || TIMESERIES_UPDATED.name().equals(msgType)) { + if (msg.checkTypeOneOf(POST_TELEMETRY_REQUEST, TIMESERIES_UPDATED)) { actionType = EdgeEventActionType.TIMESERIES_UPDATED; - } else if (ATTRIBUTES_UPDATED.name().equals(msgType)) { + } else if (msg.checkType(ATTRIBUTES_UPDATED)) { actionType = EdgeEventActionType.ATTRIBUTES_UPDATED; - } else if (POST_ATTRIBUTES_REQUEST.name().equals(msgType)) { + } else if (msg.checkType(POST_ATTRIBUTES_REQUEST)) { actionType = EdgeEventActionType.POST_ATTRIBUTES; - } else if (ATTRIBUTES_DELETED.name().equals(msgType)) { + } else if (msg.checkType(ATTRIBUTES_DELETED)) { actionType = EdgeEventActionType.ATTRIBUTES_DELETED; - } else if (CONNECT_EVENT.name().equals(msgType) - || DISCONNECT_EVENT.name().equals(msgType) - || ACTIVITY_EVENT.name().equals(msgType) - || INACTIVITY_EVENT.name().equals(msgType)) { - String scope = metadata.get(SCOPE); - if ( StringUtils.isEmpty(scope)) { - actionType = EdgeEventActionType.TIMESERIES_UPDATED; - } else { - actionType = EdgeEventActionType.ATTRIBUTES_UPDATED; - } + } else if (msg.checkTypeOneOf(CONNECT_EVENT, DISCONNECT_EVENT, ACTIVITY_EVENT, INACTIVITY_EVENT)) { + String scope = msg.getMetaData().getValue(SCOPE); + actionType = StringUtils.isEmpty(scope) ? + EdgeEventActionType.TIMESERIES_UPDATED : EdgeEventActionType.ATTRIBUTES_UPDATED; } else { - log.warn("Unsupported msg type [{}]", msgType); - throw new IllegalArgumentException("Unsupported msg type: " + msgType); + String type = msg.getType(); + log.warn("Unsupported msg type [{}]", type); + throw new IllegalArgumentException("Unsupported msg type: " + type); } return actionType; } - protected boolean isSupportedMsgType(String msgType) { - return POST_TELEMETRY_REQUEST.name().equals(msgType) - || POST_ATTRIBUTES_REQUEST.name().equals(msgType) - || ATTRIBUTES_UPDATED.name().equals(msgType) - || ATTRIBUTES_DELETED.name().equals(msgType) - || TIMESERIES_UPDATED.name().equals(msgType) - || ALARM.name().equals(msgType) - || CONNECT_EVENT.name().equals(msgType) - || DISCONNECT_EVENT.name().equals(msgType) - || ACTIVITY_EVENT.name().equals(msgType) - || INACTIVITY_EVENT.name().equals(msgType); + protected boolean isSupportedMsgType(TbMsg msg) { + return msg.checkTypeOneOf(POST_TELEMETRY_REQUEST, POST_ATTRIBUTES_REQUEST, ATTRIBUTES_UPDATED, + ATTRIBUTES_DELETED, TIMESERIES_UPDATED, ALARM, CONNECT_EVENT, DISCONNECT_EVENT, ACTIVITY_EVENT, INACTIVITY_EVENT); } protected boolean isSupportedOriginator(EntityType entityType) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java index d70dd75040..39c37f5c81 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; configClazz = EmptyNodeConfiguration.class, nodeDescription = "Route incoming messages based on the name of the asset profile", nodeDetails = "Route incoming messages based on the name of the asset profile. The asset profile name is case-sensitive.

" + - "Output connections: Message originator profile name or Failure", + "Output connections: Asset profile name or Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java index 632c1af04f..3af5c9bfe1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java @@ -118,11 +118,11 @@ public class TbCheckRelationNode implements TbVersionedNode { throw new TbNodeException("property to update: '" + DIRECTION_PROPERTY_NAME + "' doesn't exists in configuration!"); } String direction = newConfigObjectNode.get(DIRECTION_PROPERTY_NAME).asText(); - if ("TO".equals(direction)) { + if (EntitySearchDirection.TO.name().equals(direction)) { newConfigObjectNode.put(DIRECTION_PROPERTY_NAME, EntitySearchDirection.FROM.name()); return new TbPair<>(true, newConfigObjectNode); } - if ("FROM".equals(direction)) { + if (EntitySearchDirection.FROM.name().equals(direction)) { newConfigObjectNode.put(DIRECTION_PROPERTY_NAME, EntitySearchDirection.TO.name()); return new TbPair<>(true, newConfigObjectNode); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java index 7765a4089d..b146a9be44 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; configClazz = EmptyNodeConfiguration.class, nodeDescription = "Route incoming messages based on the name of the device profile", nodeDetails = "Route incoming messages based on the name of the device profile. The device profile name is case-sensitive

" + - "Output connections: Message originator profile name or Failure", + "Output connections: Device profile name or Failure", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java index e7dacbab4e..c55113783c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java @@ -119,13 +119,13 @@ public class TbPubSubNode extends TbAbstractExternalNode { private TbMsg processPublishResult(TbMsg origMsg, String messageId) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(MESSAGE_ID, messageId); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } private Publisher initPubSubClient() throws IOException { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java index 456aac4de1..68094196d0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java @@ -176,13 +176,13 @@ public class TbKafkaNode extends TbAbstractExternalNode { metaData.putValue(OFFSET, String.valueOf(recordMetadata.offset())); metaData.putValue(PARTITION, String.valueOf(recordMetadata.partition())); metaData.putValue(TOPIC, recordMetadata.topic()); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } private TbMsg processException(TbMsg origMsg, Exception e) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage()); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java index 78b7b23d5b..6319145637 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java @@ -70,7 +70,7 @@ public class TbSendEmailNode extends TbAbstractExternalNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { try { - validateType(msg.getType()); + validateType(msg); TbEmail email = getEmail(msg); var tbMsg = ackIfNeeded(ctx, msg); withCallback(ctx.getMailExecutor().executeAsync(() -> { @@ -100,8 +100,9 @@ public class TbSendEmailNode extends TbAbstractExternalNode { return email; } - private void validateType(String type) { - if (!TbMsgType.SEND_EMAIL.name().equals(type)) { + private void validateType(TbMsg msg) { + if (!msg.checkType(TbMsgType.SEND_EMAIL)) { + String type = msg.getType(); log.warn("Not expected msg type [{}] for SendEmail Node", type); throw new IllegalStateException("Not expected msg type " + type + " for SendEmail Node"); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java index 33692decc2..fe6deebbcf 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java @@ -248,7 +248,7 @@ public class TbMathNode implements TbNode { } else { md.putValue(mathResultKey, Double.toString(toDoubleValue(mathResultDef, result))); } - return TbMsg.transformMsg(msg, md); + return TbMsg.transformMsgMetadata(msg, md); } private double calculateResult(List args) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java index 3e4e6eb93f..13fe3fae69 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java @@ -25,12 +25,12 @@ import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; -import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.dao.timeseries.TimeseriesService; @@ -75,7 +75,7 @@ public class CalculateDeltaNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (!msg.getType().equals(TbMsgType.POST_TELEMETRY_REQUEST.name())) { + if (!msg.checkType(TbMsgType.POST_TELEMETRY_REQUEST)) { ctx.tellNext(msg, TbNodeConnectionType.OTHER); return; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java index 2370bfde29..89e48b5f11 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractNodeWithFetchTo.java @@ -83,7 +83,7 @@ public abstract class TbAbstractNodeWithFetchTo> list = ctx.getTimeseriesService().findAll(ctx.getTenantId(), msg.getOriginator(), buildQueries(interval, keys)); DonAsynchron.withCallback(list, data -> { var metaData = updateMetadata(data, msg, keys); - ctx.tellSuccess(TbMsg.transformMsg(msg, metaData)); + ctx.tellSuccess(TbMsg.transformMsgMetadata(msg, metaData)); }, error -> ctx.tellFailure(msg, error), ctx.getDbCallbackExecutor()); } catch (Exception e) { ctx.tellFailure(msg, e); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index d166f86008..23d2132a1b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -95,7 +95,7 @@ public class TbMqttNode extends TbAbstractExternalNode { private TbMsg processException(TbMsg origMsg, Throwable e) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, e.getClass() + ": " + e.getMessage()); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java index f1fd9727fa..5f1bea2bdb 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/notification/TbNotificationNode.java @@ -19,7 +19,6 @@ import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; @@ -77,7 +76,7 @@ public class TbNotificationNode extends TbAbstractExternalNode { ctx.getNotificationCenter().processNotificationRequest(ctx.getTenantId(), notificationRequest, stats -> { TbMsgMetaData metaData = tbMsg.getMetaData().copy(); metaData.putValue("notificationRequestResult", JacksonUtil.toString(stats)); - tellSuccess(ctx, TbMsg.transformMsg(tbMsg, metaData)); + tellSuccess(ctx, TbMsg.transformMsgMetadata(tbMsg, metaData)); })), r -> { }, diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java index 8cccc51258..7e0b0bc77c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java @@ -36,7 +36,6 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.query.EntityKey; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.rule.RuleNodeState; @@ -55,6 +54,18 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; +import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_ACK; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_CLEAR; +import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_DELETED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ATTRIBUTES_UPDATED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED; +import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_UNASSIGNED; +import static org.thingsboard.server.common.data.msg.TbMsgType.INACTIVITY_EVENT; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_ATTRIBUTES_REQUEST; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; + @Slf4j class DeviceState { @@ -136,24 +147,24 @@ class DeviceState { latestValues = fetchLatestValues(ctx, deviceId); } boolean stateChanged = false; - if (msg.getType().equals(TbMsgType.POST_TELEMETRY_REQUEST.name())) { + if (msg.checkType(POST_TELEMETRY_REQUEST)) { stateChanged = processTelemetry(ctx, msg); - } else if (msg.getType().equals(TbMsgType.POST_ATTRIBUTES_REQUEST.name())) { + } else if (msg.checkType(POST_ATTRIBUTES_REQUEST)) { stateChanged = processAttributesUpdateRequest(ctx, msg); - } else if (msg.getType().equals(TbMsgType.ACTIVITY_EVENT.name()) || msg.getType().equals(TbMsgType.INACTIVITY_EVENT.name())) { + } else if (msg.checkTypeOneOf(ACTIVITY_EVENT, INACTIVITY_EVENT)) { stateChanged = processDeviceActivityEvent(ctx, msg); - } else if (msg.getType().equals(TbMsgType.ATTRIBUTES_UPDATED.name())) { + } else if (msg.checkType(ATTRIBUTES_UPDATED)) { stateChanged = processAttributesUpdateNotification(ctx, msg); - } else if (msg.getType().equals(TbMsgType.ATTRIBUTES_DELETED.name())) { + } else if (msg.checkType(ATTRIBUTES_DELETED)) { stateChanged = processAttributesDeleteNotification(ctx, msg); - } else if (msg.getType().equals(TbMsgType.ALARM_CLEAR.name())) { + } else if (msg.checkType(ALARM_CLEAR)) { stateChanged = processAlarmClearNotification(ctx, msg); - } else if (msg.getType().equals(TbMsgType.ALARM_ACK.name())) { + } else if (msg.checkType(ALARM_ACK)) { processAlarmAckNotification(ctx, msg); - } else if (msg.getType().equals(TbMsgType.ALARM_DELETE.name())) { + } else if (msg.checkType(ALARM_DELETE)) { processAlarmDeleteNotification(ctx, msg); } else { - if (msg.getType().equals(TbMsgType.ENTITY_ASSIGNED.name()) || msg.getType().equals(TbMsgType.ENTITY_UNASSIGNED.name())) { + if (msg.checkTypeOneOf(ENTITY_ASSIGNED, ENTITY_UNASSIGNED)) { dynamicPredicateValueCtx.resetCustomer(); } ctx.tellSuccess(msg); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index 2de73b6f38..058a70fdea 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -108,16 +108,16 @@ public class TbDeviceProfileNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException { EntityType originatorType = msg.getOriginator().getEntityType(); - if (msg.getType().equals(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG.name())) { + if (msg.checkType(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG)) { scheduleAlarmHarvesting(ctx, msg); harvestAlarms(ctx, System.currentTimeMillis()); return; } - if (msg.getType().equals(TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG.name())) { + if (msg.checkType(TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG)) { updateProfile(ctx, new DeviceProfileId(UUID.fromString(msg.getData()))); return; } - if (msg.getType().equals(TbMsgType.DEVICE_UPDATE_SELF_MSG.name())) { + if (msg.checkType(TbMsgType.DEVICE_UPDATE_SELF_MSG)) { JsonNode data = JacksonUtil.toJsonNode(msg.getData()); DeviceId deviceId = new DeviceId(UUID.fromString(data.get("deviceId").asText())); if (data.has("profileId")) { @@ -129,12 +129,12 @@ public class TbDeviceProfileNode implements TbNode { } if (EntityType.DEVICE.equals(originatorType)) { DeviceId deviceId = new DeviceId(msg.getOriginator().getId()); - if (msg.getType().equals(TbMsgType.ENTITY_UPDATED.name())) { + if (msg.checkType(TbMsgType.ENTITY_UPDATED)) { invalidateDeviceProfileCache(deviceId, msg.getData()); ctx.tellSuccess(msg); return; } - if (msg.getType().equals(TbMsgType.ENTITY_DELETED.name())) { + if (msg.checkType(TbMsgType.ENTITY_DELETED)) { removeDeviceState(deviceId); ctx.tellSuccess(msg); return; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java index e83fefa513..be7a22f713 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java @@ -118,7 +118,7 @@ public class TbRabbitMqNode extends TbAbstractExternalNode { private TbMsg processException(TbMsg origMsg, Throwable t) { TbMsgMetaData metaData = origMsg.getMetaData().copy(); metaData.putValue(ERROR, t.getClass() + ": " + t.getMessage()); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 70a22a692e..0c9eca5f0a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -286,7 +286,7 @@ public class TbHttpClient { metaData.putValue(STATUS_REASON, response.getStatusCode().getReasonPhrase()); metaData.putValue(ERROR_BODY, response.getBody()); headersToMetaData(response.getHeaders(), metaData::putValue); - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } private TbMsg processException(TbMsg origMsg, Throwable e) { @@ -298,7 +298,7 @@ public class TbHttpClient { metaData.putValue(STATUS_CODE, restClientResponseException.getRawStatusCode() + ""); metaData.putValue(ERROR_BODY, restClientResponseException.getResponseBodyAsString()); } - return TbMsg.transformMsg(origMsg, metaData); + return TbMsg.transformMsgMetadata(origMsg, metaData); } private HttpHeaders prepareHeaders(TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java index 26d22b5ef2..5859cb6f48 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java @@ -27,13 +27,13 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.msg.TbNodeConnectionType; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -76,7 +76,7 @@ public class TbSendRPCRequestNode implements TbNode { ctx.tellFailure(msg, new RuntimeException("Params are not present in the message!")); } else { int requestId = json.has("requestId") ? json.get("requestId").getAsInt() : random.nextInt(); - boolean restApiCall = msg.getType().equals(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE.name()); + boolean restApiCall = msg.checkType(TbMsgType.RPC_CALL_FROM_SERVER_TO_DEVICE); tmp = msg.getMetaData().getValue("oneway"); boolean oneway = !StringUtils.isEmpty(tmp) && Boolean.parseBoolean(tmp); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java index 5ddb1c701f..c7aa99c115 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java @@ -65,7 +65,7 @@ public class TbMsgAttributesNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (!msg.getType().equals(POST_ATTRIBUTES_REQUEST.name())) { + if (!msg.checkType(POST_ATTRIBUTES_REQUEST)) { ctx.tellFailure(msg, new IllegalArgumentException("Unsupported msg type: " + msg.getType())); return; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java index 4118d28c22..852b74f64f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java @@ -82,7 +82,7 @@ public class TbMsgTimeseriesNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (!msg.getType().equals(POST_TELEMETRY_REQUEST.name())) { + if (!msg.checkType(POST_TELEMETRY_REQUEST)) { ctx.tellFailure(msg, new IllegalArgumentException("Unsupported msg type: " + msg.getType())); return; } From b95eae215a34fd5a900c5120416ebc3210938745 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 27 Jul 2023 15:26:40 +0300 Subject: [PATCH 324/421] replaced handling of AssetProfile and DeviceProfile with HasRuleEngineProfile to match PE code version --- .../queue/DefaultTbClusterService.java | 66 ++++++++----------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 9154c32701..63eaab23f2 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -32,10 +32,10 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasName; +import org.thingsboard.server.common.data.HasRuleEngineProfile; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; -import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.id.AssetId; @@ -178,15 +178,8 @@ public class DefaultTbClusterService implements TbClusterService { return; } } else { - if (entityId.getEntityType().equals(EntityType.DEVICE)) { - tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceId(entityId.getId()))); - } else if (entityId.getEntityType().equals(EntityType.DEVICE_PROFILE)) { - tbMsg = transformMsg(tbMsg, deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId()))); - } else if (entityId.getEntityType().equals(EntityType.ASSET)) { - tbMsg = transformMsg(tbMsg, assetProfileCache.get(tenantId, new AssetId(entityId.getId()))); - } else if (entityId.getEntityType().equals(EntityType.ASSET_PROFILE)) { - tbMsg = transformMsg(tbMsg, assetProfileCache.get(tenantId, new AssetProfileId(entityId.getId()))); - } + HasRuleEngineProfile ruleEngineProfile = getRuleEngineProfileForEntityOrElseNull(tenantId, entityId); + tbMsg = transformMsg(tbMsg, ruleEngineProfile); } TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, tbMsg.getQueueName(), tenantId, entityId); log.trace("PUSHING msg: {} to:{}", tbMsg, tpi); @@ -198,34 +191,33 @@ public class DefaultTbClusterService implements TbClusterService { toRuleEngineMsgs.incrementAndGet(); } - private TbMsg transformMsg(TbMsg tbMsg, DeviceProfile deviceProfile) { - if (deviceProfile != null) { - RuleChainId targetRuleChainId = deviceProfile.getDefaultRuleChainId(); - String targetQueueName = deviceProfile.getDefaultQueueName(); - tbMsg = transformMsg(tbMsg, targetRuleChainId, targetQueueName); - } - return tbMsg; - } - - private TbMsg transformMsg(TbMsg tbMsg, AssetProfile assetProfile) { - if (assetProfile != null) { - RuleChainId targetRuleChainId = assetProfile.getDefaultRuleChainId(); - String targetQueueName = assetProfile.getDefaultQueueName(); - tbMsg = transformMsg(tbMsg, targetRuleChainId, targetQueueName); + private HasRuleEngineProfile getRuleEngineProfileForEntityOrElseNull(TenantId tenantId, EntityId entityId) { + if (entityId.getEntityType().equals(EntityType.DEVICE)) { + return deviceProfileCache.get(tenantId, new DeviceId(entityId.getId())); + } else if (entityId.getEntityType().equals(EntityType.DEVICE_PROFILE)) { + return deviceProfileCache.get(tenantId, new DeviceProfileId(entityId.getId())); + } else if (entityId.getEntityType().equals(EntityType.ASSET)) { + return assetProfileCache.get(tenantId, new AssetId(entityId.getId())); + } else if (entityId.getEntityType().equals(EntityType.ASSET_PROFILE)) { + return assetProfileCache.get(tenantId, new AssetProfileId(entityId.getId())); } - return tbMsg; - } - - private TbMsg transformMsg(TbMsg tbMsg, RuleChainId targetRuleChainId, String targetQueueName) { - boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId()); - boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName()); - - if (isRuleChainTransform && isQueueTransform) { - tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName); - } else if (isRuleChainTransform) { - tbMsg = TbMsg.transformMsgRuleChainId(tbMsg, targetRuleChainId); - } else if (isQueueTransform) { - tbMsg = TbMsg.transformMsgQueueName(tbMsg, targetQueueName); + return null; + } + private TbMsg transformMsg(TbMsg tbMsg, HasRuleEngineProfile ruleEngineProfile) { + if (ruleEngineProfile != null) { + RuleChainId targetRuleChainId = ruleEngineProfile.getDefaultRuleChainId(); + String targetQueueName = ruleEngineProfile.getDefaultQueueName(); + + boolean isRuleChainTransform = targetRuleChainId != null && !targetRuleChainId.equals(tbMsg.getRuleChainId()); + boolean isQueueTransform = targetQueueName != null && !targetQueueName.equals(tbMsg.getQueueName()); + + if (isRuleChainTransform && isQueueTransform) { + tbMsg = TbMsg.transformMsg(tbMsg, targetRuleChainId, targetQueueName); + } else if (isRuleChainTransform) { + tbMsg = TbMsg.transformMsgRuleChainId(tbMsg, targetRuleChainId); + } else if (isQueueTransform) { + tbMsg = TbMsg.transformMsgQueueName(tbMsg, targetQueueName); + } } return tbMsg; } From b69f63660b5e8a9e1b8c1a0e90d35d9a9253fe41 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 27 Jul 2023 16:59:26 +0300 Subject: [PATCH 325/421] UI: Device connectivity change coap install instruction and added support spartplug --- ...e-check-connectivity-dialog.component.html | 168 ++++++++++-------- ...e-check-connectivity-dialog.component.scss | 5 +- ...ice-check-connectivity-dialog.component.ts | 42 +---- ui-ngx/src/app/shared/models/device.models.ts | 1 + .../assets/locale/locale.constant-en_US.json | 2 + 5 files changed, 100 insertions(+), 118 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html index 0f9c6dc055..71a8364134 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.html @@ -73,7 +73,7 @@
device.connectivity.install-necessary-client-tools
-
device.connectivity.install-curl-windows
+
device.connectivity.install-curl-windows
-
device.connectivity.use-following-instructions
- - - - - Windows - - -
-
-
device.connectivity.install-necessary-client-tools
-
- + + +
+ +
device.connectivity.use-following-instructions
+ + + + + Windows + + +
+
+
device.connectivity.install-necessary-client-tools
+
+ - + +
-
- - -
- - - - - - MacOS - - -
-
-
device.connectivity.install-necessary-client-tools
- +
- + MacOS + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ - -
-
- - - - - Linux - - -
-
-
device.connectivity.install-necessary-client-tools
- +
- + Linux + + +
+
+
device.connectivity.install-necessary-client-tools
+ +
+ - -
-
- - - - - Docker - - -
- + + + Docker + + +
+ - -
-
- - +
+
+
+
+ +
device.connectivity.use-following-instructions
@@ -226,10 +234,14 @@
-
+
device.connectivity.install-necessary-client-tools
- +
+ + +
-
+
device.connectivity.install-necessary-client-tools
- +
+ + +
Date: Thu, 27 Jul 2023 17:18:39 +0300 Subject: [PATCH 326/421] UI: Implement Value card widget settings. Improve widget container layout. --- .../json/system/widget_bundles/cards.json | 16 +- .../core/services/dashboard-utils.service.ts | 6 +- .../add-widget-dialog.component.scss | 4 +- .../dashboard-page.component.ts | 1 + .../dashboard-widget-select.component.scss | 2 + .../value-card-basic-config.component.html | 46 ++-- .../value-card-basic-config.component.ts | 10 + .../basic/common/data-key-row.component.html | 6 +- .../basic/common/data-key-row.component.scss | 13 +- .../common/data-keys-panel.component.html | 4 +- .../common/data-keys-panel.component.scss | 12 +- .../widget/config/data-keys.component.html | 2 +- .../widget/config/data-keys.component.scss | 8 +- .../config/widget-settings.component.ts | 10 + .../widget/config/widget-settings.models.ts | 20 +- .../value-card-widget-settings.component.html | 89 ++++++++ .../value-card-widget-settings.component.ts | 200 ++++++++++++++++++ .../background-settings-panel.component.html | 87 ++++++++ .../background-settings-panel.component.scss | 73 +++++++ .../background-settings-panel.component.ts | 120 +++++++++++ .../common/background-settings.component.html | 30 +++ .../common/background-settings.component.scss | 41 ++++ .../common/background-settings.component.ts | 120 +++++++++++ .../common/image-cards-select.component.ts | 27 ++- .../lib/settings/widget-settings.module.ts | 20 +- .../widget/widget-component.service.ts | 3 + .../widget/widget-config.component.html | 1 + .../widget/widget-container.component.html | 17 +- .../widget/widget-container.component.scss | 47 ++-- .../components/widget/widget.component.ts | 1 + .../home/models/widget-component.models.ts | 2 + .../components/unit-input.component.html | 2 +- .../shared/components/unit-input.component.ts | 19 +- ui-ngx/src/app/shared/models/unit.models.ts | 6 + ui-ngx/src/app/shared/models/widget.models.ts | 18 +- .../assets/locale/locale.constant-en_US.json | 16 +- .../src/assets/{model => metadata}/units.json | 0 ui-ngx/src/styles.scss | 25 +-- 38 files changed, 1020 insertions(+), 104 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts rename ui-ngx/src/assets/{model => metadata}/units.json (100%) diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index cc2c74c359..1289923667 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -229,19 +229,19 @@ { "alias": "value_card", "name": "Value card", - "image": null, + "image": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyNyIgZmlsbD0ibm9uZSIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgMTI4IDEyNyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2RfMTE0Ml8yMDM5NTQpIj4KICA8cmVjdCB4PSI1LjUiIHk9IjIuNSIgd2lkdGg9IjExNyIgaGVpZ2h0PSIxMTciIHJ4PSIyLjI5NDEiIGZpbGw9IiNmZmYiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPgogIDxwYXRoIGQ9Im0zMy42MDMgMjkuMjIxdi03LjY0NzFjMC0xLjU4NjgtMS4yODA4LTIuODY3Ni0yLjg2NzYtMi44Njc2cy0yLjg2NzcgMS4yODA4LTIuODY3NyAyLjg2NzZ2Ny42NDcxYy0xLjE1NjYgMC44Njk4LTEuOTExNyAyLjI2NTQtMS45MTE3IDMuODIzNSAwIDIuNjM4MiAyLjE0MTIgNC43Nzk0IDQuNzc5NCA0Ljc3OTRzNC43Nzk0LTIuMTQxMiA0Ljc3OTQtNC43Nzk0YzAtMS41NTgxLTAuNzU1MS0yLjk1MzctMS45MTE4LTMuODIzNXptLTMuODIzNS03LjY0NzFjMC0wLjUyNTcgMC40MzAyLTAuOTU1OSAwLjk1NTktMC45NTU5czAuOTU1OSAwLjQzMDIgMC45NTU5IDAuOTU1OWgtMC45NTU5djAuOTU1OWgwLjk1NTl2MS45MTE3aC0wLjk1NTl2MC45NTU5aDAuOTU1OXYxLjkxMThoLTEuOTExOHYtNS43MzUzeiIgZmlsbD0iIzU0NjlGRiIvPgogIDxnIGZpbGw9IiMwMDAiPgogICA8cGF0aCBkPSJtNTAuMTQxIDE5Ljc0MXY2LjUyMzhoLTEuMTE1N3YtNi41MjM4aDEuMTE1N3ptMi4wNDc3IDB2MC44OTYxaC01LjE5MzJ2LTAuODk2MWg1LjE5MzJ6bTIuNjAzMyA2LjYxMzVjLTAuMzU4NSAwLTAuNjgyNi0wLjA1ODMtMC45NzIzLTAuMTc0OC0wLjI4NjgtMC4xMTk1LTAuNTMxOC0wLjI4NTMtMC43MzQ5LTAuNDk3My0wLjIwMDEtMC4yMTIxLTAuMzU0LTAuNDYxNi0wLjQ2MTUtMC43NDgzLTAuMTA3NS0wLjI4NjgtMC4xNjEzLTAuNTk2LTAuMTYxMy0wLjkyNzV2LTAuMTc5M2MwLTAuMzc5MyAwLjA1NTMtMC43MjI4IDAuMTY1OC0xLjAzMDVzMC4yNjQzLTAuNTcwNiAwLjQ2MTUtMC43ODg2YzAuMTk3MS0wLjIyMTEgMC40MzAxLTAuMzg5OCAwLjY5OS0wLjUwNjMgMC4yNjg4LTAuMTE2NSAwLjU2MDEtMC4xNzQ4IDAuODczNy0wLjE3NDggMC4zNDY1IDAgMC42NDk3IDAuMDU4MyAwLjkwOTYgMC4xNzQ4czAuNDc1IDAuMjgwOCAwLjY0NTIgMC40OTI4YzAuMTczMyAwLjIwOTEgMC4zMDE3IDAuNDU4NiAwLjM4NTQgMC43NDgzIDAuMDg2NiAwLjI4OTggMC4xMjk5IDAuNjA5NCAwLjEyOTkgMC45NTg5djAuNDYxNWgtMy43NDU5di0wLjc3NTJoMi42Nzk1di0wLjA4NTFjLTZlLTMgLTAuMTk0Mi0wLjA0NDgtMC4zNzY0LTAuMTE2NS0wLjU0NjYtMC4wNjg3LTAuMTcwMy0wLjE3NDctMC4zMDc3LTAuMzE4MS0wLjQxMjMtMC4xNDM0LTAuMTA0NS0wLjMzNDYtMC4xNTY4LTAuNTczNi0wLjE1NjgtMC4xNzkyIDAtMC4zMzkgMC4wMzg4LTAuNDc5NCAwLjExNjUtMC4xMzc0IDAuMDc0Ny0wLjI1MjQgMC4xODM3LTAuMzQ1IDAuMzI3MXMtMC4xNjQzIDAuMzE2Ni0wLjIxNTEgMC41MTk4Yy0wLjA0NzggMC4yMDAxLTAuMDcxNyAwLjQyNTYtMC4wNzE3IDAuNjc2NXYwLjE3OTNjMCAwLjIxMjEgMC4wMjg0IDAuNDA5MiAwLjA4NTIgMC41OTE0IDAuMDU5NyAwLjE3OTMgMC4xNDYzIDAuMzM2MSAwLjI1OTggMC40NzA1IDAuMTEzNiAwLjEzNDQgMC4yNTEgMC4yNDA1IDAuNDEyMyAwLjMxODEgMC4xNjEzIDAuMDc0NyAwLjM0NSAwLjExMiAwLjU1MTEgMC4xMTIgMC4yNTk5IDAgMC40OTE0LTAuMDUyMiAwLjY5NDUtMC4xNTY4IDAuMjAzMS0wLjEwNDUgMC4zNzk0LTAuMjUyNCAwLjUyODctMC40NDM2bDAuNTY5MSAwLjU1MTJjLTAuMTA0NiAwLjE1MjMtMC4yNDA1IDAuMjk4Ny0wLjQwNzggMC40MzkxLTAuMTY3MyAwLjEzNzQtMC4zNzE5IDAuMjQ5NC0wLjYxMzggMC4zMzYtMC4yMzkgMC4wODY2LTAuNTE2OCAwLjEzLTAuODMzNCAwLjEzem00LjAwNTctMy45NTJ2My44NjIzaC0xLjA3OTh2LTQuODQ4MWgxLjAxNzFsMC4wNjI3IDAuOTg1OHptLTAuMTc0NyAxLjI1OTEtMC4zNjc1LTAuMDA0NWMwLTAuMzM0NiAwLjA0MTktMC42NDM3IDAuMTI1NS0wLjkyNzVzMC4yMDYxLTAuNTMwMiAwLjM2NzQtMC43MzkzYzAuMTYxMy0wLjIxMjEgMC4zNjE1LTAuMzc0OSAwLjYwMDQtMC40ODg0IDAuMjQyLTAuMTE2NSAwLjUyMTMtMC4xNzQ4IDAuODM3OS0wLjE3NDggMC4yMjExIDAgMC40MjI3IDAuMDMyOSAwLjYwNDkgMC4wOTg2IDAuMTg1MiAwLjA2MjcgMC4zNDUgMC4xNjI4IDAuNDc5NSAwLjMwMDIgMC4xMzc0IDAuMTM3NCAwLjI0MTkgMC4zMTM2IDAuMzEzNiAwLjUyODcgMC4wNzQ3IDAuMjE1MSAwLjExMiAwLjQ3NSAwLjExMiAwLjc3OTd2My4yMzA1aC0xLjA3OTh2LTMuMTM2NGMwLTAuMjM2LTAuMDM1OS0wLjQyMTItMC4xMDc2LTAuNTU1Ni0wLjA2ODctMC4xMzQ1LTAuMTY4Ny0wLjIzMDEtMC4zMDAyLTAuMjg2OC0wLjEyODQtMC4wNTk4LTAuMjgyMy0wLjA4OTYtMC40NjE1LTAuMDg5Ni0wLjIwMzEgMC0wLjM3NjQgMC4wMzg4LTAuNTE5NyAwLjExNjUtMC4xNDA0IDAuMDc3Ni0wLjI1NTQgMC4xODM3LTAuMzQ1MSAwLjMxODEtMC4wODk2IDAuMTM0NC0wLjE1NTMgMC4yODk4LTAuMTk3MSAwLjQ2NnMtMC4wNjI3IDAuMzY0NC0wLjA2MjcgMC41NjQ2em0zLjAwNjUtMC4yODY4LTAuNTA2MyAwLjExMmMwLTAuMjkyNyAwLjA0MDMtMC41NjkgMC4xMjEtMC44Mjg5IDAuMDgzNi0wLjI2MjkgMC4yMDQ2LTAuNDkyOSAwLjM2MjktMC42OSAwLjE2MTMtMC4yMDAyIDAuMzYtMC4zNTcgMC41OTU5LTAuNDcwNSAwLjIzNi0wLjExMzUgMC41MDY0LTAuMTcwMyAwLjgxMS0wLjE3MDMgMC4yNDggMCAwLjQ2OSAwLjAzNDQgMC42NjMyIDAuMTAzMSAwLjE5NzEgMC4wNjU3IDAuMzY0NCAwLjE3MDIgMC41MDE4IDAuMzEzNnMwLjI0MiAwLjMzMDEgMC4zMTM3IDAuNTYwMWMwLjA3MTcgMC4yMjcgMC4xMDc1IDAuNTAxOCAwLjEwNzUgMC44MjQ1djMuMTM2NGgtMS4wODQzdi0zLjE0MDljMC0wLjI0NS0wLjAzNTktMC40MzQ2LTAuMTA3Ni0wLjU2OTEtMC4wNjg3LTAuMTM0NC0wLjE2NzItMC4yMjctMC4yOTU3LTAuMjc3OC0wLjEyODQtMC4wNTM3LTAuMjgyMy0wLjA4MDYtMC40NjE1LTAuMDgwNi0wLjE2NzMgMC0wLjMxNTEgMC4wMzEzLTAuNDQzNiAwLjA5NDEtMC4xMjU0IDAuMDU5Ny0wLjIzMTUgMC4xNDQ4LTAuMzE4MSAwLjI1NTQtMC4wODY2IDAuMTA3NS0wLjE1MjQgMC4yMzE1LTAuMTk3MiAwLjM3MTktMC4wNDE4IDAuMTQwNC0wLjA2MjcgMC4yOTI3LTAuMDYyNyAwLjQ1N3ptNS4zMDk2LTEuMDI2MXY1Ljc4MDFoLTEuMDc5OHYtNi43MTIxaDAuOTk0N2wwLjA4NTEgMC45MzJ6bTMuMTU4OSAxLjQ0NzN2MC4wOTQxYzAgMC4zNTI1LTAuMDQxOCAwLjY3OTYtMC4xMjU0IDAuOTgxMy0wLjA4MDcgMC4yOTg3LTAuMjAxNyAwLjU2LTAuMzYzIDAuNzg0MS0wLjE1ODMgMC4yMjEtMC4zNTM5IDAuMzkyOC0wLjU4NjkgMC41MTUzLTAuMjMzIDAuMTIyNC0wLjUwMTkgMC4xODM3LTAuODA2NiAwLjE4MzctMC4zMDE3IDAtMC41NjYtMC4wNTUzLTAuNzkzLTAuMTY1OC0wLjIyNDEtMC4xMTM1LTAuNDEzOC0wLjI3MzMtMC41NjkxLTAuNDc5NS0wLjE1NTMtMC4yMDYxLTAuMjgwOC0wLjQ0OC0wLjM3NjQtMC43MjU4LTAuMDkyNi0wLjI4MDgtMC4xNTgzLTAuNTg4NS0wLjE5NzEtMC45MjMxdi0wLjM2MjljMC4wMzg4LTAuMzU1NSAwLjEwNDUtMC42NzgxIDAuMTk3MS0wLjk2NzggMC4wOTU2LTAuMjg5OCAwLjIyMTEtMC41MzkyIDAuMzc2NC0wLjc0ODNzMC4zNDUtMC4zNzA0IDAuNTY5MS0wLjQ4MzljMC4yMjQtMC4xMTM1IDAuNDg1NC0wLjE3MDMgMC43ODQxLTAuMTcwMyAwLjMwNDcgMCAwLjU3NSAwLjA1OTggMC44MTEgMC4xNzkyIDAuMjM2IDAuMTE2NSAwLjQzNDYgMC4yODM4IDAuNTk1OSAwLjUwMTkgMC4xNjEzIDAuMjE1MSAwLjI4MjMgMC40NzQ5IDAuMzYyOSAwLjc3OTYgMC4wODA3IDAuMzAxNyAwLjEyMSAwLjYzNzggMC4xMjEgMS4wMDgyem0tMS4wNzk4IDAuMDk0MXYtMC4wOTQxYzAtMC4yMjQxLTAuMDIwOS0wLjQzMTctMC4wNjI3LTAuNjIyOC0wLjA0MTktMC4xOTQyLTAuMTA3Ni0wLjM2NDUtMC4xOTcyLTAuNTEwOC0wLjA4OTYtMC4xNDY0LTAuMjA0Ni0wLjI1OTktMC4zNDUtMC4zNDA2LTAuMTM3NC0wLjA4MzYtMC4zMDMyLTAuMTI1NC0wLjQ5NzQtMC4xMjU0LTAuMTkxMSAwLTAuMzU1NCAwLjAzMjgtMC40OTI4IDAuMDk4NS0wLjEzNzUgMC4wNjI4LTAuMjUyNSAwLjE1MDktMC4zNDUxIDAuMjY0NHMtMC4xNjQzIDAuMjQ2NC0wLjIxNSAwLjM5ODhjLTAuMDUwOCAwLjE0OTMtMC4wODY3IDAuMzEyMS0wLjEwNzYgMC40ODg0djAuODY5MmMwLjAzNTkgMC4yMTUxIDAuMDk3MSAwLjQxMjMgMC4xODM3IDAuNTkxNSAwLjA4NjcgMC4xNzkyIDAuMjA5MSAwLjMyMjYgMC4zNjc1IDAuNDMwMSAwLjE2MTMgMC4xMDQ2IDAuMzY3NCAwLjE1NjkgMC42MTgzIDAuMTU2OSAwLjE5NDIgMCAwLjM1OTktMC4wNDE5IDAuNDk3My0wLjEyNTUgMC4xMzc1LTAuMDgzNiAwLjI0OTUtMC4xOTg2IDAuMzM2MS0wLjM0NSAwLjA4OTYtMC4xNDk0IDAuMTU1My0wLjMyMTEgMC4xOTcyLTAuNTE1MyAwLjA0MTgtMC4xOTQxIDAuMDYyNy0wLjQwMDMgMC4wNjI3LTAuNjE4M3ptNC4yNzkgMi40NjQ0Yy0wLjM1ODQgMC0wLjY4MjUtMC4wNTgzLTAuOTcyMy0wLjE3NDgtMC4yODY3LTAuMTE5NS0wLjUzMTctMC4yODUzLTAuNzM0OC0wLjQ5NzMtMC4yMDAxLTAuMjEyMS0wLjM1NC0wLjQ2MTYtMC40NjE1LTAuNzQ4My0wLjEwNzUtMC4yODY4LTAuMTYxMy0wLjU5Ni0wLjE2MTMtMC45Mjc1di0wLjE3OTNjMC0wLjM3OTMgMC4wNTUyLTAuNzIyOCAwLjE2NTgtMS4wMzA1IDAuMTEwNS0wLjMwNzcgMC4yNjQzLTAuNTcwNiAwLjQ2MTUtMC43ODg2IDAuMTk3MS0wLjIyMTEgMC40MzAxLTAuMzg5OCAwLjY5OS0wLjUwNjMgMC4yNjg4LTAuMTE2NSAwLjU2MDEtMC4xNzQ4IDAuODczNy0wLjE3NDggMC4zNDY1IDAgMC42NDk3IDAuMDU4MyAwLjkwOTYgMC4xNzQ4czAuNDc0OSAwLjI4MDggMC42NDUyIDAuNDkyOGMwLjE3MzMgMC4yMDkxIDAuMzAxNyAwLjQ1ODYgMC4zODUzIDAuNzQ4MyAwLjA4NjcgMC4yODk4IDAuMTMgMC42MDk0IDAuMTMgMC45NTg5djAuNDYxNWgtMy43NDU5di0wLjc3NTJoMi42Nzk1di0wLjA4NTFjLTZlLTMgLTAuMTk0Mi0wLjA0NDgtMC4zNzY0LTAuMTE2NS0wLjU0NjYtMC4wNjg3LTAuMTcwMy0wLjE3NDgtMC4zMDc3LTAuMzE4MS0wLjQxMjMtMC4xNDM0LTAuMTA0NS0wLjMzNDYtMC4xNTY4LTAuNTczNi0wLjE1NjgtMC4xNzkyIDAtMC4zMzkgMC4wMzg4LTAuNDc5NCAwLjExNjUtMC4xMzc0IDAuMDc0Ny0wLjI1MjQgMC4xODM3LTAuMzQ1IDAuMzI3MXMtMC4xNjQzIDAuMzE2Ni0wLjIxNTEgMC41MTk4Yy0wLjA0NzggMC4yMDAxLTAuMDcxNyAwLjQyNTYtMC4wNzE3IDAuNjc2NXYwLjE3OTNjMCAwLjIxMjEgMC4wMjg0IDAuNDA5MiAwLjA4NTEgMC41OTE0IDAuMDU5OCAwLjE3OTMgMC4xNDY0IDAuMzM2MSAwLjI1OTkgMC40NzA1czAuMjUwOSAwLjI0MDUgMC40MTIzIDAuMzE4MWMwLjE2MTMgMC4wNzQ3IDAuMzQ1IDAuMTEyIDAuNTUxMSAwLjExMiAwLjI1OTkgMCAwLjQ5MTQtMC4wNTIyIDAuNjk0NS0wLjE1NjggMC4yMDMxLTAuMTA0NSAwLjM3OTQtMC4yNTI0IDAuNTI4Ny0wLjQ0MzZsMC41NjkxIDAuNTUxMmMtMC4xMDQ2IDAuMTUyMy0wLjI0MDUgMC4yOTg3LTAuNDA3OCAwLjQzOTEtMC4xNjczIDAuMTM3NC0wLjM3MTkgMC4yNDk0LTAuNjEzOCAwLjMzNi0wLjIzOSAwLjA4NjYtMC41MTY4IDAuMTMtMC44MzM1IDAuMTN6bTQuMDEwMy00LjAxNDd2My45MjVoLTEuMDc5OXYtNC44NDgxaDEuMDMwNmwwLjA0OTMgMC45MjMxem0xLjQ4MzEtMC45NTQ0LTllLTMgMS4wMDM2Yy0wLjA2NTctMC4wMTE5LTAuMTM3NC0wLjAyMDktMC4yMTUxLTAuMDI2OC0wLjA3NDYtNmUtMyAtMC4xNDkzLTllLTMgLTAuMjI0LTllLTMgLTAuMTg1MiAwLTAuMzQ4IDAuMDI2OS0wLjQ4ODQgMC4wODA3LTAuMTQwNCAwLjA1MDctMC4yNTg0IDAuMTI1NC0wLjM1NCAwLjIyNC0wLjA5MjYgMC4wOTU2LTAuMTY0MyAwLjIxMjEtMC4yMTUgMC4zNDk1LTAuMDUwOCAwLjEzNzQtMC4wODA3IDAuMjkxMi0wLjA4OTYgMC40NjE1bC0wLjI0NjUgMC4wMTc5YzAtMC4zMDQ3IDAuMDI5OS0wLjU4NyAwLjA4OTYtMC44NDY4IDAuMDU5OC0wLjI1OTkgMC4xNDk0LTAuNDg4NCAwLjI2ODktMC42ODU2IDAuMTIyNC0wLjE5NzEgMC4yNzQ4LTAuMzUxIDAuNDU3LTAuNDYxNSAwLjE4NTItMC4xMTA1IDAuMzk4OC0wLjE2NTggMC42NDA3LTAuMTY1OCAwLjA2NTggMCAwLjEzNiA2ZS0zIDAuMjEwNiAwLjAxNzkgMC4wNzc3IDAuMDEyIDAuMTM2IDAuMDI1NCAwLjE3NDggMC4wNDA0em0zLjM5MTkgMy45MDcxdi0yLjMxMmMwLTAuMTczMy0wLjAzMTQtMC4zMjI2LTAuMDk0MS0wLjQ0ODEtMC4wNjI4LTAuMTI1NC0wLjE1ODMtMC4yMjI1LTAuMjg2OC0wLjI5MTItMC4xMjU0LTAuMDY4Ny0wLjI4MzgtMC4xMDMxLTAuNDc0OS0wLjEwMzEtMC4xNzYzIDAtMC4zMjg2IDAuMDI5OS0wLjQ1NzEgMC4wODk2LTAuMTI4NCAwLjA1OTgtMC4yMjg1IDAuMTQwNC0wLjMwMDIgMC4yNDJzLTAuMTA3NSAwLjIxNjYtMC4xMDc1IDAuMzQ1aC0xLjA3NTRjMC0wLjE5MTIgMC4wNDYzLTAuMzc2NCAwLjEzODktMC41NTU2czAuMjI3LTAuMzM5IDAuNDAzMy0wLjQ3OTRjMC4xNzYyLTAuMTQwNCAwLjM4NjgtMC4yNTA5IDAuNjMxOC0wLjMzMTYgMC4yNDQ5LTAuMDgwNyAwLjUxOTctMC4xMjEgMC44MjQ0LTAuMTIxIDAuMzY0NCAwIDAuNjg3IDAuMDYxMyAwLjk2NzggMC4xODM3IDAuMjgzOCAwLjEyMjUgMC41MDY0IDAuMzA3NyAwLjY2NzcgMC41NTU2IDAuMTY0MyAwLjI0NSAwLjI0NjQgMC41NTI3IDAuMjQ2NCAwLjkyMzF2Mi4xNTUyYzAgMC4yMjEgMC4wMTQ5IDAuNDE5NyAwLjA0NDggMC41OTU5IDAuMDMyOSAwLjE3MzMgMC4wNzkyIDAuMzI0MSAwLjEzODkgMC40NTI2djAuMDcxNmgtMS4xMDY3Yy0wLjA1MDgtMC4xMTY0LTAuMDkxMS0wLjI2NDMtMC4xMjEtMC40NDM1LTAuMDI2OS0wLjE4MjMtMC4wNDAzLTAuMzU4NS0wLjA0MDMtMC41Mjg4em0wLjE1NjgtMS45NzYgOWUtMyAwLjY2NzdoLTAuNzc1MmMtMC4yMDAxIDAtMC4zNzY0IDAuMDE5NC0wLjUyODcgMC4wNTgyLTAuMTUyNCAwLjAzNTktMC4yNzkzIDAuMDg5Ni0wLjM4MDkgMC4xNjEzLTAuMTAxNSAwLjA3MTctMC4xNzc3IDAuMTU4My0wLjIyODUgMC4yNTk5cy0wLjA3NjIgMC4yMTY2LTAuMDc2MiAwLjM0NWMwIDAuMTI4NSAwLjAyOTkgMC4yNDY1IDAuMDg5NiAwLjM1NCAwLjA1OTggMC4xMDQ1IDAuMTQ2NCAwLjE4NjcgMC4yNTk5IDAuMjQ2NCAwLjExNjUgMC4wNTk4IDAuMjU2OSAwLjA4OTYgMC40MjEyIDAuMDg5NiAwLjIyMTEgMCAwLjQxMzctMC4wNDQ4IDAuNTc4LTAuMTM0NCAwLjE2NzMtMC4wOTI2IDAuMjk4Ny0wLjIwNDYgMC4zOTQzLTAuMzM2IDAuMDk1Ni0wLjEzNDQgMC4xNDY0LTAuMjYxNCAwLjE1MjQtMC4zODA5bDAuMzQ5NSAwLjQ3OTVjLTAuMDM1OSAwLjEyMjQtMC4wOTcxIDAuMjUzOS0wLjE4MzggMC4zOTQzLTAuMDg2NiAwLjE0MDMtMC4yMDAxIDAuMjc0OC0wLjM0MDUgMC40MDMyLTAuMTM3NCAwLjEyNTUtMC4zMDMyIDAuMjI4NS0wLjQ5NzMgMC4zMDkyLTAuMTkxMiAwLjA4MDYtMC40MTIzIDAuMTIxLTAuNjYzMiAwLjEyMS0wLjMxNjYgMC0wLjU5ODktMC4wNjI4LTAuODQ2OC0wLjE4ODItMC4yNDgtMC4xMjg1LTAuNDQyMS0wLjMwMDItMC41ODI1LTAuNTE1My0wLjE0MDQtMC4yMTgxLTAuMjEwNi0wLjQ2NDUtMC4yMTA2LTAuNzM5MyAwLTAuMjU2OSAwLjA0NzgtMC40ODM5IDAuMTQzNC0wLjY4MTEgMC4wOTg1LTAuMjAwMSAwLjI0MTktMC4zNjc0IDAuNDMwMS0wLjUwMTggMC4xOTEyLTAuMTM0NCAwLjQyNDItMC4yMzYgMC42OTktMC4zMDQ3IDAuMjc0OC0wLjA3MTcgMC41ODg1LTAuMTA3NiAwLjk0MDktMC4xMDc2aDAuODQ2OXptNC40MjI0LTEuODk5OHYwLjc4ODZoLTIuNzMzMnYtMC43ODg2aDIuNzMzMnptLTEuOTQ0Ni0xLjE4NzRoMS4wNzk5djQuNjk1OGMwIDAuMTQ5NCAwLjAyMDkgMC4yNjQ0IDAuMDYyNyAwLjM0NSAwLjA0NDggMC4wNzc3IDAuMTA2IDAuMTMgMC4xODM3IDAuMTU2OSAwLjA3NzcgMC4wMjY4IDAuMTY4OCAwLjA0MDMgMC4yNzMzIDAuMDQwMyAwLjA3NDcgMCAwLjE0NjQtMC4wMDQ1IDAuMjE1MS0wLjAxMzUgMC4wNjg3LTAuMDA4OSAwLjEyNC0wLjAxNzkgMC4xNjU4LTAuMDI2OGwwLjAwNDUgMC44MjQ0Yy0wLjA4OTYgMC4wMjY5LTAuMTk0MiAwLjA1MDgtMC4zMTM3IDAuMDcxNy0wLjExNjUgMC4wMjA5LTAuMjUwOSAwLjAzMTQtMC40MDMyIDAuMDMxNC0wLjI0OCAwLTAuNDY3NS0wLjA0MzQtMC42NTg3LTAuMTMtMC4xOTEyLTAuMDg5Ni0wLjM0MDUtMC4yMzQ1LTAuNDQ4MS0wLjQzNDYtMC4xMDc1LTAuMjAwMS0wLjE2MTMtMC40NjYtMC4xNjEzLTAuNzk3NnYtNC43NjN6bTUuODM4NCA0Ljg5M3YtMy43MDU2aDEuMDg0M3Y0Ljg0ODFoLTEuMDIxNmwtMC4wNjI3LTEuMTQyNXptMC4xNTIzLTEuMDA4MiAwLjM2My0wLjAwODljMCAwLjMyNTUtMC4wMzU5IDAuNjI1OC0wLjEwNzYgMC45MDA2LTAuMDcxNyAwLjI3MTgtMC4xODIyIDAuNTA5My0wLjMzMTYgMC43MTI0LTAuMTQ5MyAwLjIwMDEtMC4zNDA1IDAuMzU3LTAuNTczNSAwLjQ3MDUtMC4yMzMgMC4xMTA1LTAuNTEyMyAwLjE2NTgtMC44Mzc5IDAuMTY1OC0wLjIzNiAwLTAuNDUyNS0wLjAzNDQtMC42NDk3LTAuMTAzMS0wLjE5NzEtMC4wNjg3LTAuMzY3NC0wLjE3NDctMC41MTA4LTAuMzE4MS0wLjE0MDQtMC4xNDM0LTAuMjQ5NC0wLjMzMDEtMC4zMjcxLTAuNTYwMS0wLjA3NzYtMC4yMy0wLjExNjUtMC41MDQ4LTAuMTE2NS0wLjgyNDV2LTMuMTMyaDEuMDc5OXYzLjE0MWMwIDAuMTc2MiAwLjAyMDkgMC4zMjQxIDAuMDYyNyAwLjQ0MzYgMC4wNDE4IDAuMTE2NSAwLjA5ODYgMC4yMTA2IDAuMTcwMyAwLjI4MjNzMC4xNTUzIDAuMTIyNCAwLjI1MDkgMC4xNTIzIDAuMTk3MSAwLjA0NDggMC4zMDQ3IDAuMDQ0OGMwLjMwNzcgMCAwLjU0OTYtMC4wNTk3IDAuNzI1OS0wLjE3OTIgMC4xNzkyLTAuMTIyNSAwLjMwNjEtMC4yODY4IDAuMzgwOC0wLjQ5MjkgMC4wNzc3LTAuMjA2MSAwLjExNjUtMC40Mzc2IDAuMTE2NS0wLjY5NDV6bTMuMjY2NC0xLjc3NDN2My45MjVoLTEuMDc5OHYtNC44NDgxaDEuMDMwNmwwLjA0OTIgMC45MjMxem0xLjQ4MzItMC45NTQ0LTllLTMgMS4wMDM2Yy0wLjA2NTctMC4wMTE5LTAuMTM3NC0wLjAyMDktMC4yMTUxLTAuMDI2OC0wLjA3NDctNmUtMyAtMC4xNDkzLTllLTMgLTAuMjI0LTllLTMgLTAuMTg1MiAwLTAuMzQ4IDAuMDI2OS0wLjQ4ODQgMC4wODA3LTAuMTQwNCAwLjA1MDctMC4yNTg0IDAuMTI1NC0wLjM1NCAwLjIyNC0wLjA5MjYgMC4wOTU2LTAuMTY0MyAwLjIxMjEtMC4yMTUxIDAuMzQ5NS0wLjA1MDcgMC4xMzc0LTAuMDgwNiAwLjI5MTItMC4wODk2IDAuNDYxNWwtMC4yNDY0IDAuMDE3OWMwLTAuMzA0NyAwLjAyOTktMC41ODcgMC4wODk2LTAuODQ2OCAwLjA1OTctMC4yNTk5IDAuMTQ5NC0wLjQ4ODQgMC4yNjg4LTAuNjg1NiAwLjEyMjUtMC4xOTcxIDAuMjc0OS0wLjM1MSAwLjQ1NzEtMC40NjE1IDAuMTg1Mi0wLjExMDUgMC4zOTg4LTAuMTY1OCAwLjY0MDctMC4xNjU4IDAuMDY1NyAwIDAuMTM1OSA2ZS0zIDAuMjEwNiAwLjAxNzkgMC4wNzc3IDAuMDEyIDAuMTM1OSAwLjAyNTQgMC4xNzQ4IDAuMDQwNHptMi44Njc2IDQuOTY5MWMtMC4zNTg1IDAtMC42ODI2LTAuMDU4My0wLjk3MjMtMC4xNzQ4LTAuMjg2OC0wLjExOTUtMC41MzE3LTAuMjg1My0wLjczNDgtMC40OTczLTAuMjAwMi0wLjIxMjEtMC4zNTQtMC40NjE2LTAuNDYxNi0wLjc0ODMtMC4xMDc1LTAuMjg2OC0wLjE2MTMtMC41OTYtMC4xNjEzLTAuOTI3NXYtMC4xNzkzYzAtMC4zNzkzIDAuMDU1My0wLjcyMjggMC4xNjU4LTEuMDMwNSAwLjExMDYtMC4zMDc3IDAuMjY0NC0wLjU3MDYgMC40NjE1LTAuNzg4NiAwLjE5NzItMC4yMjExIDAuNDMwMi0wLjM4OTggMC42OTktMC41MDYzIDAuMjY4OS0wLjExNjUgMC41NjAxLTAuMTc0OCAwLjg3MzgtMC4xNzQ4IDAuMzQ2NSAwIDAuNjQ5NyAwLjA1ODMgMC45MDk1IDAuMTc0OCAwLjI1OTkgMC4xMTY1IDAuNDc1IDAuMjgwOCAwLjY0NTMgMC40OTI4IDAuMTcyOSAwLjIwOTEgMC4zMDE5IDAuNDU4NiAwLjM4NDkgMC43NDgzIDAuMDg3IDAuMjg5OCAwLjEzIDAuNjA5NCAwLjEzIDAuOTU4OXYwLjQ2MTVoLTMuNzQ1NXYtMC43NzUyaDIuNjc5NHYtMC4wODUxYy0wLjAwNTktMC4xOTQyLTAuMDQ0OC0wLjM3NjQtMC4xMTY1LTAuNTQ2Ni0wLjA2ODctMC4xNzAzLTAuMTc0Ny0wLjMwNzctMC4zMTgxLTAuNDEyMy0wLjE0MzQtMC4xMDQ1LTAuMzM0NS0wLjE1NjgtMC41NzM1LTAuMTU2OC0wLjE3OTIgMC0wLjMzOTEgMC4wMzg4LTAuNDc5NSAwLjExNjUtMC4xMzc0IDAuMDc0Ny0wLjI1MjQgMC4xODM3LTAuMzQ1IDAuMzI3MXMtMC4xNjQzIDAuMzE2Ni0wLjIxNSAwLjUxOThjLTAuMDQ3OCAwLjIwMDEtMC4wNzE3IDAuNDI1Ni0wLjA3MTcgMC42NzY1djAuMTc5M2MwIDAuMjEyMSAwLjAyODMgMC40MDkyIDAuMDg1MSAwLjU5MTQgMC4wNTk3IDAuMTc5MyAwLjE0NjQgMC4zMzYxIDAuMjU5OSAwLjQ3MDVzMC4yNTA5IDAuMjQwNSAwLjQxMjIgMC4zMTgxYzAuMTYxMyAwLjA3NDcgMC4zNDUgMC4xMTIgMC41NTExIDAuMTEyIDAuMjU5OSAwIDAuNDkxNC0wLjA1MjIgMC42OTQ1LTAuMTU2OCAwLjIwMzItMC4xMDQ1IDAuMzc5NC0wLjI1MjQgMC41Mjg4LTAuNDQzNmwwLjU2ODggMC41NTEyYy0wLjEwNCAwLjE1MjMtMC4yNCAwLjI5ODctMC40MDc1IDAuNDM5MS0wLjE2NzMgMC4xMzc0LTAuMzcxOSAwLjI0OTQtMC42MTM5IDAuMzM2LTAuMjM5IDAuMDg2Ni0wLjUxNjggMC4xMy0wLjgzMzQgMC4xM3oiIGZpbGwtb3BhY2l0eT0iLjg3Ii8+CiAgIDxwYXRoIGQ9Im01MC4zNTYgMzYuNTk2djAuNjY4N2gtMi40NTY2di0wLjY2ODdoMi40NTY2em0tMi4yMjEzLTQuMjI0MnY0Ljg5MjloLTAuODQzNXYtNC44OTI5aDAuODQzNXptNC45ODU5IDQuMTYzN3YtMS43MzRjMC0wLjEzLTAuMDIzNi0wLjI0Mi0wLjA3MDYtMC4zMzYxLTAuMDQ3MS0wLjA5NDEtMC4xMTg3LTAuMTY2OS0wLjIxNTEtMC4yMTg0LTAuMDk0MS0wLjA1MTUtMC4yMTI4LTAuMDc3My0wLjM1NjItMC4wNzczLTAuMTMyMiAwLTAuMjQ2NCAwLjAyMjQtMC4zNDI4IDAuMDY3Mi0wLjA5NjMgMC4wNDQ4LTAuMTcxNCAwLjEwNTMtMC4yMjUxIDAuMTgxNS0wLjA1MzggMC4wNzYyLTAuMDgwNyAwLjE2MjQtMC4wODA3IDAuMjU4N2gtMC44MDY1YzAtMC4xNDMzIDAuMDM0Ny0wLjI4MjIgMC4xMDQyLTAuNDE2NyAwLjA2OTQtMC4xMzQ0IDAuMTcwMi0wLjI1NDIgMC4zMDI0LTAuMzU5NXMwLjI5MDEtMC4xODgyIDAuNDczOS0wLjI0ODdjMC4xODM3LTAuMDYwNSAwLjM4OTgtMC4wOTA3IDAuNjE4My0wLjA5MDcgMC4yNzMzIDAgMC41MTUzIDAuMDQ1OSAwLjcyNTkgMC4xMzc3IDAuMjEyOCAwLjA5MTkgMC4zNzk3IDAuMjMwOCAwLjUwMDcgMC40MTY3IDAuMTIzMiAwLjE4MzcgMC4xODQ4IDAuNDE0NSAwLjE4NDggMC42OTIzdjEuNjE2NGMwIDAuMTY1OCAwLjAxMTIgMC4zMTQ4IDAuMDMzNiAwLjQ0NyAwLjAyNDcgMC4xMjk5IDAuMDU5NCAwLjI0MyAwLjEwNDIgMC4zMzk0djAuMDUzN2gtMC44MzAxYy0wLjAzOC0wLjA4NzMtMC4wNjgzLTAuMTk4Mi0wLjA5MDctMC4zMzI2LTAuMDIwMi0wLjEzNjctMC4wMzAyLTAuMjY4OS0wLjAzMDItMC4zOTY2em0wLjExNzYtMS40ODIgMC4wMDY3IDAuNTAwN2gtMC41ODE0Yy0wLjE1MDEgMC0wLjI4MjMgMC4wMTQ2LTAuMzk2NSAwLjA0MzctMC4xMTQzIDAuMDI2OS0wLjIwOTUgMC4wNjcyLTAuMjg1NyAwLjEyMS0wLjA3NjEgMC4wNTM4LTAuMTMzMyAwLjExODctMC4xNzEzIDAuMTk0OS0wLjAzODEgMC4wNzYyLTAuMDU3MiAwLjE2MjQtMC4wNTcyIDAuMjU4OCAwIDAuMDk2MyAwLjAyMjQgMC4xODQ4IDAuMDY3MiAwLjI2NTUgMC4wNDQ4IDAuMDc4NCAwLjEwOTggMC4xNCAwLjE5NDkgMC4xODQ4IDAuMDg3NCAwLjA0NDggMC4xOTI3IDAuMDY3MiAwLjMxNTkgMC4wNjcyIDAuMTY1OCAwIDAuMzEwMy0wLjAzMzYgMC40MzM1LTAuMTAwOCAwLjEyNTUtMC4wNjk1IDAuMjI0MS0wLjE1MzUgMC4yOTU4LTAuMjUyMSAwLjA3MTctMC4xMDA4IDAuMTA5Ny0wLjE5NiAwLjExNDItMC4yODU2bDAuMjYyMiAwLjM1OTZjLTAuMDI2OSAwLjA5MTgtMC4wNzI5IDAuMTkwNC0wLjEzNzggMC4yOTU3LTAuMDY1IDAuMTA1My0wLjE1MDEgMC4yMDYxLTAuMjU1NCAwLjMwMjQtMC4xMDMxIDAuMDk0MS0wLjIyNzQgMC4xNzE0LTAuMzczIDAuMjMxOS0wLjE0MzQgMC4wNjA1LTAuMzA5MiAwLjA5MDgtMC40OTc0IDAuMDkwOC0wLjIzNzUgMC0wLjQ0OTItMC4wNDcxLTAuNjM1MS0wLjE0MTItMC4xODYtMC4wOTYzLTAuMzMxNi0wLjIyNTEtMC40MzY5LTAuMzg2NC0wLjEwNTMtMC4xNjM2LTAuMTU4LTAuMzQ4NC0wLjE1OC0wLjU1NDUgMC0wLjE5MjcgMC4wMzU5LTAuMzYzIDAuMTA3Ni0wLjUxMDggMC4wNzM5LTAuMTUwMSAwLjE4MTQtMC4yNzU2IDAuMzIyNi0wLjM3NjQgMC4xNDM0LTAuMTAwOCAwLjMxODEtMC4xNzcgMC41MjQyLTAuMjI4NSAwLjIwNjEtMC4wNTM4IDAuNDQxNC0wLjA4MDcgMC43MDU3LTAuMDgwN2gwLjYzNTJ6bTMuNzI1NyAxLjIyNjZjMC0wLjA4MDYtMC4wMjAyLTAuMTUzNC0wLjA2MDUtMC4yMTg0LTAuMDQwMy0wLjA2NzItMC4xMTc2LTAuMTI3Ny0wLjIzMTktMC4xODE1LTAuMTEyLTAuMDUzOC0wLjI3NzgtMC4xMDMtMC40OTczLTAuMTQ3OS0wLjE5MjctMC4wNDI1LTAuMzY5Ny0wLjA5MjktMC41MzEtMC4xNTEyLTAuMTU5MS0wLjA2MDUtMC4yOTU3LTAuMTMzMy0wLjQxLTAuMjE4NC0wLjExNDItMC4wODUxLTAuMjAyNy0wLjE4Ni0wLjI2NTUtMC4zMDI1LTAuMDYyNy0wLjExNjUtMC4wOTQxLTAuMjUwOS0wLjA5NDEtMC40MDMyIDAtMC4xNDc5IDAuMDMyNS0wLjI4NzkgMC4wOTc1LTAuNDIwMXMwLjE1NzktMC4yNDg3IDAuMjc4OS0wLjM0OTUgMC4yNjc3LTAuMTgwMyAwLjQ0MDItMC4yMzg2YzAuMTc0OC0wLjA1ODIgMC4zNjk3LTAuMDg3MyAwLjU4NDgtMC4wODczIDAuMzA0NyAwIDAuNTY1NyAwLjA1MTUgMC43ODMgMC4xNTQ1IDAuMjE5NSAwLjEwMDkgMC4zODc2IDAuMjM4NiAwLjUwNDEgMC40MTM0IDAuMTE2NSAwLjE3MjUgMC4xNzQ3IDAuMzY3NCAwLjE3NDcgMC41ODQ3aC0wLjgwOTljMC0wLjA5NjMtMC4wMjQ2LTAuMTg1OS0wLjA3MzktMC4yNjg4LTAuMDQ3MS0wLjA4NTItMC4xMTg4LTAuMTUzNS0wLjIxNTEtMC4yMDUtMC4wOTYzLTAuMDUzOC0wLjIxNzMtMC4wODA3LTAuMzYyOS0wLjA4MDctMC4xMzg5IDAtMC4yNTQzIDAuMDIyNC0wLjM0NjIgMC4wNjcyLTAuMDg5NiAwLjA0MjYtMC4xNTY4IDAuMDk4Ni0wLjIwMTYgMC4xNjgxLTAuMDQyNiAwLjA2OTQtMC4wNjM4IDAuMTQ1Ni0wLjA2MzggMC4yMjg1IDAgMC4wNjA1IDAuMDExMiAwLjExNTQgMC4wMzM2IDAuMTY0NiAwLjAyNDYgMC4wNDcxIDAuMDY0OSAwLjA5MDggMC4xMjA5IDAuMTMxMSAwLjA1NjEgMC4wMzgxIDAuMTMyMiAwLjA3MzkgMC4yMjg2IDAuMTA3NSAwLjA5ODUgMC4wMzM2IDAuMjIxOCAwLjA2NjEgMC4zNjk2IDAuMDk3NSAwLjI3NzggMC4wNTgyIDAuNTE2NCAwLjEzMzMgMC43MTU4IDAuMjI1MSAwLjIwMTYgMC4wODk3IDAuMzU2MiAwLjIwNjIgMC40NjM4IDAuMzQ5NSAwLjEwNzUgMC4xNDEyIDAuMTYxMyAwLjMyMDQgMC4xNjEzIDAuNTM3NyAwIDAuMTYxMy0wLjAzNDggMC4zMDkyLTAuMTA0MiAwLjQ0MzYtMC4wNjcyIDAuMTMyMi0wLjE2NTggMC4yNDc2LTAuMjk1NyAwLjM0NjItMC4xMyAwLjA5NjMtMC4yODU3IDAuMTcxMy0wLjQ2NzIgMC4yMjUxLTAuMTc5MiAwLjA1MzgtMC4zODA4IDAuMDgwNy0wLjYwNDggMC4wODA3LTAuMzI5NCAwLTAuNjA4My0wLjA1ODMtMC44MzY4LTAuMTc0OC0wLjIyODUtMC4xMTg3LTAuNDAyMi0wLjI3LTAuNTIwOS0wLjQ1MzctMC4xMTY1LTAuMTg1OS0wLjE3NDctMC4zNzg2LTAuMTc0Ny0wLjU3OGgwLjc4M2MwLjAwODkgMC4xNTAxIDAuMDUwNCAwLjI3IDAuMTI0MyAwLjM1OTYgMC4wNzYyIDAuMDg3NCAwLjE3MDMgMC4xNTEyIDAuMjgyMyAwLjE5MTYgMC4xMTQyIDAuMDM4IDAuMjMxOSAwLjA1NzEgMC4zNTI4IDAuMDU3MSAwLjE0NTcgMCAwLjI2NzgtMC4wMTkxIDAuMzY2My0wLjA1NzEgMC4wOTg2LTAuMDQwNCAwLjE3MzctMC4wOTQxIDAuMjI1Mi0wLjE2MTMgMC4wNTE1LTAuMDY5NSAwLjA3NzMtMC4xNDc5IDAuMDc3My0wLjIzNTN6bTMuMzEyMy0yLjY1MTR2MC41OTE0aC0yLjA0OTl2LTAuNTkxNGgyLjA0OTl6bS0xLjQ1ODQtMC44OTA2aDAuODA5OXYzLjUyMTljMCAwLjExMiAwLjAxNTYgMC4xOTgyIDAuMDQ3IDAuMjU4NyAwLjAzMzYgMC4wNTgzIDAuMDc5NSAwLjA5NzUgMC4xMzc4IDAuMTE3NiAwLjA1ODIgMC4wMjAyIDAuMTI2NiAwLjAzMDMgMC4yMDUgMC4wMzAzIDAuMDU2IDAgMC4xMDk4LTAuMDAzNCAwLjE2MTMtMC4wMTAxczAuMDkzLTAuMDEzNCAwLjEyNDMtMC4wMjAybDAuMDAzNCAwLjYxODRjLTAuMDY3MiAwLjAyMDEtMC4xNDU2IDAuMDM4MS0wLjIzNTMgMC4wNTM3LTAuMDg3MyAwLjAxNTctMC4xODgxIDAuMDIzNi0wLjMwMjQgMC4wMjM2LTAuMTg2IDAtMC4zNTA2LTAuMDMyNS0wLjQ5NC0wLjA5NzUtMC4xNDM0LTAuMDY3Mi0wLjI1NTQtMC4xNzU5LTAuMzM2MS0wLjMyNi0wLjA4MDYtMC4xNTAxLTAuMTIwOS0wLjM0OTUtMC4xMjA5LTAuNTk4MXYtMy41NzIzem02LjI3MTggMy42Njk3di0yLjc3OTFoMC44MTMzdjMuNjM2aC0wLjc2NjJsLTAuMDQ3MS0wLjg1Njl6bTAuMTE0My0wLjc1NjEgMC4yNzIyLTAuMDA2N2MwIDAuMjQ0Mi0wLjAyNjkgMC40NjkzLTAuMDgwNyAwLjY3NTQtMC4wNTM3IDAuMjAzOS0wLjEzNjYgMC4zODItMC4yNDg2IDAuNTM0NC0wLjExMjEgMC4xNTAxLTAuMjU1NCAwLjI2NzctMC40MzAyIDAuMzUyOC0wLjE3NDcgMC4wODI5LTAuMzg0MiAwLjEyNDQtMC42Mjg0IDAuMTI0NC0wLjE3NyAwLTAuMzM5NC0wLjAyNTgtMC40ODczLTAuMDc3My0wLjE0NzgtMC4wNTE2LTAuMjc1NS0wLjEzMTEtMC4zODMxLTAuMjM4Ni0wLjEwNTMtMC4xMDc2LTAuMTg3MS0wLjI0NzYtMC4yNDUzLTAuNDIwMS0wLjA1ODMtMC4xNzI1LTAuMDg3NC0wLjM3ODYtMC4wODc0LTAuNjE4M3YtMi4zNDloMC44MDk5djIuMzU1N2MwIDAuMTMyMiAwLjAxNTcgMC4yNDMxIDAuMDQ3MSAwLjMzMjcgMC4wMzEzIDAuMDg3NCAwLjA3MzkgMC4xNTc5IDAuMTI3NyAwLjIxMTcgMC4wNTM3IDAuMDUzOCAwLjExNjUgMC4wOTE4IDAuMTg4MSAwLjExNDMgMC4wNzE3IDAuMDIyNCAwLjE0NzkgMC4wMzM2IDAuMjI4NiAwLjAzMzYgMC4yMzA3IDAgMC40MTIyLTAuMDQ0OSAwLjU0NDQtMC4xMzQ1IDAuMTM0NC0wLjA5MTggMC4yMjk2LTAuMjE1IDAuMjg1Ni0wLjM2OTYgMC4wNTgzLTAuMTU0NiAwLjA4NzQtMC4zMjgyIDAuMDg3NC0wLjUyMDl6bTIuNDg1Ny0xLjMyNHY0LjMzNWgtMC44MDk5di01LjAzNGgwLjc0NmwwLjA2MzkgMC42OTl6bTIuMzY5MSAxLjA4NTR2MC4wNzA2YzAgMC4yNjQzLTAuMDMxMyAwLjUwOTctMC4wOTQxIDAuNzM1OS0wLjA2MDUgMC4yMjQxLTAuMTUxMiAwLjQyMDEtMC4yNzIyIDAuNTg4MS0wLjExODcgMC4xNjU4LTAuMjY1NSAwLjI5NDYtMC40NDAyIDAuMzg2NS0wLjE3NDggMC4wOTE4LTAuMzc2NCAwLjEzNzgtMC42MDQ5IDAuMTM3OC0wLjIyNjMgMC0wLjQyNDUtMC4wNDE1LTAuNTk0OC0wLjEyNDQtMC4xNjgtMC4wODUxLTAuMzEwMy0wLjIwNS0wLjQyNjgtMC4zNTk2LTAuMTE2NS0wLjE1NDUtMC4yMTA2LTAuMzM2LTAuMjgyMy0wLjU0NDQtMC4wNjk0LTAuMjEwNi0wLjExODctMC40NDEzLTAuMTQ3OC0wLjY5MjJ2LTAuMjcyMmMwLjAyOTEtMC4yNjY2IDAuMDc4NC0wLjUwODYgMC4xNDc4LTAuNzI1OSAwLjA3MTctMC4yMTczIDAuMTY1OC0wLjQwNDQgMC4yODIzLTAuNTYxMnMwLjI1ODgtMC4yNzc4IDAuNDI2OC0wLjM2MjljMC4xNjgtMC4wODUyIDAuMzY0LTAuMTI3NyAwLjU4ODEtMC4xMjc3IDAuMjI4NSAwIDAuNDMxMiAwLjA0NDggMC42MDgyIDAuMTM0NCAwLjE3NyAwLjA4NzMgMC4zMjYgMC4yMTI4IDAuNDQ3IDAuMzc2NCAwLjEyMSAwLjE2MTMgMC4yMTE3IDAuMzU2MiAwLjI3MjIgMC41ODQ3IDAuMDYwNSAwLjIyNjMgMC4wOTA3IDAuNDc4MyAwLjA5MDcgMC43NTYxem0tMC44MDk5IDAuMDcwNnYtMC4wNzA2YzAtMC4xNjgtMC4wMTU2LTAuMzIzNy0wLjA0Ny0wLjQ2NzEtMC4wMzE0LTAuMTQ1Ni0wLjA4MDctMC4yNzMzLTAuMTQ3OS0wLjM4MzFzLTAuMTUzNC0wLjE5NDktMC4yNTg3LTAuMjU1NGMtMC4xMDMxLTAuMDYyNy0wLjIyNzQtMC4wOTQxLTAuMzczMS0wLjA5NDEtMC4xNDMzIDAtMC4yNjY2IDAuMDI0Ni0wLjM2OTYgMC4wNzM5LTAuMTAzMSAwLjA0NzEtMC4xODkzIDAuMTEzMi0wLjI1ODggMC4xOTgzLTAuMDY5NCAwLjA4NTEtMC4xMjMyIDAuMTg0OC0wLjE2MTMgMC4yOTkxLTAuMDM4MSAwLjExMi0wLjA2NDkgMC4yMzQxLTAuMDgwNiAwLjM2NjN2MC42NTE5YzAuMDI2OSAwLjE2MTMgMC4wNzI4IDAuMzA5MiAwLjEzNzggMC40NDM2IDAuMDY0OSAwLjEzNDQgMC4xNTY4IDAuMjQyIDAuMjc1NSAwLjMyMjYgMC4xMjEgMC4wNzg0IDAuMjc1NiAwLjExNzYgMC40NjM4IDAuMTE3NiAwLjE0NTYgMCAwLjI2OTktMC4wMzEzIDAuMzczLTAuMDk0MSAwLjEwMy0wLjA2MjcgMC4xODcxLTAuMTQ4OSAwLjI1Mi0wLjI1ODcgMC4wNjcyLTAuMTEyIDAuMTE2NS0wLjI0MDkgMC4xNDc5LTAuMzg2NXMwLjA0Ny0wLjMwMDIgMC4wNDctMC40NjM3em0zLjg2MDIgMS4wMjgzdi00LjQwOWgwLjgxMzJ2NS4xNjE3aC0wLjczNTlsLTAuMDc3My0wLjc1Mjd6bS0yLjM2NTktMS4wMjV2LTAuMDcwNWMwLTAuMjc1NiAwLjAzMjUtMC41MjY1IDAuMDk3NS0wLjc1MjggMC4wNjUtMC4yMjg1IDAuMTU5MS0wLjQyNDUgMC4yODIzLTAuNTg4MSAwLjEyMzItMC4xNjU4IDAuMjczMy0wLjI5MjQgMC40NTAzLTAuMzc5NyAwLjE3Ny0wLjA4OTYgMC4zNzY0LTAuMTM0NCAwLjU5ODItMC4xMzQ0IDAuMjE5NSAwIDAuNDEyMiAwLjA0MjUgMC41NzggMC4xMjc3IDAuMTY1OCAwLjA4NTEgMC4zMDY5IDAuMjA3MiAwLjQyMzQgMC4zNjYyIDAuMTE2NSAwLjE1NjkgMC4yMDk1IDAuMzQ1MSAwLjI3ODkgMC41NjQ2IDAuMDY5NSAwLjIxNzMgMC4xMTg4IDAuNDU5MyAwLjE0NzkgMC43MjU5djAuMjI1MWMtMC4wMjkxIDAuMjU5OS0wLjA3ODQgMC40OTc0LTAuMTQ3OSAwLjcxMjUtMC4wNjk0IDAuMjE1LTAuMTYyNCAwLjQwMS0wLjI3ODkgMC41NTc4cy0wLjI1ODggMC4yNzc4LTAuNDI2OCAwLjM2M2MtMC4xNjU4IDAuMDg1MS0wLjM1OTYgMC4xMjc3LTAuNTgxMyAwLjEyNzctMC4yMTk2IDAtMC40MTc5LTAuMDQ2LTAuNTk0OS0wLjEzNzgtMC4xNzQ3LTAuMDkxOS0wLjMyMzctMC4yMjA3LTAuNDQ2OS0wLjM4NjVzLTAuMjE3My0wLjM2MDctMC4yODIzLTAuNTg0N2MtMC4wNjUtMC4yMjYzLTAuMDk3NS0wLjQ3MTYtMC4wOTc1LTAuNzM2em0wLjgwOTktMC4wNzA1djAuMDcwNWMwIDAuMTY1OCAwLjAxNDYgMC4zMjA0IDAuMDQzNyAwLjQ2MzggMC4wMzE0IDAuMTQzNCAwLjA3OTYgMC4yNjk5IDAuMTQ0NSAwLjM3OTcgMC4wNjUgMC4xMDc2IDAuMTQ5IDAuMTkyNyAwLjI1MjEgMC4yNTU0IDAuMTA1MyAwLjA2MDUgMC4yMzA3IDAuMDkwOCAwLjM3NjMgMC4wOTA4IDAuMTgzOCAwIDAuMzM1LTAuMDQwNCAwLjQ1MzctMC4xMjEgMC4xMTg4LTAuMDgwNyAwLjIxMTctMC4xODkzIDAuMjc4OS0wLjMyNiAwLjA2OTUtMC4xMzg5IDAuMTE2NS0wLjI5MzUgMC4xNDEyLTAuNDYzN3YtMC42MDgzYy0wLjAxMzUtMC4xMzIyLTAuMDQxNS0wLjI1NTQtMC4wODQtMC4zNjk3LTAuMDQwNC0wLjExNDItMC4wOTUyLTAuMjEzOS0wLjE2NDctMC4yOTktMC4wNjk1LTAuMDg3NC0wLjE1NTctMC4xNTQ2LTAuMjU4OC0wLjIwMTctMC4xMDA4LTAuMDQ5My0wLjIyMDYtMC4wNzM5LTAuMzU5NS0wLjA3MzktMC4xNDc5IDAtMC4yNzM0IDAuMDMxNC0wLjM3NjQgMC4wOTQxLTAuMTAzMSAwLjA2MjctMC4xODgyIDAuMTQ5LTAuMjU1NCAwLjI1ODctMC4wNjUgMC4xMDk4LTAuMTEzMiAwLjIzNzUtMC4xNDQ1IDAuMzgzMS0wLjAzMTQgMC4xNDU3LTAuMDQ3MSAwLjMwMTQtMC4wNDcxIDAuNDY3MnptNS40MDk0IDEuMTE5di0xLjczNGMwLTAuMTMtMC4wMjM2LTAuMjQyLTAuMDcwNi0wLjMzNjEtMC4wNDcxLTAuMDk0MS0wLjExODgtMC4xNjY5LTAuMjE1MS0wLjIxODQtMC4wOTQxLTAuMDUxNS0wLjIxMjgtMC4wNzczLTAuMzU2Mi0wLjA3NzMtMC4xMzIyIDAtMC4yNDY0IDAuMDIyNC0wLjM0MjggMC4wNjcyLTAuMDk2MyAwLjA0NDgtMC4xNzE0IDAuMTA1My0wLjIyNTEgMC4xODE1LTAuMDUzOCAwLjA3NjItMC4wODA3IDAuMTYyNC0wLjA4MDcgMC4yNTg3aC0wLjgwNjVjMC0wLjE0MzMgMC4wMzQ3LTAuMjgyMiAwLjEwNDItMC40MTY3IDAuMDY5NC0wLjEzNDQgMC4xNzAyLTAuMjU0MiAwLjMwMjQtMC4zNTk1czAuMjkwMS0wLjE4ODIgMC40NzM4LTAuMjQ4N2MwLjE4MzgtMC4wNjA1IDAuMzg5OS0wLjA5MDcgMC42MTg0LTAuMDkwNyAwLjI3MzMgMCAwLjUxNTMgMC4wNDU5IDAuNzI1OSAwLjEzNzcgMC4yMTI4IDAuMDkxOSAwLjM3OTcgMC4yMzA4IDAuNTAwNyAwLjQxNjcgMC4xMjMyIDAuMTgzNyAwLjE4NDggMC40MTQ1IDAuMTg0OCAwLjY5MjN2MS42MTY0YzAgMC4xNjU4IDAuMDExMiAwLjMxNDggMC4wMzM2IDAuNDQ3IDAuMDI0NyAwLjEyOTkgMC4wNTk0IDAuMjQzIDAuMTA0MiAwLjMzOTR2MC4wNTM3aC0wLjgzMDFjLTAuMDM4LTAuMDg3My0wLjA2ODMtMC4xOTgyLTAuMDkwNy0wLjMzMjYtMC4wMjAyLTAuMTM2Ny0wLjAzMDItMC4yNjg5LTAuMDMwMi0wLjM5NjZ6bTAuMTE3Ni0xLjQ4MiAwLjAwNjcgMC41MDA3aC0wLjU4MTRjLTAuMTUwMSAwLTAuMjgyMyAwLjAxNDYtMC4zOTY1IDAuMDQzNy0wLjExNDMgMC4wMjY5LTAuMjA5NSAwLjA2NzItMC4yODU3IDAuMTIxLTAuMDc2MSAwLjA1MzgtMC4xMzMzIDAuMTE4Ny0wLjE3MTMgMC4xOTQ5LTAuMDM4MSAwLjA3NjItMC4wNTcyIDAuMTYyNC0wLjA1NzIgMC4yNTg4IDAgMC4wOTYzIDAuMDIyNCAwLjE4NDggMC4wNjcyIDAuMjY1NSAwLjA0NDggMC4wNzg0IDAuMTA5OCAwLjE0IDAuMTk0OSAwLjE4NDggMC4wODc0IDAuMDQ0OCAwLjE5MjcgMC4wNjcyIDAuMzE1OSAwLjA2NzIgMC4xNjU4IDAgMC4zMTAzLTAuMDMzNiAwLjQzMzUtMC4xMDA4IDAuMTI1NS0wLjA2OTUgMC4yMjQxLTAuMTUzNSAwLjI5NTgtMC4yNTIxIDAuMDcxNy0wLjEwMDggMC4xMDk3LTAuMTk2IDAuMTE0Mi0wLjI4NTZsMC4yNjIxIDAuMzU5NmMtMC4wMjY4IDAuMDkxOC0wLjA3MjggMC4xOTA0LTAuMTM3NyAwLjI5NTctMC4wNjUgMC4xMDUzLTAuMTUwMSAwLjIwNjEtMC4yNTU0IDAuMzAyNC0wLjEwMzEgMC4wOTQxLTAuMjI3NCAwLjE3MTQtMC4zNzMxIDAuMjMxOS0wLjE0MzMgMC4wNjA1LTAuMzA5MSAwLjA5MDgtMC40OTczIDAuMDkwOC0wLjIzNzUgMC0wLjQ0OTItMC4wNDcxLTAuNjM1MS0wLjE0MTItMC4xODYtMC4wOTYzLTAuMzMxNi0wLjIyNTEtMC40MzY5LTAuMzg2NC0wLjEwNTMtMC4xNjM2LTAuMTU4LTAuMzQ4NC0wLjE1OC0wLjU1NDUgMC0wLjE5MjcgMC4wMzU5LTAuMzYzIDAuMTA3Ni0wLjUxMDggMC4wNzM5LTAuMTUwMSAwLjE4MTQtMC4yNzU2IDAuMzIyNi0wLjM3NjQgMC4xNDM0LTAuMTAwOCAwLjMxODEtMC4xNzcgMC41MjQyLTAuMjI4NSAwLjIwNjEtMC4wNTM4IDAuNDQxNC0wLjA4MDcgMC43MDU3LTAuMDgwN2gwLjYzNTJ6bTMuMzUyNy0xLjQyNDh2MC41OTE0aC0yLjA1di0wLjU5MTRoMi4wNXptLTEuNDU4NS0wLjg5MDZoMC44MDk5djMuNTIxOWMwIDAuMTEyIDAuMDE1NyAwLjE5ODIgMC4wNDcgMC4yNTg3IDAuMDMzNiAwLjA1ODMgMC4wNzk2IDAuMDk3NSAwLjEzNzggMC4xMTc2IDAuMDU4MyAwLjAyMDIgMC4xMjY2IDAuMDMwMyAwLjIwNSAwLjAzMDMgMC4wNTYgMCAwLjEwOTgtMC4wMDM0IDAuMTYxMy0wLjAxMDFzMC4wOTMtMC4wMTM0IDAuMTI0My0wLjAyMDJsMC4wMDM0IDAuNjE4NGMtMC4wNjcyIDAuMDIwMS0wLjE0NTYgMC4wMzgxLTAuMjM1MiAwLjA1MzctMC4wODc0IDAuMDE1Ny0wLjE4ODIgMC4wMjM2LTAuMzAyNSAwLjAyMzYtMC4xODU5IDAtMC4zNTA2LTAuMDMyNS0wLjQ5NC0wLjA5NzUtMC4xNDM0LTAuMDY3Mi0wLjI1NTQtMC4xNzU5LTAuMzM2LTAuMzI2LTAuMDgwNy0wLjE1MDEtMC4xMjEtMC4zNDk1LTAuMTIxLTAuNTk4MXYtMy41NzIzem0zLjgyOTkgNC41OTM5Yy0wLjI2ODkgMC0wLjUxMi0wLjA0MzctMC43MjkzLTAuMTMxMS0wLjIxNS0wLjA4OTYtMC4zOTg3LTAuMjE0LTAuNTUxMS0wLjM3My0wLjE1MDEtMC4xNTkxLTAuMjY1NS0wLjM0NjItMC4zNDYxLTAuNTYxMi0wLjA4MDctMC4yMTUxLTAuMTIxLTAuNDQ3LTAuMTIxLTAuNjk1N3YtMC4xMzQ0YzAtMC4yODQ1IDAuMDQxNC0wLjU0MjEgMC4xMjQzLTAuNzcyOXMwLjE5ODMtMC40Mjc5IDAuMzQ2Mi0wLjU5MTRjMC4xNDc4LTAuMTY1OCAwLjMyMjYtMC4yOTI0IDAuNTI0Mi0wLjM3OThzMC40MjAxLTAuMTMxIDAuNjU1My0wLjEzMWMwLjI1OTkgMCAwLjQ4NzMgMC4wNDM2IDAuNjgyMiAwLjEzMXMwLjM1NjIgMC4yMTA2IDAuNDgzOSAwLjM2OTdjMC4xMyAwLjE1NjggMC4yMjYzIDAuMzQzOSAwLjI4OSAwLjU2MTIgMC4wNjUgMC4yMTczIDAuMDk3NSAwLjQ1NyAwLjA5NzUgMC43MTkxdjAuMzQ2MmgtMi44MDk0di0wLjU4MTRoMi4wMDk2di0wLjA2MzljLTAuMDA0NS0wLjE0NTYtMC4wMzM2LTAuMjgyMi0wLjA4NzQtMC40MDk5LTAuMDUxNS0wLjEyNzctMC4xMzExLTAuMjMwOC0wLjIzODYtMC4zMDkycy0wLjI1MDktMC4xMTc2LTAuNDMwMS0wLjExNzZjLTAuMTM0NSAwLTAuMjU0MyAwLjAyOTEtMC4zNTk2IDAuMDg3My0wLjEwMzEgMC4wNTYxLTAuMTg5MyAwLjEzNzgtMC4yNTg4IDAuMjQ1NC0wLjA2OTQgMC4xMDc1LTAuMTIzMiAwLjIzNzQtMC4xNjEzIDAuMzg5OC0wLjAzNTggMC4xNTAxLTAuMDUzOCAwLjMxOTItMC4wNTM4IDAuNTA3NHYwLjEzNDRjMCAwLjE1OTEgMC4wMjEzIDAuMzA3IDAuMDYzOSAwLjQ0MzYgMC4wNDQ4IDAuMTM0NSAwLjEwOTggMC4yNTIxIDAuMTk0OSAwLjM1MjlzMC4xODgyIDAuMTgwMyAwLjMwOTIgMC4yMzg2YzAuMTIwOSAwLjA1NiAwLjI1ODcgMC4wODQgMC40MTMzIDAuMDg0IDAuMTk0OSAwIDAuMzY4Ni0wLjAzOTIgMC41MjA5LTAuMTE3NnMwLjI4NDUtMC4xODkzIDAuMzk2NS0wLjMzMjdsMC40MjY4IDAuNDEzM2MtMC4wNzg0IDAuMTE0My0wLjE4MDMgMC4yMjQxLTAuMzA1OCAwLjMyOTQtMC4xMjU0IDAuMTAzLTAuMjc4OSAwLjE4Ny0wLjQ2MDQgMC4yNTItMC4xNzkyIDAuMDY1LTAuMzg3NiAwLjA5NzUtMC42MjUgMC4wOTc1em02LjI1MTctNC45Nzd2NC45MDk3aC0wLjgwOTl2LTMuOTQ4NmwtMS4xOTk3IDAuNDA2N3YtMC42Njg4bDEuOTEyMS0wLjY5OWgwLjA5NzV6bTQuMTA4OCA0LjE1N3YtNC40MDloMC44MTMydjUuMTYxN2gtMC43MzU5bC0wLjA3NzMtMC43NTI3em0tMi4zNjU4LTEuMDI1di0wLjA3MDVjMC0wLjI3NTYgMC4wMzI0LTAuNTI2NSAwLjA5NzQtMC43NTI4IDAuMDY1LTAuMjI4NSAwLjE1OTEtMC40MjQ1IDAuMjgyMy0wLjU4ODEgMC4xMjMyLTAuMTY1OCAwLjI3MzMtMC4yOTI0IDAuNDUwMy0wLjM3OTcgMC4xNzctMC4wODk2IDAuMzc2NC0wLjEzNDQgMC41OTgyLTAuMTM0NCAwLjIxOTUgMCAwLjQxMjIgMC4wNDI1IDAuNTc4IDAuMTI3NyAwLjE2NTggMC4wODUxIDAuMzA2OSAwLjIwNzIgMC40MjM0IDAuMzY2MiAwLjExNjUgMC4xNTY5IDAuMjA5NSAwLjM0NTEgMC4yNzg5IDAuNTY0NiAwLjA2OTUgMC4yMTczIDAuMTE4OCAwLjQ1OTMgMC4xNDc5IDAuNzI1OXYwLjIyNTFjLTAuMDI5MSAwLjI1OTktMC4wNzg0IDAuNDk3NC0wLjE0NzkgMC43MTI1LTAuMDY5NCAwLjIxNS0wLjE2MjQgMC40MDEtMC4yNzg5IDAuNTU3OHMtMC4yNTg3IDAuMjc3OC0wLjQyNjggMC4zNjNjLTAuMTY1OCAwLjA4NTEtMC4zNTk1IDAuMTI3Ny0wLjU4MTMgMC4xMjc3LTAuMjE5NiAwLTAuNDE3OS0wLjA0Ni0wLjU5NDktMC4xMzc4LTAuMTc0Ny0wLjA5MTktMC4zMjM3LTAuMjIwNy0wLjQ0NjktMC4zODY1cy0wLjIxNzMtMC4zNjA3LTAuMjgyMy0wLjU4NDdjLTAuMDY1LTAuMjI2My0wLjA5NzQtMC40NzE2LTAuMDk3NC0wLjczNnptMC44MDk4LTAuMDcwNXYwLjA3MDVjMCAwLjE2NTggMC4wMTQ2IDAuMzIwNCAwLjA0MzcgMC40NjM4IDAuMDMxNCAwLjE0MzQgMC4wNzk2IDAuMjY5OSAwLjE0NDUgMC4zNzk3IDAuMDY1IDAuMTA3NiAwLjE0OSAwLjE5MjcgMC4yNTIxIDAuMjU1NCAwLjEwNTMgMC4wNjA1IDAuMjMwNyAwLjA5MDggMC4zNzYzIDAuMDkwOCAwLjE4MzggMCAwLjMzNS0wLjA0MDQgMC40NTM3LTAuMTIxIDAuMTE4OC0wLjA4MDcgMC4yMTE3LTAuMTg5MyAwLjI3ODktMC4zMjYgMC4wNjk1LTAuMTM4OSAwLjExNjUtMC4yOTM1IDAuMTQxMi0wLjQ2Mzd2LTAuNjA4M2MtMC4wMTM1LTAuMTMyMi0wLjA0MTUtMC4yNTU0LTAuMDg0LTAuMzY5Ny0wLjA0MDQtMC4xMTQyLTAuMDk1Mi0wLjIxMzktMC4xNjQ3LTAuMjk5LTAuMDY5NC0wLjA4NzQtMC4xNTU3LTAuMTU0Ni0wLjI1ODgtMC4yMDE3LTAuMTAwOC0wLjA0OTMtMC4yMjA2LTAuMDczOS0wLjM1OTUtMC4wNzM5LTAuMTQ3OSAwLTAuMjczNCAwLjAzMTQtMC4zNzY0IDAuMDk0MS0wLjEwMzEgMC4wNjI3LTAuMTg4MiAwLjE0OS0wLjI1NTQgMC4yNTg3LTAuMDY1IDAuMTA5OC0wLjExMzEgMC4yMzc1LTAuMTQ0NSAwLjM4MzEtMC4wMzE0IDAuMTQ1Ny0wLjA0NzEgMC4zMDE0LTAuMDQ3MSAwLjQ2NzJ6bTcuMjY2NiAxLjExOXYtMS43MzRjMC0wLjEzLTAuMDIzNS0wLjI0Mi0wLjA3MDYtMC4zMzYxLTAuMDQ3LTAuMDk0MS0wLjExODctMC4xNjY5LTAuMjE1LTAuMjE4NC0wLjA5NDEtMC4wNTE1LTAuMjEyOS0wLjA3NzMtMC4zNTYyLTAuMDc3My0wLjEzMjIgMC0wLjI0NjUgMC4wMjI0LTAuMzQyOCAwLjA2NzItMC4wOTY0IDAuMDQ0OC0wLjE3MTQgMC4xMDUzLTAuMjI1MiAwLjE4MTUtMC4wNTM3IDAuMDc2Mi0wLjA4MDYgMC4xNjI0LTAuMDgwNiAwLjI1ODdoLTAuODA2NmMwLTAuMTQzMyAwLjAzNDgtMC4yODIyIDAuMTA0Mi0wLjQxNjcgMC4wNjk1LTAuMTM0NCAwLjE3MDMtMC4yNTQyIDAuMzAyNS0wLjM1OTUgMC4xMzIxLTAuMTA1MyAwLjI5MDEtMC4xODgyIDAuNDczOC0wLjI0ODdzMC4zODk4LTAuMDkwNyAwLjYxODMtMC4wOTA3YzAuMjczNCAwIDAuNTE1MyAwLjA0NTkgMC43MjU5IDAuMTM3NyAwLjIxMjggMC4wOTE5IDAuMzc5OCAwLjIzMDggMC41MDA3IDAuNDE2NyAwLjEyMzIgMC4xODM3IDAuMTg0OSAwLjQxNDUgMC4xODQ5IDAuNjkyM3YxLjYxNjRjMCAwLjE2NTggMC4wMTEyIDAuMzE0OCAwLjAzMzYgMC40NDcgMC4wMjQ2IDAuMTI5OSAwLjA1OTMgMC4yNDMgMC4xMDQxIDAuMzM5NHYwLjA1MzdoLTAuODNjLTAuMDM4MS0wLjA4NzMtMC4wNjgzLTAuMTk4Mi0wLjA5MDctMC4zMzI2LTAuMDIwMi0wLjEzNjctMC4wMzAzLTAuMjY4OS0wLjAzMDMtMC4zOTY2em0wLjExNzYtMS40ODIgMC4wMDY4IDAuNTAwN2gtMC41ODE0Yy0wLjE1MDEgMC0wLjI4MjMgMC4wMTQ2LTAuMzk2NiAwLjA0MzctMC4xMTQyIDAuMDI2OS0wLjIwOTQgMC4wNjcyLTAuMjg1NiAwLjEyMXMtMC4xMzMzIDAuMTE4Ny0wLjE3MTQgMC4xOTQ5LTAuMDU3MSAwLjE2MjQtMC4wNTcxIDAuMjU4OGMwIDAuMDk2MyAwLjAyMjQgMC4xODQ4IDAuMDY3MiAwLjI2NTUgMC4wNDQ4IDAuMDc4NCAwLjEwOTggMC4xNCAwLjE5NDkgMC4xODQ4IDAuMDg3NCAwLjA0NDggMC4xOTI3IDAuMDY3MiAwLjMxNTkgMC4wNjcyIDAuMTY1OCAwIDAuMzEwMy0wLjAzMzYgMC40MzM1LTAuMTAwOCAwLjEyNTUtMC4wNjk1IDAuMjI0LTAuMTUzNSAwLjI5NTctMC4yNTIxIDAuMDcxNy0wLjEwMDggMC4xMDk4LTAuMTk2IDAuMTE0My0wLjI4NTZsMC4yNjIxIDAuMzU5NmMtMC4wMjY5IDAuMDkxOC0wLjA3MjggMC4xOTA0LTAuMTM3OCAwLjI5NTdzLTAuMTUwMSAwLjIwNjEtMC4yNTU0IDAuMzAyNGMtMC4xMDMgMC4wOTQxLTAuMjI3NCAwLjE3MTQtMC4zNzMgMC4yMzE5LTAuMTQzNCAwLjA2MDUtMC4zMDkyIDAuMDkwOC0wLjQ5NzQgMC4wOTA4LTAuMjM3NCAwLTAuNDQ5MS0wLjA0NzEtMC42MzUxLTAuMTQxMi0wLjE4NTktMC4wOTYzLTAuMzMxNi0wLjIyNTEtMC40MzY5LTAuMzg2NC0wLjEwNTMtMC4xNjM2LTAuMTU3OS0wLjM0ODQtMC4xNTc5LTAuNTU0NSAwLTAuMTkyNyAwLjAzNTgtMC4zNjMgMC4xMDc1LTAuNTEwOCAwLjA3NC0wLjE1MDEgMC4xODE1LTAuMjc1NiAwLjMyMjYtMC4zNzY0IDAuMTQzNC0wLjEwMDggMC4zMTgyLTAuMTc3IDAuNTI0My0wLjIyODUgMC4yMDYxLTAuMDUzOCAwLjQ0MTMtMC4wODA3IDAuNzA1Ny0wLjA4MDdoMC42MzUxem00LjAxNDktMS40MjQ4aDAuNzM2djMuNTM1MmMwIDAuMzI3MS0wLjA3IDAuNjA0OS0wLjIwOSAwLjgzMzQtMC4xMzggMC4yMjg2LTAuMzMyIDAuNDAyMi0wLjU4MSAwLjUyMDktMC4yNDkgMC4xMjEtMC41MzYgMC4xODE1LTAuODY0IDAuMTgxNS0wLjEzOCAwLTAuMjkzLTAuMDIwMi0wLjQ2My0wLjA2MDUtMC4xNjgtMC4wNDAzLTAuMzMyLTAuMTA1My0wLjQ5MS0wLjE5NDktMC4xNTctMC4wODc0LTAuMjg4LTAuMjAyOC0wLjM5My0wLjM0NjFsMC4zOC0wLjQ3NzJjMC4xMyAwLjE1NDUgMC4yNzMgMC4yNjc3IDAuNDMgMC4zMzk0czAuMzIxIDAuMTA3NSAwLjQ5NCAwLjEwNzVjMC4xODYgMCAwLjM0NC0wLjAzNDcgMC40NzQtMC4xMDQyIDAuMTMyLTAuMDY3MiAwLjIzNC0wLjE2NjkgMC4zMDUtMC4yOTkgMC4wNzItMC4xMzIyIDAuMTA4LTAuMjkzNSAwLjEwOC0wLjQ4NHYtMi43Mjg3bDAuMDc0LTAuODIzM3ptLTIuNDcgMS44NTgzdi0wLjA3MDVjMC0wLjI3NTYgMC4wMzMtMC41MjY1IDAuMTAxLTAuNzUyOCAwLjA2Ny0wLjIyODUgMC4xNjMtMC40MjQ1IDAuMjg5LTAuNTg4MSAwLjEyNS0wLjE2NTggMC4yNzctMC4yOTI0IDAuNDU3LTAuMzc5NyAwLjE3OS0wLjA4OTYgMC4zODItMC4xMzQ0IDAuNjA4LTAuMTM0NCAwLjIzNSAwIDAuNDM2IDAuMDQyNSAwLjYwMSAwLjEyNzcgMC4xNjkgMC4wODUxIDAuMzA5IDAuMjA3MiAwLjQyMSAwLjM2NjIgMC4xMTIgMC4xNTY5IDAuMTk5IDAuMzQ1MSAwLjI2MiAwLjU2NDYgMC4wNjUgMC4yMTczIDAuMTEzIDAuNDU5MyAwLjE0NCAwLjcyNTl2MC4yMjUxYy0wLjAyOSAwLjI1OTktMC4wNzggMC40OTc0LTAuMTQ4IDAuNzEyNS0wLjA2OSAwLjIxNS0wLjE2MSAwLjQwMS0wLjI3NSAwLjU1NzgtMC4xMTUgMC4xNTY4LTAuMjU2IDAuMjc3OC0wLjQyNCAwLjM2My0wLjE2NSAwLjA4NTEtMC4zNjEgMC4xMjc3LTAuNTg4IDAuMTI3Ny0wLjIyMiAwLTAuNDIyLTAuMDQ2LTAuNjAxLTAuMTM3OC0wLjE3Ny0wLjA5MTktMC4zMy0wLjIyMDctMC40NTctMC4zODY1LTAuMTI2LTAuMTY1OC0wLjIyMi0wLjM2MDctMC4yODktMC41ODQ3LTAuMDY4LTAuMjI2My0wLjEwMS0wLjQ3MTYtMC4xMDEtMC43MzZ6bTAuODEtMC4wNzA1djAuMDcwNWMwIDAuMTY1OCAwLjAxNSAwLjMyMDQgMC4wNDcgMC40NjM4IDAuMDMzIDAuMTQzNCAwLjA4NCAwLjI2OTkgMC4xNTEgMC4zNzk3IDAuMDY5IDAuMTA3NiAwLjE1NyAwLjE5MjcgMC4yNjIgMC4yNTU0IDAuMTA4IDAuMDYwNSAwLjIzNCAwLjA5MDggMC4zOCAwLjA5MDggMC4xOSAwIDAuMzQ2LTAuMDQwNCAwLjQ2Ny0wLjEyMSAwLjEyMy0wLjA4MDcgMC4yMTctMC4xODkzIDAuMjgyLTAuMzI2IDAuMDY3LTAuMTM4OSAwLjExNS0wLjI5MzUgMC4xNDEtMC40NjM3di0wLjYwODNjLTAuMDEzLTAuMTMyMi0wLjA0MS0wLjI1NTQtMC4wODQtMC4zNjk3LTAuMDQtMC4xMTQyLTAuMDk1LTAuMjEzOS0wLjE2NC0wLjI5OS0wLjA3LTAuMDg3NC0wLjE1Ny0wLjE1NDYtMC4yNjItMC4yMDE3LTAuMTA2LTAuMDQ5My0wLjIzLTAuMDczOS0wLjM3My0wLjA3MzktMC4xNDYgMC0wLjI3MyAwLjAzMTQtMC4zOCAwLjA5NDEtMC4xMDggMC4wNjI3LTAuMTk2IDAuMTQ5LTAuMjY2IDAuMjU4Ny0wLjA2NyAwLjEwOTgtMC4xMTcgMC4yMzc1LTAuMTUxIDAuMzgzMS0wLjAzMyAwLjE0NTctMC4wNSAwLjMwMTQtMC4wNSAwLjQ2NzJ6bTMuMjI1IDAuMDcwNXYtMC4wNzczYzAtMC4yNjIxIDAuMDM4LTAuNTA1MiAwLjExNC0wLjcyOTIgMC4wNzYtMC4yMjYzIDAuMTg2LTAuNDIyMyAwLjMyOS0wLjU4ODEgMC4xNDYtMC4xNjggMC4zMjMtMC4yOTggMC41MzEtMC4zODk4IDAuMjExLTAuMDk0MSAwLjQ0OC0wLjE0MTEgMC43MTMtMC4xNDExIDAuMjY2IDAgMC41MDQgMC4wNDcgMC43MTIgMC4xNDExIDAuMjExIDAuMDkxOCAwLjM4OSAwLjIyMTggMC41MzQgMC4zODk4IDAuMTQ2IDAuMTY1OCAwLjI1NyAwLjM2MTggMC4zMzMgMC41ODgxIDAuMDc2IDAuMjI0IDAuMTE0IDAuNDY3MSAwLjExNCAwLjcyOTJ2MC4wNzczYzAgMC4yNjIyLTAuMDM4IDAuNTA1Mi0wLjExNCAwLjcyOTMtMC4wNzYgMC4yMjQtMC4xODcgMC40Mi0wLjMzMyAwLjU4ODEtMC4xNDUgMC4xNjU3LTAuMzIyIDAuMjk1Ny0wLjUzMSAwLjM4OTgtMC4yMDggMC4wOTE4LTAuNDQ0IDAuMTM3OC0wLjcwOSAwLjEzNzgtMC4yNjYgMC0wLjUwNS0wLjA0Ni0wLjcxNS0wLjEzNzgtMC4yMDktMC4wOTQxLTAuMzg2LTAuMjI0MS0wLjUzMS0wLjM4OTgtMC4xNDYtMC4xNjgxLTAuMjU3LTAuMzY0MS0wLjMzMy0wLjU4ODEtMC4wNzYtMC4yMjQxLTAuMTE0LTAuNDY3MS0wLjExNC0wLjcyOTN6bTAuODEtMC4wNzczdjAuMDc3M2MwIDAuMTYzNiAwLjAxNiAwLjMxODIgMC4wNSAwLjQ2MzhzMC4wODYgMC4yNzMzIDAuMTU4IDAuMzgzMSAwLjE2NCAwLjE5NiAwLjI3NiAwLjI1ODdjMC4xMTIgMC4wNjI4IDAuMjQ1IDAuMDk0MSAwLjM5OSAwLjA5NDEgMC4xNTEgMCAwLjI4LTAuMDMxMyAwLjM5LTAuMDk0MSAwLjExMi0wLjA2MjcgMC4yMDQtMC4xNDg5IDAuMjc2LTAuMjU4N3MwLjEyNC0wLjIzNzUgMC4xNTgtMC4zODMxYzAuMDM2LTAuMTQ1NiAwLjA1NC0wLjMwMDIgMC4wNTQtMC40NjM4di0wLjA3NzNjMC0wLjE2MTMtMC4wMTgtMC4zMTM2LTAuMDU0LTAuNDU3LTAuMDM0LTAuMTQ1Ni0wLjA4OC0wLjI3NDQtMC4xNjItMC4zODY1LTAuMDcxLTAuMTEyLTAuMTYzLTAuMTk5My0wLjI3NS0wLjI2MjEtMC4xMS0wLjA2NDktMC4yNDEtMC4wOTc0LTAuMzkzLTAuMDk3NC0wLjE1MyAwLTAuMjg1IDAuMDMyNS0wLjM5NyAwLjA5NzQtMC4xMSAwLjA2MjgtMC4yIDAuMTUwMS0wLjI3MiAwLjI2MjEtMC4wNzIgMC4xMTIxLTAuMTI0IDAuMjQwOS0wLjE1OCAwLjM4NjUtMC4wMzQgMC4xNDM0LTAuMDUgMC4yOTU3LTAuMDUgMC40NTd6IiBmaWxsLW9wYWNpdHk9Ii4zOCIvPgogICA8cGF0aCBkPSJtNDguMTk2IDgwLjQ2OXYyLjc5NTloLTE0LjIxM3YtMi40MDI3bDYuOTAyNS03LjUyODdjMC43NTcyLTAuODU0MyAxLjM1NDMtMS41OTIyIDEuNzkxMS0yLjIxMzUgMC40MzY5LTAuNjIxMyAwLjc0MjctMS4xNzk1IDAuOTE3NS0xLjY3NDYgMC4xODQ0LTAuNTA0OSAwLjI3NjYtMC45OTUxIDAuMjc2Ni0xLjQ3MDggMC0wLjY2OTktMC4xMjYyLTEuMjU3Mi0wLjM3ODYtMS43NjIxLTAuMjQyNy0wLjUxNDUtMC42MDE5LTAuOTE3NC0xLjA3NzYtMS4yMDg2LTAuNDc1Ny0wLjMwMS0xLjA1MzMtMC40NTE1LTEuNzMyOS0wLjQ1MTUtMC43ODY0IDAtMS40NDY1IDAuMTY5OS0xLjk4MDUgMC41MDk3LTAuNTMzOSAwLjMzOTgtMC45MzY4IDAuODEwNi0xLjIwODYgMS40MTI2LTAuMjcxOSAwLjU5MjEtMC40MDc4IDEuMjcxNy0wLjQwNzggMi4wMzg3aC0zLjUwOTVjMC0xLjIzMyAwLjI4MTYtMi4zNTkxIDAuODQ0Ni0zLjM3ODUgMC41NjMxLTEuMDI5IDEuMzc4Ni0xLjg0NDUgMi40NDY1LTIuNDQ2NCAxLjA2NzktMC42MTE3IDIuMzU0Mi0wLjkxNzUgMy44NTktMC45MTc1IDEuNDE3NCAwIDIuNjIxMiAwLjIzNzkgMy42MTE0IDAuNzEzNiAwLjk5MDMgMC40NzU3IDEuNzQyNyAxLjE1MDQgMi4yNTcyIDIuMDI0MSAwLjUyNDIgMC44NzM4IDAuNzg2NCAxLjkwNzcgMC43ODY0IDMuMTAxOCAwIDAuNjYwMi0wLjEwNjggMS4zMTU1LTAuMzIwNCAxLjk2NTktMC4yMTM2IDAuNjUwNS0wLjUxOTQgMS4zMDA5LTAuOTE3NCAxLjk1MTQtMC4zODg0IDAuNjQwNy0wLjg0OTUgMS4yODYzLTEuMzgzNSAxLjkzNjctMC41MzM5IDAuNjQwOC0xLjEyMTIgMS4yOTEyLTEuNzYyIDEuOTUxNGwtNC41ODcxIDUuMDUzMWg5Ljc4NTh6bTE2LjQyOSAwdjIuNzk1OWgtMTQuMjEzdi0yLjQwMjdsNi45MDI2LTcuNTI4N2MwLjc1NzItMC44NTQzIDEuMzU0Mi0xLjU5MjIgMS43OTExLTIuMjEzNXMwLjc0MjctMS4xNzk1IDAuOTE3NC0xLjY3NDZjMC4xODQ1LTAuNTA0OSAwLjI3NjctMC45OTUxIDAuMjc2Ny0xLjQ3MDggMC0wLjY2OTktMC4xMjYyLTEuMjU3Mi0wLjM3ODYtMS43NjIxLTAuMjQyNy0wLjUxNDUtMC42MDE5LTAuOTE3NC0xLjA3NzYtMS4yMDg2LTAuNDc1Ny0wLjMwMS0xLjA1MzMtMC40NTE1LTEuNzMyOS0wLjQ1MTUtMC43ODY0IDAtMS40NDY1IDAuMTY5OS0xLjk4MDUgMC41MDk3LTAuNTMzOSAwLjMzOTgtMC45MzY4IDAuODEwNi0xLjIwODcgMS40MTI2LTAuMjcxOCAwLjU5MjEtMC40MDc3IDEuMjcxNy0wLjQwNzcgMi4wMzg3aC0zLjUwOTVjMC0xLjIzMyAwLjI4MTUtMi4zNTkxIDAuODQ0Ni0zLjM3ODUgMC41NjMxLTEuMDI5IDEuMzc4Ni0xLjg0NDUgMi40NDY1LTIuNDQ2NCAxLjA2NzktMC42MTE3IDIuMzU0Mi0wLjkxNzUgMy44NTktMC45MTc1IDEuNDE3NCAwIDIuNjIxMiAwLjIzNzkgMy42MTE0IDAuNzEzNnMxLjc0MjYgMS4xNTA0IDIuMjU3MiAyLjAyNDFjMC41MjQyIDAuODczOCAwLjc4NjMgMS45MDc3IDAuNzg2MyAzLjEwMTggMCAwLjY2MDItMC4xMDY4IDEuMzE1NS0wLjMyMDMgMS45NjU5LTAuMjEzNiAwLjY1MDUtMC41MTk0IDEuMzAwOS0wLjkxNzUgMS45NTE0LTAuMzg4MyAwLjY0MDctMC44NDk0IDEuMjg2My0xLjM4MzQgMS45MzY3LTAuNTMzOSAwLjY0MDgtMS4xMjEzIDEuMjkxMi0xLjc2MiAxLjk1MTRsLTQuNTg3MSA1LjA1MzFoOS43ODU4em0yLjQ5MjUtMTQuODFjMC0wLjcwODcgMC4xNzQ3LTEuMzU5MiAwLjUyNDItMS45NTE0czAuODE1NS0xLjA2MyAxLjM5OC0xLjQxMjVjMC41OTIyLTAuMzU5MiAxLjIzMjktMC41Mzg4IDEuOTIyMi0wLjUzODggMC42OTkgMCAxLjMzNDkgMC4xNzk2IDEuOTA3NyAwLjUzODggMC41NzI4IDAuMzQ5NSAxLjAyOTEgMC44MjAzIDEuMzY4OCAxLjQxMjUgMC4zNDk1IDAuNTkyMiAwLjUyNDMgMS4yNDI3IDAuNTI0MyAxLjk1MTRzLTAuMTc0OCAxLjM1OTEtMC41MjQzIDEuOTUxM2MtMC4zMzk3IDAuNTgyNS0wLjc5NiAxLjA0MzYtMS4zNjg4IDEuMzgzNHMtMS4yMDg3IDAuNTA5Ny0xLjkwNzcgMC41MDk3Yy0wLjY4OTMgMC0xLjMzLTAuMTY5OS0xLjkyMjItMC41MDk3LTAuNTgyNS0wLjMzOTgtMS4wNDg1LTAuODAwOS0xLjM5OC0xLjM4MzQtMC4zNDk1LTAuNTkyMi0wLjUyNDItMS4yNDI2LTAuNTI0Mi0xLjk1MTN6bTEuOTY1OSAwYzAgMC41MjQyIDAuMTg0NSAwLjk2NTkgMC41NTM0IDEuMzI1MSAwLjM2ODkgMC4zNDk1IDAuODEwNiAwLjUyNDMgMS4zMjUxIDAuNTI0MyAwLjUxNDYgMCAwLjk0NjYtMC4xNzQ4IDEuMjk2MS0wLjUyNDNzMC41MjQyLTAuNzkxMiAwLjUyNDItMS4zMjUxYzAtMC41NDM3LTAuMTc0Ny0wLjk5NTEtMC41MjQyLTEuMzU0M3MtMC43ODE1LTAuNTM4OC0xLjI5NjEtMC41Mzg4Yy0wLjUxNDUgMC0wLjk1NjIgMC4xNzk2LTEuMzI1MSAwLjUzODhzLTAuNTUzNCAwLjgxMDYtMC41NTM0IDEuMzU0M3ptMjEuNzI5IDEwLjcwM2gzLjY0MDZjLTAuMTE2NSAxLjM4ODMtMC41MDQ4IDIuNjI2MS0xLjE2NSAzLjcxMzQtMC42NjAxIDEuMDc3Ni0xLjU4NzMgMS45MjcxLTIuNzgxNCAyLjU0ODRzLTIuNjQ1NCAwLjkzMi00LjM1NDEgMC45MzJjLTEuMzEwNiAwLTIuNDkwMS0wLjIzMy0zLjUzODYtMC42OTktMS4wNDg1LTAuNDc1Ny0xLjk0NjUtMS4xNDU2LTIuNjk0LTIuMDA5Ni0wLjc0NzYtMC44NzM3LTEuMzIwNC0xLjkyNzEtMS43MTg0LTMuMTYtMC4zODgzLTEuMjMyOS0wLjU4MjUtMi42MTE1LTAuNTgyNS00LjEzNTd2LTEuNzYyYzAtMS41MjQyIDAuMTk5LTIuOTAyOCAwLjU5NzEtNC4xMzU3IDAuNDA3Ny0xLjIzMjkgMC45OTAyLTIuMjg2MyAxLjc0NzQtMy4xNiAwLjc1NzMtMC44ODM1IDEuNjY1LTEuNTU4MiAyLjcyMzItMi4wMjQyIDEuMDY3OS0wLjQ2NiAyLjI2NjktMC42OTkgMy41OTY5LTAuNjk5IDEuNjg5MiAwIDMuMTE2MyAwLjMxMDcgNC4yODEzIDAuOTMyczIuMDY3OCAxLjQ4MDUgMi43MDg2IDIuNTc3NWMwLjY1MDQgMS4wOTcxIDEuMDQ4NCAyLjM1NDMgMS4xOTQxIDMuNzcxN2gtMy42NDA2Yy0wLjA5NzEtMC45MTI2LTAuMzEwNy0xLjY5NDEtMC42NDA3LTIuMzQ0Ni0wLjMyMDQtMC42NTA0LTAuNzk2MS0xLjE0NTUtMS40MjcxLTEuNDg1My0wLjYzMTEtMC4zNDk1LTEuNDU2My0wLjUyNDItMi40NzU2LTAuNTI0Mi0wLjgzNDkgMC0xLjU2MyAwLjE1NTMtMi4xODQ0IDAuNDY1OS0wLjYyMTMgMC4zMTA3LTEuMTQwNyAwLjc2Ny0xLjU1ODEgMS4zNjg5LTAuNDE3NSAwLjYwMTktMC43MzMgMS4zNDQ2LTAuOTQ2NiAyLjIyOC0wLjIwMzkgMC44NzM4LTAuMzA1OCAxLjg3MzctMC4zMDU4IDIuOTk5OXYxLjc5MTFjMCAxLjA2NzkgMC4wOTIyIDIuMDM4NyAwLjI3NjcgMi45MTI1IDAuMTk0MiAwLjg2NCAwLjQ4NTQgMS42MDY3IDAuODczNyAyLjIyOCAwLjM5ODEgMC42MjEzIDAuOTAyOSAxLjEwMTkgMS41MTQ1IDEuNDQxNyAwLjYxMTYgMC4zMzk3IDEuMzQ0NiAwLjUwOTYgMi4xOTg5IDAuNTA5NiAxLjAzODggMCAxLjg3ODUtMC4xNjUgMi41MTkzLTAuNDk1MSAwLjY1MDQtMC4zMzAxIDEuMTQwNy0wLjgxMDYgMS40NzA4LTEuNDQxNiAwLjMzOTgtMC42NDA4IDAuNTYzLTEuNDIyMyAwLjY2OTgtMi4zNDQ2eiIgZmlsbC1vcGFjaXR5PSIuODciLz4KICA8L2c+CiA8L2c+CiA8ZGVmcz4KICA8ZmlsdGVyIGlkPSJmaWx0ZXIwX2RfMTE0Ml8yMDM5NTQiIHg9Ii45MTE3NiIgeT0iLjIwNTg4IiB3aWR0aD0iMTI2LjE4IiBoZWlnaHQ9IjEyNi4xOCIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiPgogICA8ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPgogICA8ZmVDb2xvck1hdHJpeCBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0iaGFyZEFscGhhIiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDEyNyAwIi8+CiAgIDxmZU9mZnNldCBkeT0iMi4yOTQxMiIvPgogICA8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIyLjI5NDEyIi8+CiAgIDxmZUNvbXBvc2l0ZSBpbjI9ImhhcmRBbHBoYSIgb3BlcmF0b3I9Im91dCIvPgogICA8ZmVDb2xvck1hdHJpeCB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAuMDQgMCIvPgogICA8ZmVCbGVuZCBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3dfMTE0Ml8yMDM5NTQiLz4KICAgPGZlQmxlbmQgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iZWZmZWN0MV9kcm9wU2hhZG93XzExNDJfMjAzOTU0IiByZXN1bHQ9InNoYXBlIi8+CiAgPC9maWx0ZXI+CiA8L2RlZnM+Cjwvc3ZnPgo=", "description": "Designed to display single value of the selected attribute or timeseries data. Widget styles are customizable.", "descriptor": { "type": "latest", - "sizeX": 2.5, - "sizeY": 2.5, + "sizeX": 3, + "sizeY": 3, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px'\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n absoluteHeader: true\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", - "settingsDirective": "", + "settingsDirective": "tb-value-card-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-value-card-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\"}" @@ -250,7 +250,7 @@ { "alias": "horizontal_value_card", "name": "Horizontal value card", - "image": null, + "image": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzk5IiBoZWlnaHQ9IjEwOCIgdmlld0JveD0iMCAwIDM5OSAxMDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2RfMTI0Nl80NDQ0NykiPgo8cmVjdCB4PSI4IiB5PSI0IiB3aWR0aD0iMzgzIiBoZWlnaHQ9IjkyIiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTU3LjAwMDEgNTEuNjY2N1YzOC4zMzM0QzU3LjAwMDEgMzUuNTY2NyA1NC43NjY3IDMzLjMzMzQgNTIuMDAwMSAzMy4zMzM0QzQ5LjIzMzQgMzMuMzMzNCA0Ny4wMDAxIDM1LjU2NjcgNDcuMDAwMSAzOC4zMzM0VjUxLjY2NjdDNDQuOTgzNCA1My4xODM0IDQzLjY2NjcgNTUuNjE2NyA0My42NjY3IDU4LjMzMzRDNDMuNjY2NyA2Mi45MzM0IDQ3LjQwMDEgNjYuNjY2NyA1Mi4wMDAxIDY2LjY2NjdDNTYuNjAwMSA2Ni42NjY3IDYwLjMzMzQgNjIuOTMzNCA2MC4zMzM0IDU4LjMzMzRDNjAuMzMzNCA1NS42MTY3IDU5LjAxNjcgNTMuMTgzNCA1Ny4wMDAxIDUxLjY2NjdaTTUwLjMzMzQgMzguMzMzNEM1MC4zMzM0IDM3LjQxNjcgNTEuMDgzNCAzNi42NjY3IDUyLjAwMDEgMzYuNjY2N0M1Mi45MTY3IDM2LjY2NjcgNTMuNjY2NyAzNy40MTY3IDUzLjY2NjcgMzguMzMzNEg1Mi4wMDAxVjQwSDUzLjY2NjdWNDMuMzMzNEg1Mi4wMDAxVjQ1SDUzLjY2NjdWNDguMzMzNEg1MC4zMzM0VjM4LjMzMzRaIiBmaWxsPSIjNTQ2OUZGIi8+CjxwYXRoIGQ9Ik04NS44MzU5IDM1LjYyNVY0N0g4My44OTA2VjM1LjYyNUg4NS44MzU5Wk04OS40MDYyIDM1LjYyNVYzNy4xODc1SDgwLjM1MTZWMzUuNjI1SDg5LjQwNjJaTTkzLjk0NTMgNDcuMTU2MkM5My4zMjAzIDQ3LjE1NjIgOTIuNzU1MiA0Ny4wNTQ3IDkyLjI1IDQ2Ljg1MTZDOTEuNzUgNDYuNjQzMiA5MS4zMjI5IDQ2LjM1NDIgOTAuOTY4OCA0NS45ODQ0QzkwLjYxOTggNDUuNjE0NiA5MC4zNTE2IDQ1LjE3OTcgOTAuMTY0MSA0NC42Nzk3Qzg5Ljk3NjYgNDQuMTc5NyA4OS44ODI4IDQzLjY0MDYgODkuODgyOCA0My4wNjI1VjQyLjc1Qzg5Ljg4MjggNDIuMDg4NSA4OS45NzkyIDQxLjQ4OTYgOTAuMTcxOSA0MC45NTMxQzkwLjM2NDYgNDAuNDE2NyA5MC42MzI4IDM5Ljk1ODMgOTAuOTc2NiAzOS41NzgxQzkxLjMyMDMgMzkuMTkyNyA5MS43MjY2IDM4Ljg5ODQgOTIuMTk1MyAzOC42OTUzQzkyLjY2NDEgMzguNDkyMiA5My4xNzE5IDM4LjM5MDYgOTMuNzE4OCAzOC4zOTA2Qzk0LjMyMjkgMzguMzkwNiA5NC44NTE2IDM4LjQ5MjIgOTUuMzA0NyAzOC42OTUzQzk1Ljc1NzggMzguODk4NCA5Ni4xMzI4IDM5LjE4NDkgOTYuNDI5NyAzOS41NTQ3Qzk2LjczMTggMzkuOTE5MyA5Ni45NTU3IDQwLjM1NDIgOTcuMTAxNiA0MC44NTk0Qzk3LjI1MjYgNDEuMzY0NiA5Ny4zMjgxIDQxLjkyMTkgOTcuMzI4MSA0Mi41MzEyVjQzLjMzNTlIOTAuNzk2OVY0MS45ODQ0SDk1LjQ2ODhWNDEuODM1OUM5NS40NTgzIDQxLjQ5NzQgOTUuMzkwNiA0MS4xNzk3IDk1LjI2NTYgNDAuODgyOEM5NS4xNDU4IDQwLjU4NTkgOTQuOTYwOSA0MC4zNDY0IDk0LjcxMDkgNDAuMTY0MUM5NC40NjA5IDM5Ljk4MTggOTQuMTI3NiAzOS44OTA2IDkzLjcxMDkgMzkuODkwNkM5My4zOTg0IDM5Ljg5MDYgOTMuMTE5OCAzOS45NTgzIDkyLjg3NSA0MC4wOTM4QzkyLjYzNTQgNDAuMjI0IDkyLjQzNDkgNDAuNDE0MSA5Mi4yNzM0IDQwLjY2NDFDOTIuMTEyIDQwLjkxNDEgOTEuOTg3IDQxLjIxNjEgOTEuODk4NCA0MS41NzAzQzkxLjgxNTEgNDEuOTE5MyA5MS43NzM0IDQyLjMxMjUgOTEuNzczNCA0Mi43NVY0My4wNjI1QzkxLjc3MzQgNDMuNDMyMyA5MS44MjI5IDQzLjc3NiA5MS45MjE5IDQ0LjA5MzhDOTIuMDI2IDQ0LjQwNjIgOTIuMTc3MSA0NC42Nzk3IDkyLjM3NSA0NC45MTQxQzkyLjU3MjkgNDUuMTQ4NCA5Mi44MTI1IDQ1LjMzMzMgOTMuMDkzOCA0NS40Njg4QzkzLjM3NSA0NS41OTkgOTMuNjk1MyA0NS42NjQxIDk0LjA1NDcgNDUuNjY0MUM5NC41MDc4IDQ1LjY2NDEgOTQuOTExNSA0NS41NzI5IDk1LjI2NTYgNDUuMzkwNkM5NS42MTk4IDQ1LjIwODMgOTUuOTI3MSA0NC45NTA1IDk2LjE4NzUgNDQuNjE3Mkw5Ny4xNzk3IDQ1LjU3ODFDOTYuOTk3NCA0NS44NDM4IDk2Ljc2MDQgNDYuMDk5IDk2LjQ2ODggNDYuMzQzOEM5Ni4xNzcxIDQ2LjU4MzMgOTUuODIwMyA0Ni43Nzg2IDk1LjM5ODQgNDYuOTI5N0M5NC45ODE4IDQ3LjA4MDcgOTQuNDk3NCA0Ny4xNTYyIDkzLjk0NTMgNDcuMTU2MlpNMTAwLjkzIDQwLjI2NTZWNDdIOTkuMDQ2OVYzOC41NDY5SDEwMC44MkwxMDAuOTMgNDAuMjY1NlpNMTAwLjYyNSA0Mi40NjA5TDk5Ljk4NDQgNDIuNDUzMUM5OS45ODQ0IDQxLjg2OTggMTAwLjA1NyA0MS4zMzA3IDEwMC4yMDMgNDAuODM1OUMxMDAuMzQ5IDQwLjM0MTEgMTAwLjU2MiAzOS45MTE1IDEwMC44NDQgMzkuNTQ2OUMxMDEuMTI1IDM5LjE3NzEgMTAxLjQ3NCAzOC44OTMyIDEwMS44OTEgMzguNjk1M0MxMDIuMzEyIDM4LjQ5MjIgMTAyLjc5OSAzOC4zOTA2IDEwMy4zNTIgMzguMzkwNkMxMDMuNzM3IDM4LjM5MDYgMTA0LjA4OSAzOC40NDc5IDEwNC40MDYgMzguNTYyNUMxMDQuNzI5IDM4LjY3MTkgMTA1LjAwOCAzOC44NDY0IDEwNS4yNDIgMzkuMDg1OUMxMDUuNDgyIDM5LjMyNTUgMTA1LjY2NCAzOS42MzI4IDEwNS43ODkgNDAuMDA3OEMxMDUuOTE5IDQwLjM4MjggMTA1Ljk4NCA0MC44MzU5IDEwNS45ODQgNDEuMzY3MlY0N0gxMDQuMTAyVjQxLjUzMTJDMTA0LjEwMiA0MS4xMTk4IDEwNC4wMzkgNDAuNzk2OSAxMDMuOTE0IDQwLjU2MjVDMTAzLjc5NCA0MC4zMjgxIDEwMy42MiA0MC4xNjE1IDEwMy4zOTEgNDAuMDYyNUMxMDMuMTY3IDM5Ljk1ODMgMTAyLjg5OCAzOS45MDYyIDEwMi41ODYgMzkuOTA2MkMxMDIuMjMyIDM5LjkwNjIgMTAxLjkzIDM5Ljk3NCAxMDEuNjggNDAuMTA5NEMxMDEuNDM1IDQwLjI0NDggMTAxLjIzNCA0MC40Mjk3IDEwMS4wNzggNDAuNjY0MUMxMDAuOTIyIDQwLjg5ODQgMTAwLjgwNyA0MS4xNjkzIDEwMC43MzQgNDEuNDc2NkMxMDAuNjYxIDQxLjc4MzkgMTAwLjYyNSA0Mi4xMTIgMTAwLjYyNSA0Mi40NjA5Wk0xMDUuODY3IDQxLjk2MDlMMTA0Ljk4NCA0Mi4xNTYyQzEwNC45ODQgNDEuNjQ1OCAxMDUuMDU1IDQxLjE2NDEgMTA1LjE5NSA0MC43MTA5QzEwNS4zNDEgNDAuMjUyNiAxMDUuNTUyIDM5Ljg1MTYgMTA1LjgyOCAzOS41MDc4QzEwNi4xMDkgMzkuMTU4OSAxMDYuNDU2IDM4Ljg4NTQgMTA2Ljg2NyAzOC42ODc1QzEwNy4yNzkgMzguNDg5NiAxMDcuNzUgMzguMzkwNiAxMDguMjgxIDM4LjM5MDZDMTA4LjcxNCAzOC4zOTA2IDEwOS4wOTkgMzguNDUwNSAxMDkuNDM4IDM4LjU3MDNDMTA5Ljc4MSAzOC42ODQ5IDExMC4wNzMgMzguODY3MiAxMTAuMzEyIDM5LjExNzJDMTEwLjU1MiAzOS4zNjcyIDExMC43MzQgMzkuNjkyNyAxMTAuODU5IDQwLjA5MzhDMTEwLjk4NCA0MC40ODk2IDExMS4wNDcgNDAuOTY4OCAxMTEuMDQ3IDQxLjUzMTJWNDdIMTA5LjE1NlY0MS41MjM0QzEwOS4xNTYgNDEuMDk2NCAxMDkuMDk0IDQwLjc2NTYgMTA4Ljk2OSA0MC41MzEyQzEwOC44NDkgNDAuMjk2OSAxMDguNjc3IDQwLjEzNTQgMTA4LjQ1MyA0MC4wNDY5QzEwOC4yMjkgMzkuOTUzMSAxMDcuOTYxIDM5LjkwNjIgMTA3LjY0OCAzOS45MDYyQzEwNy4zNTcgMzkuOTA2MiAxMDcuMDk5IDM5Ljk2MDkgMTA2Ljg3NSA0MC4wNzAzQzEwNi42NTYgNDAuMTc0NSAxMDYuNDcxIDQwLjMyMjkgMTA2LjMyIDQwLjUxNTZDMTA2LjE2OSA0MC43MDMxIDEwNi4wNTUgNDAuOTE5MyAxMDUuOTc3IDQxLjE2NDFDMTA1LjkwNCA0MS40MDg5IDEwNS44NjcgNDEuNjc0NSAxMDUuODY3IDQxLjk2MDlaTTExNS4xMjUgNDAuMTcxOVY1MC4yNUgxMTMuMjQyVjM4LjU0NjlIMTE0Ljk3N0wxMTUuMTI1IDQwLjE3MTlaTTEyMC42MzMgNDIuNjk1M1Y0Mi44NTk0QzEyMC42MzMgNDMuNDc0IDEyMC41NiA0NC4wNDQzIDEyMC40MTQgNDQuNTcwM0MxMjAuMjczIDQ1LjA5MTEgMTIwLjA2MiA0NS41NDY5IDExOS43ODEgNDUuOTM3NUMxMTkuNTA1IDQ2LjMyMjkgMTE5LjE2NCA0Ni42MjI0IDExOC43NTggNDYuODM1OUMxMTguMzUyIDQ3LjA0OTUgMTE3Ljg4MyA0Ny4xNTYyIDExNy4zNTIgNDcuMTU2MkMxMTYuODI2IDQ3LjE1NjIgMTE2LjM2NSA0Ny4wNTk5IDExNS45NjkgNDYuODY3MkMxMTUuNTc4IDQ2LjY2OTMgMTE1LjI0NyA0Ni4zOTA2IDExNC45NzcgNDYuMDMxMkMxMTQuNzA2IDQ1LjY3MTkgMTE0LjQ4NyA0NS4yNSAxMTQuMzIgNDQuNzY1NkMxMTQuMTU5IDQ0LjI3NiAxMTQuMDQ0IDQzLjczOTYgMTEzLjk3NyA0My4xNTYyVjQyLjUyMzRDMTE0LjA0NCA0MS45MDM2IDExNC4xNTkgNDEuMzQxMSAxMTQuMzIgNDAuODM1OUMxMTQuNDg3IDQwLjMzMDcgMTE0LjcwNiAzOS44OTU4IDExNC45NzcgMzkuNTMxMkMxMTUuMjQ3IDM5LjE2NjcgMTE1LjU3OCAzOC44ODU0IDExNS45NjkgMzguNjg3NUMxMTYuMzU5IDM4LjQ4OTYgMTE2LjgxNSAzOC4zOTA2IDExNy4zMzYgMzguMzkwNkMxMTcuODY3IDM4LjM5MDYgMTE4LjMzOSAzOC40OTQ4IDExOC43NSAzOC43MDMxQzExOS4xNjEgMzguOTA2MiAxMTkuNTA4IDM5LjE5NzkgMTE5Ljc4OSAzOS41NzgxQzEyMC4wNyAzOS45NTMxIDEyMC4yODEgNDAuNDA2MiAxMjAuNDIyIDQwLjkzNzVDMTIwLjU2MiA0MS40NjM1IDEyMC42MzMgNDIuMDQ5NSAxMjAuNjMzIDQyLjY5NTNaTTExOC43NSA0Mi44NTk0VjQyLjY5NTNDMTE4Ljc1IDQyLjMwNDcgMTE4LjcxNCA0MS45NDI3IDExOC42NDEgNDEuNjA5NEMxMTguNTY4IDQxLjI3MDggMTE4LjQ1MyA0MC45NzQgMTE4LjI5NyA0MC43MTg4QzExOC4xNDEgNDAuNDYzNSAxMTcuOTQgNDAuMjY1NiAxMTcuNjk1IDQwLjEyNUMxMTcuNDU2IDM5Ljk3OTIgMTE3LjE2NyAzOS45MDYyIDExNi44MjggMzkuOTA2MkMxMTYuNDk1IDM5LjkwNjIgMTE2LjIwOCAzOS45NjM1IDExNS45NjkgNDAuMDc4MUMxMTUuNzI5IDQwLjE4NzUgMTE1LjUyOSA0MC4zNDExIDExNS4zNjcgNDAuNTM5MUMxMTUuMjA2IDQwLjczNyAxMTUuMDgxIDQwLjk2ODggMTE0Ljk5MiA0MS4yMzQ0QzExNC45MDQgNDEuNDk0OCAxMTQuODQxIDQxLjc3ODYgMTE0LjgwNSA0Mi4wODU5VjQzLjYwMTZDMTE0Ljg2NyA0My45NzY2IDExNC45NzQgNDQuMzIwMyAxMTUuMTI1IDQ0LjYzMjhDMTE1LjI3NiA0NC45NDUzIDExNS40OSA0NS4xOTUzIDExNS43NjYgNDUuMzgyOEMxMTYuMDQ3IDQ1LjU2NTEgMTE2LjQwNiA0NS42NTYyIDExNi44NDQgNDUuNjU2MkMxMTcuMTgyIDQ1LjY1NjIgMTE3LjQ3MSA0NS41ODMzIDExNy43MTEgNDUuNDM3NUMxMTcuOTUxIDQ1LjI5MTcgMTE4LjE0NiA0NS4wOTExIDExOC4yOTcgNDQuODM1OUMxMTguNDUzIDQ0LjU3NTUgMTE4LjU2OCA0NC4yNzYgMTE4LjY0MSA0My45Mzc1QzExOC43MTQgNDMuNTk5IDExOC43NSA0My4yMzk2IDExOC43NSA0Mi44NTk0Wk0xMjYuMjExIDQ3LjE1NjJDMTI1LjU4NiA0Ny4xNTYyIDEyNS4wMjEgNDcuMDU0NyAxMjQuNTE2IDQ2Ljg1MTZDMTI0LjAxNiA0Ni42NDMyIDEyMy41ODkgNDYuMzU0MiAxMjMuMjM0IDQ1Ljk4NDRDMTIyLjg4NSA0NS42MTQ2IDEyMi42MTcgNDUuMTc5NyAxMjIuNDMgNDQuNjc5N0MxMjIuMjQyIDQ0LjE3OTcgMTIyLjE0OCA0My42NDA2IDEyMi4xNDggNDMuMDYyNVY0Mi43NUMxMjIuMTQ4IDQyLjA4ODUgMTIyLjI0NSA0MS40ODk2IDEyMi40MzggNDAuOTUzMUMxMjIuNjMgNDAuNDE2NyAxMjIuODk4IDM5Ljk1ODMgMTIzLjI0MiAzOS41NzgxQzEyMy41ODYgMzkuMTkyNyAxMjMuOTkyIDM4Ljg5ODQgMTI0LjQ2MSAzOC42OTUzQzEyNC45MyAzOC40OTIyIDEyNS40MzggMzguMzkwNiAxMjUuOTg0IDM4LjM5MDZDMTI2LjU4OSAzOC4zOTA2IDEyNy4xMTcgMzguNDkyMiAxMjcuNTcgMzguNjk1M0MxMjguMDIzIDM4Ljg5ODQgMTI4LjM5OCAzOS4xODQ5IDEyOC42OTUgMzkuNTU0N0MxMjguOTk3IDM5LjkxOTMgMTI5LjIyMSA0MC4zNTQyIDEyOS4zNjcgNDAuODU5NEMxMjkuNTE4IDQxLjM2NDYgMTI5LjU5NCA0MS45MjE5IDEyOS41OTQgNDIuNTMxMlY0My4zMzU5SDEyMy4wNjJWNDEuOTg0NEgxMjcuNzM0VjQxLjgzNTlDMTI3LjcyNCA0MS40OTc0IDEyNy42NTYgNDEuMTc5NyAxMjcuNTMxIDQwLjg4MjhDMTI3LjQxMSA0MC41ODU5IDEyNy4yMjcgNDAuMzQ2NCAxMjYuOTc3IDQwLjE2NDFDMTI2LjcyNyAzOS45ODE4IDEyNi4zOTMgMzkuODkwNiAxMjUuOTc3IDM5Ljg5MDZDMTI1LjY2NCAzOS44OTA2IDEyNS4zODUgMzkuOTU4MyAxMjUuMTQxIDQwLjA5MzhDMTI0LjkwMSA0MC4yMjQgMTI0LjcwMSA0MC40MTQxIDEyNC41MzkgNDAuNjY0MUMxMjQuMzc4IDQwLjkxNDEgMTI0LjI1MyA0MS4yMTYxIDEyNC4xNjQgNDEuNTcwM0MxMjQuMDgxIDQxLjkxOTMgMTI0LjAzOSA0Mi4zMTI1IDEyNC4wMzkgNDIuNzVWNDMuMDYyNUMxMjQuMDM5IDQzLjQzMjMgMTI0LjA4OSA0My43NzYgMTI0LjE4OCA0NC4wOTM4QzEyNC4yOTIgNDQuNDA2MiAxMjQuNDQzIDQ0LjY3OTcgMTI0LjY0MSA0NC45MTQxQzEyNC44MzkgNDUuMTQ4NCAxMjUuMDc4IDQ1LjMzMzMgMTI1LjM1OSA0NS40Njg4QzEyNS42NDEgNDUuNTk5IDEyNS45NjEgNDUuNjY0MSAxMjYuMzIgNDUuNjY0MUMxMjYuNzczIDQ1LjY2NDEgMTI3LjE3NyA0NS41NzI5IDEyNy41MzEgNDUuMzkwNkMxMjcuODg1IDQ1LjIwODMgMTI4LjE5MyA0NC45NTA1IDEyOC40NTMgNDQuNjE3MkwxMjkuNDQ1IDQ1LjU3ODFDMTI5LjI2MyA0NS44NDM4IDEyOS4wMjYgNDYuMDk5IDEyOC43MzQgNDYuMzQzOEMxMjguNDQzIDQ2LjU4MzMgMTI4LjA4NiA0Ni43Nzg2IDEyNy42NjQgNDYuOTI5N0MxMjcuMjQ3IDQ3LjA4MDcgMTI2Ljc2MyA0Ny4xNTYyIDEyNi4yMTEgNDcuMTU2MlpNMTMzLjIwMyA0MC4xNTYyVjQ3SDEzMS4zMlYzOC41NDY5SDEzMy4xMTdMMTMzLjIwMyA0MC4xNTYyWk0xMzUuNzg5IDM4LjQ5MjJMMTM1Ljc3MyA0MC4yNDIyQzEzNS42NTkgNDAuMjIxNCAxMzUuNTM0IDQwLjIwNTcgMTM1LjM5OCA0MC4xOTUzQzEzNS4yNjggNDAuMTg0OSAxMzUuMTM4IDQwLjE3OTcgMTM1LjAwOCA0MC4xNzk3QzEzNC42ODUgNDAuMTc5NyAxMzQuNDAxIDQwLjIyNjYgMTM0LjE1NiA0MC4zMjAzQzEzMy45MTEgNDAuNDA4OSAxMzMuNzA2IDQwLjUzOTEgMTMzLjUzOSA0MC43MTA5QzEzMy4zNzggNDAuODc3NiAxMzMuMjUzIDQxLjA4MDcgMTMzLjE2NCA0MS4zMjAzQzEzMy4wNzYgNDEuNTU5OSAxMzMuMDIzIDQxLjgyODEgMTMzLjAwOCA0Mi4xMjVMMTMyLjU3OCA0Mi4xNTYyQzEzMi41NzggNDEuNjI1IDEzMi42MyA0MS4xMzI4IDEzMi43MzQgNDAuNjc5N0MxMzIuODM5IDQwLjIyNjYgMTMyLjk5NSAzOS44MjgxIDEzMy4yMDMgMzkuNDg0NEMxMzMuNDE3IDM5LjE0MDYgMTMzLjY4MiAzOC44NzI0IDEzNCAzOC42Nzk3QzEzNC4zMjMgMzguNDg3IDEzNC42OTUgMzguMzkwNiAxMzUuMTE3IDM4LjM5MDZDMTM1LjIzMiAzOC4zOTA2IDEzNS4zNTQgMzguNDAxIDEzNS40ODQgMzguNDIxOUMxMzUuNjIgMzguNDQyNyAxMzUuNzIxIDM4LjQ2NjEgMTM1Ljc4OSAzOC40OTIyWk0xNDEuNzAzIDQ1LjMwNDdWNDEuMjczNEMxNDEuNzAzIDQwLjk3MTQgMTQxLjY0OCA0MC43MTA5IDE0MS41MzkgNDAuNDkyMkMxNDEuNDMgNDAuMjczNCAxNDEuMjYzIDQwLjEwNDIgMTQxLjAzOSAzOS45ODQ0QzE0MC44MiAzOS44NjQ2IDE0MC41NDQgMzkuODA0NyAxNDAuMjExIDM5LjgwNDdDMTM5LjkwNCAzOS44MDQ3IDEzOS42MzggMzkuODU2OCAxMzkuNDE0IDM5Ljk2MDlDMTM5LjE5IDQwLjA2NTEgMTM5LjAxNiA0MC4yMDU3IDEzOC44OTEgNDAuMzgyOEMxMzguNzY2IDQwLjU1OTkgMTM4LjcwMyA0MC43NjA0IDEzOC43MDMgNDAuOTg0NEgxMzYuODI4QzEzNi44MjggNDAuNjUxIDEzNi45MDkgNDAuMzI4MSAxMzcuMDcgNDAuMDE1NkMxMzcuMjMyIDM5LjcwMzEgMTM3LjQ2NiAzOS40MjQ1IDEzNy43NzMgMzkuMTc5N0MxMzguMDgxIDM4LjkzNDkgMTM4LjQ0OCAzOC43NDIyIDEzOC44NzUgMzguNjAxNkMxMzkuMzAyIDM4LjQ2MDkgMTM5Ljc4MSAzOC4zOTA2IDE0MC4zMTIgMzguMzkwNkMxNDAuOTQ4IDM4LjM5MDYgMTQxLjUxIDM4LjQ5NzQgMTQyIDM4LjcxMDlDMTQyLjQ5NSAzOC45MjQ1IDE0Mi44ODMgMzkuMjQ3NCAxNDMuMTY0IDM5LjY3OTdDMTQzLjQ1MSA0MC4xMDY4IDE0My41OTQgNDAuNjQzMiAxNDMuNTk0IDQxLjI4OTFWNDUuMDQ2OUMxNDMuNTk0IDQ1LjQzMjMgMTQzLjYyIDQ1Ljc3ODYgMTQzLjY3MiA0Ni4wODU5QzE0My43MjkgNDYuMzg4IDE0My44MSA0Ni42NTEgMTQzLjkxNCA0Ni44NzVWNDdIMTQxLjk4NEMxNDEuODk2IDQ2Ljc5NjkgMTQxLjgyNiA0Ni41MzkxIDE0MS43NzMgNDYuMjI2NkMxNDEuNzI3IDQ1LjkwODkgMTQxLjcwMyA0NS42MDE2IDE0MS43MDMgNDUuMzA0N1pNMTQxLjk3NyA0MS44NTk0TDE0MS45OTIgNDMuMDIzNEgxNDAuNjQxQzE0MC4yOTIgNDMuMDIzNCAxMzkuOTg0IDQzLjA1NzMgMTM5LjcxOSA0My4xMjVDMTM5LjQ1MyA0My4xODc1IDEzOS4yMzIgNDMuMjgxMiAxMzkuMDU1IDQzLjQwNjJDMTM4Ljg3OCA0My41MzEyIDEzOC43NDUgNDMuNjgyMyAxMzguNjU2IDQzLjg1OTRDMTM4LjU2OCA0NC4wMzY1IDEzOC41MjMgNDQuMjM3IDEzOC41MjMgNDQuNDYwOUMxMzguNTIzIDQ0LjY4NDkgMTM4LjU3NiA0NC44OTA2IDEzOC42OCA0NS4wNzgxQzEzOC43ODQgNDUuMjYwNCAxMzguOTM1IDQ1LjQwMzYgMTM5LjEzMyA0NS41MDc4QzEzOS4zMzYgNDUuNjEyIDEzOS41ODEgNDUuNjY0MSAxMzkuODY3IDQ1LjY2NDFDMTQwLjI1MyA0NS42NjQxIDE0MC41ODkgNDUuNTg1OSAxNDAuODc1IDQ1LjQyOTdDMTQxLjE2NyA0NS4yNjgyIDE0MS4zOTYgNDUuMDcyOSAxNDEuNTYyIDQ0Ljg0MzhDMTQxLjcyOSA0NC42MDk0IDE0MS44MTggNDQuMzg4IDE0MS44MjggNDQuMTc5N0wxNDIuNDM4IDQ1LjAxNTZDMTQyLjM3NSA0NS4yMjkyIDE0Mi4yNjggNDUuNDU4MyAxNDIuMTE3IDQ1LjcwMzFDMTQxLjk2NiA0NS45NDc5IDE0MS43NjggNDYuMTgyMyAxNDEuNTIzIDQ2LjQwNjJDMTQxLjI4NCA0Ni42MjUgMTQwLjk5NSA0Ni44MDQ3IDE0MC42NTYgNDYuOTQ1M0MxNDAuMzIzIDQ3LjA4NTkgMTM5LjkzOCA0Ny4xNTYyIDEzOS41IDQ3LjE1NjJDMTM4Ljk0OCA0Ny4xNTYyIDEzOC40NTYgNDcuMDQ2OSAxMzguMDIzIDQ2LjgyODFDMTM3LjU5MSA0Ni42MDQyIDEzNy4yNTMgNDYuMzA0NyAxMzcuMDA4IDQ1LjkyOTdDMTM2Ljc2MyA0NS41NDk1IDEzNi42NDEgNDUuMTE5OCAxMzYuNjQxIDQ0LjY0MDZDMTM2LjY0MSA0NC4xOTI3IDEzNi43MjQgNDMuNzk2OSAxMzYuODkxIDQzLjQ1MzFDMTM3LjA2MiA0My4xMDQyIDEzNy4zMTIgNDIuODEyNSAxMzcuNjQxIDQyLjU3ODFDMTM3Ljk3NCA0Mi4zNDM4IDEzOC4zOCA0Mi4xNjY3IDEzOC44NTkgNDIuMDQ2OUMxMzkuMzM5IDQxLjkyMTkgMTM5Ljg4NSA0MS44NTk0IDE0MC41IDQxLjg1OTRIMTQxLjk3N1pNMTQ5LjY4OCAzOC41NDY5VjM5LjkyMTlIMTQ0LjkyMlYzOC41NDY5SDE0OS42ODhaTTE0Ni4yOTcgMzYuNDc2NkgxNDguMThWNDQuNjY0MUMxNDguMTggNDQuOTI0NSAxNDguMjE2IDQ1LjEyNSAxNDguMjg5IDQ1LjI2NTZDMTQ4LjM2NyA0NS40MDEgMTQ4LjQ3NCA0NS40OTIyIDE0OC42MDkgNDUuNTM5MUMxNDguNzQ1IDQ1LjU4NTkgMTQ4LjkwNCA0NS42MDk0IDE0OS4wODYgNDUuNjA5NEMxNDkuMjE2IDQ1LjYwOTQgMTQ5LjM0MSA0NS42MDE2IDE0OS40NjEgNDUuNTg1OUMxNDkuNTgxIDQ1LjU3MDMgMTQ5LjY3NyA0NS41NTQ3IDE0OS43NSA0NS41MzkxTDE0OS43NTggNDYuOTc2NkMxNDkuNjAyIDQ3LjAyMzQgMTQ5LjQxOSA0Ny4wNjUxIDE0OS4yMTEgNDcuMTAxNkMxNDkuMDA4IDQ3LjEzOCAxNDguNzczIDQ3LjE1NjIgMTQ4LjUwOCA0Ny4xNTYyQzE0OC4wNzYgNDcuMTU2MiAxNDcuNjkzIDQ3LjA4MDcgMTQ3LjM1OSA0Ni45Mjk3QzE0Ny4wMjYgNDYuNzczNCAxNDYuNzY2IDQ2LjUyMDggMTQ2LjU3OCA0Ni4xNzE5QzE0Ni4zOTEgNDUuODIyOSAxNDYuMjk3IDQ1LjM1OTQgMTQ2LjI5NyA0NC43ODEyVjM2LjQ3NjZaTTE1Ni40NzcgNDUuMDA3OFYzOC41NDY5SDE1OC4zNjdWNDdIMTU2LjU4NkwxNTYuNDc3IDQ1LjAwNzhaTTE1Ni43NDIgNDMuMjVMMTU3LjM3NSA0My4yMzQ0QzE1Ny4zNzUgNDMuODAyMSAxNTcuMzEyIDQ0LjMyNTUgMTU3LjE4OCA0NC44MDQ3QzE1Ny4wNjIgNDUuMjc4NiAxNTYuODcgNDUuNjkyNyAxNTYuNjA5IDQ2LjA0NjlDMTU2LjM0OSA0Ni4zOTU4IDE1Ni4wMTYgNDYuNjY5MyAxNTUuNjA5IDQ2Ljg2NzJDMTU1LjIwMyA0Ny4wNTk5IDE1NC43MTYgNDcuMTU2MiAxNTQuMTQ4IDQ3LjE1NjJDMTUzLjczNyA0Ny4xNTYyIDE1My4zNTkgNDcuMDk2NCAxNTMuMDE2IDQ2Ljk3NjZDMTUyLjY3MiA0Ni44NTY4IDE1Mi4zNzUgNDYuNjcxOSAxNTIuMTI1IDQ2LjQyMTlDMTUxLjg4IDQ2LjE3MTkgMTUxLjY5IDQ1Ljg0NjQgMTUxLjU1NSA0NS40NDUzQzE1MS40MTkgNDUuMDQ0MyAxNTEuMzUyIDQ0LjU2NTEgMTUxLjM1MiA0NC4wMDc4VjM4LjU0NjlIMTUzLjIzNFY0NC4wMjM0QzE1My4yMzQgNDQuMzMwNyAxNTMuMjcxIDQ0LjU4ODUgMTUzLjM0NCA0NC43OTY5QzE1My40MTcgNDUgMTUzLjUxNiA0NS4xNjQxIDE1My42NDEgNDUuMjg5MUMxNTMuNzY2IDQ1LjQxNDEgMTUzLjkxMSA0NS41MDI2IDE1NC4wNzggNDUuNTU0N0MxNTQuMjQ1IDQ1LjYwNjggMTU0LjQyMiA0NS42MzI4IDE1NC42MDkgNDUuNjMyOEMxNTUuMTQ2IDQ1LjYzMjggMTU1LjU2OCA0NS41Mjg2IDE1NS44NzUgNDUuMzIwM0MxNTYuMTg4IDQ1LjEwNjggMTU2LjQwOSA0NC44MjAzIDE1Ni41MzkgNDQuNDYwOUMxNTYuNjc0IDQ0LjEwMTYgMTU2Ljc0MiA0My42OTc5IDE1Ni43NDIgNDMuMjVaTTE2Mi40MzggNDAuMTU2MlY0N0gxNjAuNTU1VjM4LjU0NjlIMTYyLjM1MkwxNjIuNDM4IDQwLjE1NjJaTTE2NS4wMjMgMzguNDkyMkwxNjUuMDA4IDQwLjI0MjJDMTY0Ljg5MyA0MC4yMjE0IDE2NC43NjggNDAuMjA1NyAxNjQuNjMzIDQwLjE5NTNDMTY0LjUwMyA0MC4xODQ5IDE2NC4zNzIgNDAuMTc5NyAxNjQuMjQyIDQwLjE3OTdDMTYzLjkxOSA0MC4xNzk3IDE2My42MzUgNDAuMjI2NiAxNjMuMzkxIDQwLjMyMDNDMTYzLjE0NiA0MC40MDg5IDE2Mi45NCA0MC41MzkxIDE2Mi43NzMgNDAuNzEwOUMxNjIuNjEyIDQwLjg3NzYgMTYyLjQ4NyA0MS4wODA3IDE2Mi4zOTggNDEuMzIwM0MxNjIuMzEgNDEuNTU5OSAxNjIuMjU4IDQxLjgyODEgMTYyLjI0MiA0Mi4xMjVMMTYxLjgxMiA0Mi4xNTYyQzE2MS44MTIgNDEuNjI1IDE2MS44NjUgNDEuMTMyOCAxNjEuOTY5IDQwLjY3OTdDMTYyLjA3MyA0MC4yMjY2IDE2Mi4yMjkgMzkuODI4MSAxNjIuNDM4IDM5LjQ4NDRDMTYyLjY1MSAzOS4xNDA2IDE2Mi45MTcgMzguODcyNCAxNjMuMjM0IDM4LjY3OTdDMTYzLjU1NyAzOC40ODcgMTYzLjkzIDM4LjM5MDYgMTY0LjM1MiAzOC4zOTA2QzE2NC40NjYgMzguMzkwNiAxNjQuNTg5IDM4LjQwMSAxNjQuNzE5IDM4LjQyMTlDMTY0Ljg1NCAzOC40NDI3IDE2NC45NTYgMzguNDY2MSAxNjUuMDIzIDM4LjQ5MjJaTTE3MC4wMjMgNDcuMTU2MkMxNjkuMzk4IDQ3LjE1NjIgMTY4LjgzMyA0Ny4wNTQ3IDE2OC4zMjggNDYuODUxNkMxNjcuODI4IDQ2LjY0MzIgMTY3LjQwMSA0Ni4zNTQyIDE2Ny4wNDcgNDUuOTg0NEMxNjYuNjk4IDQ1LjYxNDYgMTY2LjQzIDQ1LjE3OTcgMTY2LjI0MiA0NC42Nzk3QzE2Ni4wNTUgNDQuMTc5NyAxNjUuOTYxIDQzLjY0MDYgMTY1Ljk2MSA0My4wNjI1VjQyLjc1QzE2NS45NjEgNDIuMDg4NSAxNjYuMDU3IDQxLjQ4OTYgMTY2LjI1IDQwLjk1MzFDMTY2LjQ0MyA0MC40MTY3IDE2Ni43MTEgMzkuOTU4MyAxNjcuMDU1IDM5LjU3ODFDMTY3LjM5OCAzOS4xOTI3IDE2Ny44MDUgMzguODk4NCAxNjguMjczIDM4LjY5NTNDMTY4Ljc0MiAzOC40OTIyIDE2OS4yNSAzOC4zOTA2IDE2OS43OTcgMzguMzkwNkMxNzAuNDAxIDM4LjM5MDYgMTcwLjkzIDM4LjQ5MjIgMTcxLjM4MyAzOC42OTUzQzE3MS44MzYgMzguODk4NCAxNzIuMjExIDM5LjE4NDkgMTcyLjUwOCAzOS41NTQ3QzE3Mi44MSAzOS45MTkzIDE3My4wMzQgNDAuMzU0MiAxNzMuMTggNDAuODU5NEMxNzMuMzMxIDQxLjM2NDYgMTczLjQwNiA0MS45MjE5IDE3My40MDYgNDIuNTMxMlY0My4zMzU5SDE2Ni44NzVWNDEuOTg0NEgxNzEuNTQ3VjQxLjgzNTlDMTcxLjUzNiA0MS40OTc0IDE3MS40NjkgNDEuMTc5NyAxNzEuMzQ0IDQwLjg4MjhDMTcxLjIyNCA0MC41ODU5IDE3MS4wMzkgNDAuMzQ2NCAxNzAuNzg5IDQwLjE2NDFDMTcwLjUzOSAzOS45ODE4IDE3MC4yMDYgMzkuODkwNiAxNjkuNzg5IDM5Ljg5MDZDMTY5LjQ3NyAzOS44OTA2IDE2OS4xOTggMzkuOTU4MyAxNjguOTUzIDQwLjA5MzhDMTY4LjcxNCA0MC4yMjQgMTY4LjUxMyA0MC40MTQxIDE2OC4zNTIgNDAuNjY0MUMxNjguMTkgNDAuOTE0MSAxNjguMDY1IDQxLjIxNjEgMTY3Ljk3NyA0MS41NzAzQzE2Ny44OTMgNDEuOTE5MyAxNjcuODUyIDQyLjMxMjUgMTY3Ljg1MiA0Mi43NVY0My4wNjI1QzE2Ny44NTIgNDMuNDMyMyAxNjcuOTAxIDQzLjc3NiAxNjggNDQuMDkzOEMxNjguMTA0IDQ0LjQwNjIgMTY4LjI1NSA0NC42Nzk3IDE2OC40NTMgNDQuOTE0MUMxNjguNjUxIDQ1LjE0ODQgMTY4Ljg5MSA0NS4zMzMzIDE2OS4xNzIgNDUuNDY4OEMxNjkuNDUzIDQ1LjU5OSAxNjkuNzczIDQ1LjY2NDEgMTcwLjEzMyA0NS42NjQxQzE3MC41ODYgNDUuNjY0MSAxNzAuOTkgNDUuNTcyOSAxNzEuMzQ0IDQ1LjM5MDZDMTcxLjY5OCA0NS4yMDgzIDE3Mi4wMDUgNDQuOTUwNSAxNzIuMjY2IDQ0LjYxNzJMMTczLjI1OCA0NS41NzgxQzE3My4wNzYgNDUuODQzOCAxNzIuODM5IDQ2LjA5OSAxNzIuNTQ3IDQ2LjM0MzhDMTcyLjI1NSA0Ni41ODMzIDE3MS44OTggNDYuNzc4NiAxNzEuNDc3IDQ2LjkyOTdDMTcxLjA2IDQ3LjA4MDcgMTcwLjU3NiA0Ny4xNTYyIDE3MC4wMjMgNDcuMTU2MloiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTg2LjIxMDkgNjQuODM0VjY2SDgxLjkyNzdWNjQuODM0SDg2LjIxMDlaTTgyLjMzNzkgNTcuNDY4OFY2Nkg4MC44NjcyVjU3LjQ2ODhIODIuMzM3OVpNOTEuMDMxMiA2NC43Mjg1VjYxLjcwNTFDOTEuMDMxMiA2MS40Nzg1IDkwLjk5MDIgNjEuMjgzMiA5MC45MDgyIDYxLjExOTFDOTAuODI2MiA2MC45NTUxIDkwLjcwMTIgNjAuODI4MSA5MC41MzMyIDYwLjczODNDOTAuMzY5MSA2MC42NDg0IDkwLjE2MjEgNjAuNjAzNSA4OS45MTIxIDYwLjYwMzVDODkuNjgxNiA2MC42MDM1IDg5LjQ4MjQgNjAuNjQyNiA4OS4zMTQ1IDYwLjcyMDdDODkuMTQ2NSA2MC43OTg4IDg5LjAxNTYgNjAuOTA0MyA4OC45MjE5IDYxLjAzNzFDODguODI4MSA2MS4xNjk5IDg4Ljc4MTIgNjEuMzIwMyA4OC43ODEyIDYxLjQ4ODNIODcuMzc1Qzg3LjM3NSA2MS4yMzgzIDg3LjQzNTUgNjAuOTk2MSA4Ny41NTY2IDYwLjc2MTdDODcuNjc3NyA2MC41MjczIDg3Ljg1MzUgNjAuMzE4NCA4OC4wODQgNjAuMTM0OEM4OC4zMTQ1IDU5Ljk1MTIgODguNTg5OCA1OS44MDY2IDg4LjkxMDIgNTkuNzAxMkM4OS4yMzA1IDU5LjU5NTcgODkuNTg5OCA1OS41NDMgODkuOTg4MyA1OS41NDNDOTAuNDY0OCA1OS41NDMgOTAuODg2NyA1OS42MjMgOTEuMjUzOSA1OS43ODMyQzkxLjYyNSA1OS45NDM0IDkxLjkxNiA2MC4xODU1IDkyLjEyNyA2MC41MDk4QzkyLjM0MTggNjAuODMwMSA5Mi40NDkyIDYxLjIzMjQgOTIuNDQ5MiA2MS43MTY4VjY0LjUzNTJDOTIuNDQ5MiA2NC44MjQyIDkyLjQ2ODggNjUuMDg0IDkyLjUwNzggNjUuMzE0NUM5Mi41NTA4IDY1LjU0MSA5Mi42MTEzIDY1LjczODMgOTIuNjg5NSA2NS45MDYyVjY2SDkxLjI0MjJDOTEuMTc1OCA2NS44NDc3IDkxLjEyMyA2NS42NTQzIDkxLjA4NCA2NS40MTk5QzkxLjA0ODggNjUuMTgxNiA5MS4wMzEyIDY0Ljk1MTIgOTEuMDMxMiA2NC43Mjg1Wk05MS4yMzYzIDYyLjE0NDVMOTEuMjQ4IDYzLjAxNzZIOTAuMjM0NEM4OS45NzI3IDYzLjAxNzYgODkuNzQyMiA2My4wNDMgODkuNTQzIDYzLjA5MzhDODkuMzQzOCA2My4xNDA2IDg5LjE3NzcgNjMuMjEwOSA4OS4wNDQ5IDYzLjMwNDdDODguOTEyMSA2My4zOTg0IDg4LjgxMjUgNjMuNTExNyA4OC43NDYxIDYzLjY0NDVDODguNjc5NyA2My43NzczIDg4LjY0NjUgNjMuOTI3NyA4OC42NDY1IDY0LjA5NTdDODguNjQ2NSA2NC4yNjM3IDg4LjY4NTUgNjQuNDE4IDg4Ljc2MzcgNjQuNTU4NkM4OC44NDE4IDY0LjY5NTMgODguOTU1MSA2NC44MDI3IDg5LjEwMzUgNjQuODgwOUM4OS4yNTU5IDY0Ljk1OSA4OS40Mzk1IDY0Ljk5OCA4OS42NTQzIDY0Ljk5OEM4OS45NDM0IDY0Ljk5OCA5MC4xOTUzIDY0LjkzOTUgOTAuNDEwMiA2NC44MjIzQzkwLjYyODkgNjQuNzAxMiA5MC44MDA4IDY0LjU1NDcgOTAuOTI1OCA2NC4zODI4QzkxLjA1MDggNjQuMjA3IDkxLjExNzIgNjQuMDQxIDkxLjEyNSA2My44ODQ4TDkxLjU4MiA2NC41MTE3QzkxLjUzNTIgNjQuNjcxOSA5MS40NTUxIDY0Ljg0MzggOTEuMzQxOCA2NS4wMjczQzkxLjIyODUgNjUuMjEwOSA5MS4wODAxIDY1LjM4NjcgOTAuODk2NSA2NS41NTQ3QzkwLjcxNjggNjUuNzE4OCA5MC41IDY1Ljg1MzUgOTAuMjQ2MSA2NS45NTlDODkuOTk2MSA2Ni4wNjQ1IDg5LjcwNyA2Ni4xMTcyIDg5LjM3ODkgNjYuMTE3MkM4OC45NjQ4IDY2LjExNzIgODguNTk1NyA2Ni4wMzUyIDg4LjI3MTUgNjUuODcxMUM4Ny45NDczIDY1LjcwMzEgODcuNjkzNCA2NS40Nzg1IDg3LjUwOTggNjUuMTk3M0M4Ny4zMjYyIDY0LjkxMjEgODcuMjM0NCA2NC41ODk4IDg3LjIzNDQgNjQuMjMwNUM4Ny4yMzQ0IDYzLjg5NDUgODcuMjk2OSA2My41OTc3IDg3LjQyMTkgNjMuMzM5OEM4Ny41NTA4IDYzLjA3ODEgODcuNzM4MyA2Mi44NTk0IDg3Ljk4NDQgNjIuNjgzNkM4OC4yMzQ0IDYyLjUwNzggODguNTM5MSA2Mi4zNzUgODguODk4NCA2Mi4yODUyQzg5LjI1NzggNjIuMTkxNCA4OS42NjggNjIuMTQ0NSA5MC4xMjg5IDYyLjE0NDVIOTEuMjM2M1pNOTcuNzMyNCA2NC4yODMyQzk3LjczMjQgNjQuMTQyNiA5Ny42OTczIDY0LjAxNTYgOTcuNjI3IDYzLjkwMjNDOTcuNTU2NiA2My43ODUyIDk3LjQyMTkgNjMuNjc5NyA5Ny4yMjI3IDYzLjU4NTlDOTcuMDI3MyA2My40OTIyIDk2LjczODMgNjMuNDA2MiA5Ni4zNTU1IDYzLjMyODFDOTYuMDE5NSA2My4yNTM5IDk1LjcxMDkgNjMuMTY2IDk1LjQyOTcgNjMuMDY0NUM5NS4xNTIzIDYyLjk1OSA5NC45MTQxIDYyLjgzMiA5NC43MTQ4IDYyLjY4MzZDOTQuNTE1NiA2Mi41MzUyIDk0LjM2MTMgNjIuMzU5NCA5NC4yNTIgNjIuMTU2MkM5NC4xNDI2IDYxLjk1MzEgOTQuMDg3OSA2MS43MTg4IDk0LjA4NzkgNjEuNDUzMUM5NC4wODc5IDYxLjE5NTMgOTQuMTQ0NSA2MC45NTEyIDk0LjI1NzggNjAuNzIwN0M5NC4zNzExIDYwLjQ5MDIgOTQuNTMzMiA2MC4yODcxIDk0Ljc0NDEgNjAuMTExM0M5NC45NTUxIDU5LjkzNTUgOTUuMjEwOSA1OS43OTY5IDk1LjUxMTcgNTkuNjk1M0M5NS44MTY0IDU5LjU5MzggOTYuMTU2MiA1OS41NDMgOTYuNTMxMiA1OS41NDNDOTcuMDYyNSA1OS41NDMgOTcuNTE3NiA1OS42MzI4IDk3Ljg5NjUgNTkuODEyNUM5OC4yNzkzIDU5Ljk4ODMgOTguNTcyMyA2MC4yMjg1IDk4Ljc3NTQgNjAuNTMzMkM5OC45Nzg1IDYwLjgzNCA5OS4wODAxIDYxLjE3MzggOTkuMDgwMSA2MS41NTI3SDk3LjY2OEM5Ny42NjggNjEuMzg0OCA5Ny42MjUgNjEuMjI4NSA5Ny41MzkxIDYxLjA4NEM5Ny40NTcgNjAuOTM1NSA5Ny4zMzIgNjAuODE2NCA5Ny4xNjQxIDYwLjcyNjZDOTYuOTk2MSA2MC42MzI4IDk2Ljc4NTIgNjAuNTg1OSA5Ni41MzEyIDYwLjU4NTlDOTYuMjg5MSA2MC41ODU5IDk2LjA4NzkgNjAuNjI1IDk1LjkyNzcgNjAuNzAzMUM5NS43NzE1IDYwLjc3NzMgOTUuNjU0MyA2MC44NzUgOTUuNTc2MiA2MC45OTYxQzk1LjUwMiA2MS4xMTcyIDk1LjQ2NDggNjEuMjUgOTUuNDY0OCA2MS4zOTQ1Qzk1LjQ2NDggNjEuNSA5NS40ODQ0IDYxLjU5NTcgOTUuNTIzNCA2MS42ODE2Qzk1LjU2NjQgNjEuNzYzNyA5NS42MzY3IDYxLjgzOTggOTUuNzM0NCA2MS45MTAyQzk1LjgzMiA2MS45NzY2IDk1Ljk2NDggNjIuMDM5MSA5Ni4xMzI4IDYyLjA5NzdDOTYuMzA0NyA2Mi4xNTYyIDk2LjUxOTUgNjIuMjEyOSA5Ni43NzczIDYyLjI2NzZDOTcuMjYxNyA2Mi4zNjkxIDk3LjY3NzcgNjIuNSA5OC4wMjU0IDYyLjY2MDJDOTguMzc3IDYyLjgxNjQgOTguNjQ2NSA2My4wMTk1IDk4LjgzNCA2My4yNjk1Qzk5LjAyMTUgNjMuNTE1NiA5OS4xMTUyIDYzLjgyODEgOTkuMTE1MiA2NC4yMDdDOTkuMTE1MiA2NC40ODgzIDk5LjA1NDcgNjQuNzQ2MSA5OC45MzM2IDY0Ljk4MDVDOTguODE2NCA2NS4yMTA5IDk4LjY0NDUgNjUuNDEyMSA5OC40MTggNjUuNTg0Qzk4LjE5MTQgNjUuNzUyIDk3LjkxOTkgNjUuODgyOCA5Ny42MDM1IDY1Ljk3NjZDOTcuMjkxIDY2LjA3MDMgOTYuOTM5NSA2Ni4xMTcyIDk2LjU0ODggNjYuMTE3MkM5NS45NzQ2IDY2LjExNzIgOTUuNDg4MyA2Ni4wMTU2IDk1LjA4OTggNjUuODEyNUM5NC42OTE0IDY1LjYwNTUgOTQuMzg4NyA2NS4zNDE4IDk0LjE4MTYgNjUuMDIxNUM5My45Nzg1IDY0LjY5NzMgOTMuODc3IDY0LjM2MTMgOTMuODc3IDY0LjAxMzdIOTUuMjQyMkM5NS4yNTc4IDY0LjI3NTQgOTUuMzMwMSA2NC40ODQ0IDk1LjQ1OSA2NC42NDA2Qzk1LjU5MTggNjQuNzkzIDk1Ljc1NTkgNjQuOTA0MyA5NS45NTEyIDY0Ljk3NDZDOTYuMTUwNCA2NS4wNDEgOTYuMzU1NSA2NS4wNzQyIDk2LjU2NjQgNjUuMDc0MkM5Ni44MjAzIDY1LjA3NDIgOTcuMDMzMiA2NS4wNDEgOTcuMjA1MSA2NC45NzQ2Qzk3LjM3NyA2NC45MDQzIDk3LjUwNzggNjQuODEwNSA5Ny41OTc3IDY0LjY5MzRDOTcuNjg3NSA2NC41NzIzIDk3LjczMjQgNjQuNDM1NSA5Ny43MzI0IDY0LjI4MzJaTTEwMy41MDggNTkuNjYwMlY2MC42OTE0SDk5LjkzMzZWNTkuNjYwMkgxMDMuNTA4Wk0xMDAuOTY1IDU4LjEwNzRIMTAyLjM3N1Y2NC4yNDhDMTAyLjM3NyA2NC40NDM0IDEwMi40MDQgNjQuNTkzOCAxMDIuNDU5IDY0LjY5OTJDMTAyLjUxOCA2NC44MDA4IDEwMi41OTggNjQuODY5MSAxMDIuNjk5IDY0LjkwNDNDMTAyLjgwMSA2NC45Mzk1IDEwMi45MiA2NC45NTcgMTAzLjA1NyA2NC45NTdDMTAzLjE1NCA2NC45NTcgMTAzLjI0OCA2NC45NTEyIDEwMy4zMzggNjQuOTM5NUMxMDMuNDI4IDY0LjkyNzcgMTAzLjUgNjQuOTE2IDEwMy41NTUgNjQuOTA0M0wxMDMuNTYxIDY1Ljk4MjRDMTAzLjQ0MyA2Ni4wMTc2IDEwMy4zMDcgNjYuMDQ4OCAxMDMuMTUgNjYuMDc2MkMxMDIuOTk4IDY2LjEwMzUgMTAyLjgyMiA2Ni4xMTcyIDEwMi42MjMgNjYuMTE3MkMxMDIuMjk5IDY2LjExNzIgMTAyLjAxMiA2Ni4wNjA1IDEwMS43NjIgNjUuOTQ3M0MxMDEuNTEyIDY1LjgzMDEgMTAxLjMxNiA2NS42NDA2IDEwMS4xNzYgNjUuMzc4OUMxMDEuMDM1IDY1LjExNzIgMTAwLjk2NSA2NC43Njk1IDEwMC45NjUgNjQuMzM1OVY1OC4xMDc0Wk0xMTEuOSA2NC41MDU5VjU5LjY2MDJIMTEzLjMxOFY2NkgxMTEuOTgyTDExMS45IDY0LjUwNTlaTTExMi4xIDYzLjE4NzVMMTEyLjU3NCA2My4xNzU4QzExMi41NzQgNjMuNjAxNiAxMTIuNTI3IDYzLjk5NDEgMTEyLjQzNCA2NC4zNTM1QzExMi4zNCA2NC43MDkgMTEyLjE5NSA2NS4wMTk1IDExMiA2NS4yODUyQzExMS44MDUgNjUuNTQ2OSAxMTEuNTU1IDY1Ljc1MiAxMTEuMjUgNjUuOTAwNEMxMTAuOTQ1IDY2LjA0NDkgMTEwLjU4IDY2LjExNzIgMTEwLjE1NCA2Ni4xMTcyQzEwOS44NDYgNjYuMTE3MiAxMDkuNTYyIDY2LjA3MjMgMTA5LjMwNSA2NS45ODI0QzEwOS4wNDcgNjUuODkyNiAxMDguODI0IDY1Ljc1MzkgMTA4LjYzNyA2NS41NjY0QzEwOC40NTMgNjUuMzc4OSAxMDguMzExIDY1LjEzNDggMTA4LjIwOSA2NC44MzRDMTA4LjEwNyA2NC41MzMyIDEwOC4wNTcgNjQuMTczOCAxMDguMDU3IDYzLjc1NTlWNTkuNjYwMkgxMDkuNDY5VjYzLjc2NzZDMTA5LjQ2OSA2My45OTggMTA5LjQ5NiA2NC4xOTE0IDEwOS41NTEgNjQuMzQ3N0MxMDkuNjA1IDY0LjUgMTA5LjY4IDY0LjYyMyAxMDkuNzczIDY0LjcxNjhDMTA5Ljg2NyA2NC44MTA1IDEwOS45NzcgNjQuODc3IDExMC4xMDIgNjQuOTE2QzExMC4yMjcgNjQuOTU1MSAxMTAuMzU5IDY0Ljk3NDYgMTEwLjUgNjQuOTc0NkMxMTAuOTAyIDY0Ljk3NDYgMTExLjIxOSA2NC44OTY1IDExMS40NDkgNjQuNzQwMkMxMTEuNjg0IDY0LjU4MDEgMTExLjg1IDY0LjM2NTIgMTExLjk0NyA2NC4wOTU3QzExMi4wNDkgNjMuODI2MiAxMTIuMSA2My41MjM0IDExMi4xIDYzLjE4NzVaTTExNi40MzQgNjAuODc4OVY2OC40Mzc1SDExNS4wMjFWNTkuNjYwMkgxMTYuMzIyTDExNi40MzQgNjAuODc4OVpNMTIwLjU2NCA2Mi43NzE1VjYyLjg5NDVDMTIwLjU2NCA2My4zNTU1IDEyMC41MSA2My43ODMyIDEyMC40IDY0LjE3NzdDMTIwLjI5NSA2NC41Njg0IDEyMC4xMzcgNjQuOTEwMiAxMTkuOTI2IDY1LjIwMzFDMTE5LjcxOSA2NS40OTIyIDExOS40NjMgNjUuNzE2OCAxMTkuMTU4IDY1Ljg3N0MxMTguODU0IDY2LjAzNzEgMTE4LjUwMiA2Ni4xMTcyIDExOC4xMDQgNjYuMTE3MkMxMTcuNzA5IDY2LjExNzIgMTE3LjM2MyA2Ni4wNDQ5IDExNy4wNjYgNjUuOTAwNEMxMTYuNzczIDY1Ljc1MiAxMTYuNTI1IDY1LjU0MyAxMTYuMzIyIDY1LjI3MzRDMTE2LjExOSA2NS4wMDM5IDExNS45NTUgNjQuNjg3NSAxMTUuODMgNjQuMzI0MkMxMTUuNzA5IDYzLjk1NyAxMTUuNjIzIDYzLjU1NDcgMTE1LjU3MiA2My4xMTcyVjYyLjY0MjZDMTE1LjYyMyA2Mi4xNzc3IDExNS43MDkgNjEuNzU1OSAxMTUuODMgNjEuMzc3QzExNS45NTUgNjAuOTk4IDExNi4xMTkgNjAuNjcxOSAxMTYuMzIyIDYwLjM5ODRDMTE2LjUyNSA2MC4xMjUgMTE2Ljc3MyA1OS45MTQxIDExNy4wNjYgNTkuNzY1NkMxMTcuMzU5IDU5LjYxNzIgMTE3LjcwMSA1OS41NDMgMTE4LjA5MiA1OS41NDNDMTE4LjQ5IDU5LjU0MyAxMTguODQ0IDU5LjYyMTEgMTE5LjE1MiA1OS43NzczQzExOS40NjEgNTkuOTI5NyAxMTkuNzIxIDYwLjE0ODQgMTE5LjkzMiA2MC40MzM2QzEyMC4xNDMgNjAuNzE0OCAxMjAuMzAxIDYxLjA1NDcgMTIwLjQwNiA2MS40NTMxQzEyMC41MTIgNjEuODQ3NyAxMjAuNTY0IDYyLjI4NzEgMTIwLjU2NCA2Mi43NzE1Wk0xMTkuMTUyIDYyLjg5NDVWNjIuNzcxNUMxMTkuMTUyIDYyLjQ3ODUgMTE5LjEyNSA2Mi4yMDcgMTE5LjA3IDYxLjk1N0MxMTkuMDE2IDYxLjcwMzEgMTE4LjkzIDYxLjQ4MDUgMTE4LjgxMiA2MS4yODkxQzExOC42OTUgNjEuMDk3NyAxMTguNTQ1IDYwLjk0OTIgMTE4LjM2MSA2MC44NDM4QzExOC4xODIgNjAuNzM0NCAxMTcuOTY1IDYwLjY3OTcgMTE3LjcxMSA2MC42Nzk3QzExNy40NjEgNjAuNjc5NyAxMTcuMjQ2IDYwLjcyMjcgMTE3LjA2NiA2MC44MDg2QzExNi44ODcgNjAuODkwNiAxMTYuNzM2IDYxLjAwNTkgMTE2LjYxNSA2MS4xNTQzQzExNi40OTQgNjEuMzAyNyAxMTYuNCA2MS40NzY2IDExNi4zMzQgNjEuNjc1OEMxMTYuMjY4IDYxLjg3MTEgMTE2LjIyMSA2Mi4wODQgMTE2LjE5MyA2Mi4zMTQ1VjYzLjQ1MTJDMTE2LjI0IDYzLjczMjQgMTE2LjMyIDYzLjk5MDIgMTE2LjQzNCA2NC4yMjQ2QzExNi41NDcgNjQuNDU5IDExNi43MDcgNjQuNjQ2NSAxMTYuOTE0IDY0Ljc4NzFDMTE3LjEyNSA2NC45MjM4IDExNy4zOTUgNjQuOTkyMiAxMTcuNzIzIDY0Ljk5MjJDMTE3Ljk3NyA2NC45OTIyIDExOC4xOTMgNjQuOTM3NSAxMTguMzczIDY0LjgyODFDMTE4LjU1MyA2NC43MTg4IDExOC42OTkgNjQuNTY4NCAxMTguODEyIDY0LjM3N0MxMTguOTMgNjQuMTgxNiAxMTkuMDE2IDYzLjk1NyAxMTkuMDcgNjMuNzAzMUMxMTkuMTI1IDYzLjQ0OTIgMTE5LjE1MiA2My4xNzk3IDExOS4xNTIgNjIuODk0NVpNMTI1Ljg4MyA2NC42ODc1VjU3SDEyNy4zMDFWNjZIMTI2LjAxOEwxMjUuODgzIDY0LjY4NzVaTTEyMS43NTggNjIuOTAwNFY2Mi43NzczQzEyMS43NTggNjIuMjk2OSAxMjEuODE0IDYxLjg1OTQgMTIxLjkyOCA2MS40NjQ4QzEyMi4wNDEgNjEuMDY2NCAxMjIuMjA1IDYwLjcyNDYgMTIyLjQyIDYwLjQzOTVDMTIyLjYzNSA2MC4xNTA0IDEyMi44OTYgNTkuOTI5NyAxMjMuMjA1IDU5Ljc3NzNDMTIzLjUxNCA1OS42MjExIDEyMy44NjEgNTkuNTQzIDEyNC4yNDggNTkuNTQzQzEyNC42MzEgNTkuNTQzIDEyNC45NjcgNTkuNjE3MiAxMjUuMjU2IDU5Ljc2NTZDMTI1LjU0NSA1OS45MTQxIDEyNS43OTEgNjAuMTI3IDEyNS45OTQgNjAuNDA0M0MxMjYuMTk3IDYwLjY3NzcgMTI2LjM1OSA2MS4wMDU5IDEyNi40OCA2MS4zODg3QzEyNi42MDIgNjEuNzY3NiAxMjYuNjg4IDYyLjE4OTUgMTI2LjczOCA2Mi42NTQzVjYzLjA0NjlDMTI2LjY4OCA2My41IDEyNi42MDIgNjMuOTE0MSAxMjYuNDggNjQuMjg5MUMxMjYuMzU5IDY0LjY2NDEgMTI2LjE5NyA2NC45ODgzIDEyNS45OTQgNjUuMjYxN0MxMjUuNzkxIDY1LjUzNTIgMTI1LjU0MyA2NS43NDYxIDEyNS4yNSA2NS44OTQ1QzEyNC45NjEgNjYuMDQzIDEyNC42MjMgNjYuMTE3MiAxMjQuMjM2IDY2LjExNzJDMTIzLjg1NCA2Ni4xMTcyIDEyMy41MDggNjYuMDM3MSAxMjMuMTk5IDY1Ljg3N0MxMjIuODk1IDY1LjcxNjggMTIyLjYzNSA2NS40OTIyIDEyMi40MiA2NS4yMDMxQzEyMi4yMDUgNjQuOTE0MSAxMjIuMDQxIDY0LjU3NDIgMTIxLjkyOCA2NC4xODM2QzEyMS44MTQgNjMuNzg5MSAxMjEuNzU4IDYzLjM2MTMgMTIxLjc1OCA2Mi45MDA0Wk0xMjMuMTcgNjIuNzc3M1Y2Mi45MDA0QzEyMy4xNyA2My4xODk1IDEyMy4xOTUgNjMuNDU5IDEyMy4yNDYgNjMuNzA5QzEyMy4zMDEgNjMuOTU5IDEyMy4zODUgNjQuMTc5NyAxMjMuNDk4IDY0LjM3MTFDMTIzLjYxMSA2NC41NTg2IDEyMy43NTggNjQuNzA3IDEyMy45MzggNjQuODE2NEMxMjQuMTIxIDY0LjkyMTkgMTI0LjM0IDY0Ljk3NDYgMTI0LjU5NCA2NC45NzQ2QzEyNC45MTQgNjQuOTc0NiAxMjUuMTc4IDY0LjkwNDMgMTI1LjM4NSA2NC43NjM3QzEyNS41OTIgNjQuNjIzIDEyNS43NTQgNjQuNDMzNiAxMjUuODcxIDY0LjE5NTNDMTI1Ljk5MiA2My45NTMxIDEyNi4wNzQgNjMuNjgzNiAxMjYuMTE3IDYzLjM4NjdWNjIuMzI2MkMxMjYuMDk0IDYyLjA5NTcgMTI2LjA0NSA2MS44ODA5IDEyNS45NzEgNjEuNjgxNkMxMjUuOSA2MS40ODI0IDEyNS44MDUgNjEuMzA4NiAxMjUuNjg0IDYxLjE2MDJDMTI1LjU2MiA2MS4wMDc4IDEyNS40MTIgNjAuODkwNiAxMjUuMjMyIDYwLjgwODZDMTI1LjA1NyA2MC43MjI3IDEyNC44NDggNjAuNjc5NyAxMjQuNjA1IDYwLjY3OTdDMTI0LjM0OCA2MC42Nzk3IDEyNC4xMjkgNjAuNzM0NCAxMjMuOTQ5IDYwLjg0MzhDMTIzLjc3IDYwLjk1MzEgMTIzLjYyMSA2MS4xMDM1IDEyMy41MDQgNjEuMjk0OUMxMjMuMzkxIDYxLjQ4NjMgMTIzLjMwNyA2MS43MDkgMTIzLjI1MiA2MS45NjI5QzEyMy4xOTcgNjIuMjE2OCAxMjMuMTcgNjIuNDg4MyAxMjMuMTcgNjIuNzc3M1pNMTMyLjYwMiA2NC43Mjg1VjYxLjcwNTFDMTMyLjYwMiA2MS40Nzg1IDEzMi41NjEgNjEuMjgzMiAxMzIuNDc5IDYxLjExOTFDMTMyLjM5NiA2MC45NTUxIDEzMi4yNzEgNjAuODI4MSAxMzIuMTA0IDYwLjczODNDMTMxLjkzOSA2MC42NDg0IDEzMS43MzIgNjAuNjAzNSAxMzEuNDgyIDYwLjYwMzVDMTMxLjI1MiA2MC42MDM1IDEzMS4wNTMgNjAuNjQyNiAxMzAuODg1IDYwLjcyMDdDMTMwLjcxNyA2MC43OTg4IDEzMC41ODYgNjAuOTA0MyAxMzAuNDkyIDYxLjAzNzFDMTMwLjM5OCA2MS4xNjk5IDEzMC4zNTIgNjEuMzIwMyAxMzAuMzUyIDYxLjQ4ODNIMTI4Ljk0NUMxMjguOTQ1IDYxLjIzODMgMTI5LjAwNiA2MC45OTYxIDEyOS4xMjcgNjAuNzYxN0MxMjkuMjQ4IDYwLjUyNzMgMTI5LjQyNCA2MC4zMTg0IDEyOS42NTQgNjAuMTM0OEMxMjkuODg1IDU5Ljk1MTIgMTMwLjE2IDU5LjgwNjYgMTMwLjQ4IDU5LjcwMTJDMTMwLjgwMSA1OS41OTU3IDEzMS4xNiA1OS41NDMgMTMxLjU1OSA1OS41NDNDMTMyLjAzNSA1OS41NDMgMTMyLjQ1NyA1OS42MjMgMTMyLjgyNCA1OS43ODMyQzEzMy4xOTUgNTkuOTQzNCAxMzMuNDg2IDYwLjE4NTUgMTMzLjY5NyA2MC41MDk4QzEzMy45MTIgNjAuODMwMSAxMzQuMDIgNjEuMjMyNCAxMzQuMDIgNjEuNzE2OFY2NC41MzUyQzEzNC4wMiA2NC44MjQyIDEzNC4wMzkgNjUuMDg0IDEzNC4wNzggNjUuMzE0NUMxMzQuMTIxIDY1LjU0MSAxMzQuMTgyIDY1LjczODMgMTM0LjI2IDY1LjkwNjJWNjZIMTMyLjgxMkMxMzIuNzQ2IDY1Ljg0NzcgMTMyLjY5MyA2NS42NTQzIDEzMi42NTQgNjUuNDE5OUMxMzIuNjE5IDY1LjE4MTYgMTMyLjYwMiA2NC45NTEyIDEzMi42MDIgNjQuNzI4NVpNMTMyLjgwNyA2Mi4xNDQ1TDEzMi44MTggNjMuMDE3NkgxMzEuODA1QzEzMS41NDMgNjMuMDE3NiAxMzEuMzEyIDYzLjA0MyAxMzEuMTEzIDYzLjA5MzhDMTMwLjkxNCA2My4xNDA2IDEzMC43NDggNjMuMjEwOSAxMzAuNjE1IDYzLjMwNDdDMTMwLjQ4MiA2My4zOTg0IDEzMC4zODMgNjMuNTExNyAxMzAuMzE2IDYzLjY0NDVDMTMwLjI1IDYzLjc3NzMgMTMwLjIxNyA2My45Mjc3IDEzMC4yMTcgNjQuMDk1N0MxMzAuMjE3IDY0LjI2MzcgMTMwLjI1NiA2NC40MTggMTMwLjMzNCA2NC41NTg2QzEzMC40MTIgNjQuNjk1MyAxMzAuNTI1IDY0LjgwMjcgMTMwLjY3NCA2NC44ODA5QzEzMC44MjYgNjQuOTU5IDEzMS4wMSA2NC45OTggMTMxLjIyNSA2NC45OThDMTMxLjUxNCA2NC45OTggMTMxLjc2NiA2NC45Mzk1IDEzMS45OCA2NC44MjIzQzEzMi4xOTkgNjQuNzAxMiAxMzIuMzcxIDY0LjU1NDcgMTMyLjQ5NiA2NC4zODI4QzEzMi42MjEgNjQuMjA3IDEzMi42ODggNjQuMDQxIDEzMi42OTUgNjMuODg0OEwxMzMuMTUyIDY0LjUxMTdDMTMzLjEwNSA2NC42NzE5IDEzMy4wMjUgNjQuODQzOCAxMzIuOTEyIDY1LjAyNzNDMTMyLjc5OSA2NS4yMTA5IDEzMi42NSA2NS4zODY3IDEzMi40NjcgNjUuNTU0N0MxMzIuMjg3IDY1LjcxODggMTMyLjA3IDY1Ljg1MzUgMTMxLjgxNiA2NS45NTlDMTMxLjU2NiA2Ni4wNjQ1IDEzMS4yNzcgNjYuMTE3MiAxMzAuOTQ5IDY2LjExNzJDMTMwLjUzNSA2Ni4xMTcyIDEzMC4xNjYgNjYuMDM1MiAxMjkuODQyIDY1Ljg3MTFDMTI5LjUxOCA2NS43MDMxIDEyOS4yNjQgNjUuNDc4NSAxMjkuMDggNjUuMTk3M0MxMjguODk2IDY0LjkxMjEgMTI4LjgwNSA2NC41ODk4IDEyOC44MDUgNjQuMjMwNUMxMjguODA1IDYzLjg5NDUgMTI4Ljg2NyA2My41OTc3IDEyOC45OTIgNjMuMzM5OEMxMjkuMTIxIDYzLjA3ODEgMTI5LjMwOSA2Mi44NTk0IDEyOS41NTUgNjIuNjgzNkMxMjkuODA1IDYyLjUwNzggMTMwLjEwOSA2Mi4zNzUgMTMwLjQ2OSA2Mi4yODUyQzEzMC44MjggNjIuMTkxNCAxMzEuMjM4IDYyLjE0NDUgMTMxLjY5OSA2Mi4xNDQ1SDEzMi44MDdaTTEzOC42NTIgNTkuNjYwMlY2MC42OTE0SDEzNS4wNzhWNTkuNjYwMkgxMzguNjUyWk0xMzYuMTA5IDU4LjEwNzRIMTM3LjUyMVY2NC4yNDhDMTM3LjUyMSA2NC40NDM0IDEzNy41NDkgNjQuNTkzOCAxMzcuNjA0IDY0LjY5OTJDMTM3LjY2MiA2NC44MDA4IDEzNy43NDIgNjQuODY5MSAxMzcuODQ0IDY0LjkwNDNDMTM3Ljk0NSA2NC45Mzk1IDEzOC4wNjQgNjQuOTU3IDEzOC4yMDEgNjQuOTU3QzEzOC4yOTkgNjQuOTU3IDEzOC4zOTMgNjQuOTUxMiAxMzguNDgyIDY0LjkzOTVDMTM4LjU3MiA2NC45Mjc3IDEzOC42NDUgNjQuOTE2IDEzOC42OTkgNjQuOTA0M0wxMzguNzA1IDY1Ljk4MjRDMTM4LjU4OCA2Ni4wMTc2IDEzOC40NTEgNjYuMDQ4OCAxMzguMjk1IDY2LjA3NjJDMTM4LjE0MyA2Ni4xMDM1IDEzNy45NjcgNjYuMTE3MiAxMzcuNzY4IDY2LjExNzJDMTM3LjQ0MyA2Ni4xMTcyIDEzNy4xNTYgNjYuMDYwNSAxMzYuOTA2IDY1Ljk0NzNDMTM2LjY1NiA2NS44MzAxIDEzNi40NjEgNjUuNjQwNiAxMzYuMzIgNjUuMzc4OUMxMzYuMTggNjUuMTE3MiAxMzYuMTA5IDY0Ljc2OTUgMTM2LjEwOSA2NC4zMzU5VjU4LjEwNzRaTTE0Mi43ODcgNjYuMTE3MkMxNDIuMzE4IDY2LjExNzIgMTQxLjg5NSA2Ni4wNDEgMTQxLjUxNiA2NS44ODg3QzE0MS4xNDEgNjUuNzMyNCAxNDAuODIgNjUuNTE1NiAxNDAuNTU1IDY1LjIzODNDMTQwLjI5MyA2NC45NjA5IDE0MC4wOTIgNjQuNjM0OCAxMzkuOTUxIDY0LjI1OThDMTM5LjgxMSA2My44ODQ4IDEzOS43NCA2My40ODA1IDEzOS43NCA2My4wNDY5VjYyLjgxMjVDMTM5Ljc0IDYyLjMxNjQgMTM5LjgxMiA2MS44NjcyIDEzOS45NTcgNjEuNDY0OEMxNDAuMTAyIDYxLjA2MjUgMTQwLjMwMyA2MC43MTg4IDE0MC41NjEgNjAuNDMzNkMxNDAuODE4IDYwLjE0NDUgMTQxLjEyMyA1OS45MjM4IDE0MS40NzUgNTkuNzcxNUMxNDEuODI2IDU5LjYxOTEgMTQyLjIwNyA1OS41NDMgMTQyLjYxNyA1OS41NDNDMTQzLjA3IDU5LjU0MyAxNDMuNDY3IDU5LjYxOTEgMTQzLjgwNyA1OS43NzE1QzE0NC4xNDYgNTkuOTIzOCAxNDQuNDI4IDYwLjEzODcgMTQ0LjY1IDYwLjQxNkMxNDQuODc3IDYwLjY4OTUgMTQ1LjA0NSA2MS4wMTU2IDE0NS4xNTQgNjEuMzk0NUMxNDUuMjY4IDYxLjc3MzQgMTQ1LjMyNCA2Mi4xOTE0IDE0NS4zMjQgNjIuNjQ4NFY2My4yNTJIMTQwLjQyNlY2Mi4yMzgzSDE0My45M1Y2Mi4xMjdDMTQzLjkyMiA2MS44NzMgMTQzLjg3MSA2MS42MzQ4IDE0My43NzcgNjEuNDEyMUMxNDMuNjg4IDYxLjE4OTUgMTQzLjU0OSA2MS4wMDk4IDE0My4zNjEgNjAuODczQzE0My4xNzQgNjAuNzM2MyAxNDIuOTI0IDYwLjY2OCAxNDIuNjExIDYwLjY2OEMxNDIuMzc3IDYwLjY2OCAxNDIuMTY4IDYwLjcxODggMTQxLjk4NCA2MC44MjAzQzE0MS44MDUgNjAuOTE4IDE0MS42NTQgNjEuMDYwNSAxNDEuNTMzIDYxLjI0OEMxNDEuNDEyIDYxLjQzNTUgMTQxLjMxOCA2MS42NjIxIDE0MS4yNTIgNjEuOTI3N0MxNDEuMTg5IDYyLjE4OTUgMTQxLjE1OCA2Mi40ODQ0IDE0MS4xNTggNjIuODEyNVY2My4wNDY5QzE0MS4xNTggNjMuMzI0MiAxNDEuMTk1IDYzLjU4MiAxNDEuMjcgNjMuODIwM0MxNDEuMzQ4IDY0LjA1NDcgMTQxLjQ2MSA2NC4yNTk4IDE0MS42MDkgNjQuNDM1NUMxNDEuNzU4IDY0LjYxMTMgMTQxLjkzOCA2NC43NSAxNDIuMTQ4IDY0Ljg1MTZDMTQyLjM1OSA2NC45NDkyIDE0Mi42IDY0Ljk5OCAxNDIuODY5IDY0Ljk5OEMxNDMuMjA5IDY0Ljk5OCAxNDMuNTEyIDY0LjkyOTcgMTQzLjc3NyA2NC43OTNDMTQ0LjA0MyA2NC42NTYyIDE0NC4yNzMgNjQuNDYyOSAxNDQuNDY5IDY0LjIxMjlMMTQ1LjIxMyA2NC45MzM2QzE0NS4wNzYgNjUuMTMyOCAxNDQuODk4IDY1LjMyNDIgMTQ0LjY4IDY1LjUwNzhDMTQ0LjQ2MSA2NS42ODc1IDE0NC4xOTMgNjUuODM0IDE0My44NzcgNjUuOTQ3M0MxNDMuNTY0IDY2LjA2MDUgMTQzLjIwMSA2Ni4xMTcyIDE0Mi43ODcgNjYuMTE3MlpNMTUzLjY4OCA1Ny40Mzk1VjY2SDE1Mi4yNzVWNTkuMTE1MkwxNTAuMTg0IDU5LjgyNDJWNTguNjU4MkwxNTMuNTE4IDU3LjQzOTVIMTUzLjY4OFpNMTYwLjg1MiA2NC42ODc1VjU3SDE2Mi4yN1Y2NkgxNjAuOTg2TDE2MC44NTIgNjQuNjg3NVpNMTU2LjcyNyA2Mi45MDA0VjYyLjc3NzNDMTU2LjcyNyA2Mi4yOTY5IDE1Ni43ODMgNjEuODU5NCAxNTYuODk2IDYxLjQ2NDhDMTU3LjAxIDYxLjA2NjQgMTU3LjE3NCA2MC43MjQ2IDE1Ny4zODkgNjAuNDM5NUMxNTcuNjA0IDYwLjE1MDQgMTU3Ljg2NSA1OS45Mjk3IDE1OC4xNzQgNTkuNzc3M0MxNTguNDgyIDU5LjYyMTEgMTU4LjgzIDU5LjU0MyAxNTkuMjE3IDU5LjU0M0MxNTkuNiA1OS41NDMgMTU5LjkzNiA1OS42MTcyIDE2MC4yMjUgNTkuNzY1NkMxNjAuNTE0IDU5LjkxNDEgMTYwLjc2IDYwLjEyNyAxNjAuOTYzIDYwLjQwNDNDMTYxLjE2NiA2MC42Nzc3IDE2MS4zMjggNjEuMDA1OSAxNjEuNDQ5IDYxLjM4ODdDMTYxLjU3IDYxLjc2NzYgMTYxLjY1NiA2Mi4xODk1IDE2MS43MDcgNjIuNjU0M1Y2My4wNDY5QzE2MS42NTYgNjMuNSAxNjEuNTcgNjMuOTE0MSAxNjEuNDQ5IDY0LjI4OTFDMTYxLjMyOCA2NC42NjQxIDE2MS4xNjYgNjQuOTg4MyAxNjAuOTYzIDY1LjI2MTdDMTYwLjc2IDY1LjUzNTIgMTYwLjUxMiA2NS43NDYxIDE2MC4yMTkgNjUuODk0NUMxNTkuOTMgNjYuMDQzIDE1OS41OTIgNjYuMTE3MiAxNTkuMjA1IDY2LjExNzJDMTU4LjgyMiA2Ni4xMTcyIDE1OC40NzcgNjYuMDM3MSAxNTguMTY4IDY1Ljg3N0MxNTcuODYzIDY1LjcxNjggMTU3LjYwNCA2NS40OTIyIDE1Ny4zODkgNjUuMjAzMUMxNTcuMTc0IDY0LjkxNDEgMTU3LjAxIDY0LjU3NDIgMTU2Ljg5NiA2NC4xODM2QzE1Ni43ODMgNjMuNzg5MSAxNTYuNzI3IDYzLjM2MTMgMTU2LjcyNyA2Mi45MDA0Wk0xNTguMTM5IDYyLjc3NzNWNjIuOTAwNEMxNTguMTM5IDYzLjE4OTUgMTU4LjE2NCA2My40NTkgMTU4LjIxNSA2My43MDlDMTU4LjI3IDYzLjk1OSAxNTguMzU0IDY0LjE3OTcgMTU4LjQ2NyA2NC4zNzExQzE1OC41OCA2NC41NTg2IDE1OC43MjcgNjQuNzA3IDE1OC45MDYgNjQuODE2NEMxNTkuMDkgNjQuOTIxOSAxNTkuMzA5IDY0Ljk3NDYgMTU5LjU2MiA2NC45NzQ2QzE1OS44ODMgNjQuOTc0NiAxNjAuMTQ2IDY0LjkwNDMgMTYwLjM1NCA2NC43NjM3QzE2MC41NjEgNjQuNjIzIDE2MC43MjMgNjQuNDMzNiAxNjAuODQgNjQuMTk1M0MxNjAuOTYxIDYzLjk1MzEgMTYxLjA0MyA2My42ODM2IDE2MS4wODYgNjMuMzg2N1Y2Mi4zMjYyQzE2MS4wNjIgNjIuMDk1NyAxNjEuMDE0IDYxLjg4MDkgMTYwLjkzOSA2MS42ODE2QzE2MC44NjkgNjEuNDgyNCAxNjAuNzczIDYxLjMwODYgMTYwLjY1MiA2MS4xNjAyQzE2MC41MzEgNjEuMDA3OCAxNjAuMzgxIDYwLjg5MDYgMTYwLjIwMSA2MC44MDg2QzE2MC4wMjUgNjAuNzIyNyAxNTkuODE2IDYwLjY3OTcgMTU5LjU3NCA2MC42Nzk3QzE1OS4zMTYgNjAuNjc5NyAxNTkuMDk4IDYwLjczNDQgMTU4LjkxOCA2MC44NDM4QzE1OC43MzggNjAuOTUzMSAxNTguNTkgNjEuMTAzNSAxNTguNDczIDYxLjI5NDlDMTU4LjM1OSA2MS40ODYzIDE1OC4yNzUgNjEuNzA5IDE1OC4yMjEgNjEuOTYyOUMxNTguMTY2IDYyLjIxNjggMTU4LjEzOSA2Mi40ODgzIDE1OC4xMzkgNjIuNzc3M1pNMTcwLjgwOSA2NC43Mjg1VjYxLjcwNTFDMTcwLjgwOSA2MS40Nzg1IDE3MC43NjggNjEuMjgzMiAxNzAuNjg2IDYxLjExOTFDMTcwLjYwNCA2MC45NTUxIDE3MC40NzkgNjAuODI4MSAxNzAuMzExIDYwLjczODNDMTcwLjE0NiA2MC42NDg0IDE2OS45MzkgNjAuNjAzNSAxNjkuNjg5IDYwLjYwMzVDMTY5LjQ1OSA2MC42MDM1IDE2OS4yNiA2MC42NDI2IDE2OS4wOTIgNjAuNzIwN0MxNjguOTI0IDYwLjc5ODggMTY4Ljc5MyA2MC45MDQzIDE2OC42OTkgNjEuMDM3MUMxNjguNjA1IDYxLjE2OTkgMTY4LjU1OSA2MS4zMjAzIDE2OC41NTkgNjEuNDg4M0gxNjcuMTUyQzE2Ny4xNTIgNjEuMjM4MyAxNjcuMjEzIDYwLjk5NjEgMTY3LjMzNCA2MC43NjE3QzE2Ny40NTUgNjAuNTI3MyAxNjcuNjMxIDYwLjMxODQgMTY3Ljg2MSA2MC4xMzQ4QzE2OC4wOTIgNTkuOTUxMiAxNjguMzY3IDU5LjgwNjYgMTY4LjY4OCA1OS43MDEyQzE2OS4wMDggNTkuNTk1NyAxNjkuMzY3IDU5LjU0MyAxNjkuNzY2IDU5LjU0M0MxNzAuMjQyIDU5LjU0MyAxNzAuNjY0IDU5LjYyMyAxNzEuMDMxIDU5Ljc4MzJDMTcxLjQwMiA1OS45NDM0IDE3MS42OTMgNjAuMTg1NSAxNzEuOTA0IDYwLjUwOThDMTcyLjExOSA2MC44MzAxIDE3Mi4yMjcgNjEuMjMyNCAxNzIuMjI3IDYxLjcxNjhWNjQuNTM1MkMxNzIuMjI3IDY0LjgyNDIgMTcyLjI0NiA2NS4wODQgMTcyLjI4NSA2NS4zMTQ1QzE3Mi4zMjggNjUuNTQxIDE3Mi4zODkgNjUuNzM4MyAxNzIuNDY3IDY1LjkwNjJWNjZIMTcxLjAyQzE3MC45NTMgNjUuODQ3NyAxNzAuOSA2NS42NTQzIDE3MC44NjEgNjUuNDE5OUMxNzAuODI2IDY1LjE4MTYgMTcwLjgwOSA2NC45NTEyIDE3MC44MDkgNjQuNzI4NVpNMTcxLjAxNCA2Mi4xNDQ1TDE3MS4wMjUgNjMuMDE3NkgxNzAuMDEyQzE2OS43NSA2My4wMTc2IDE2OS41MiA2My4wNDMgMTY5LjMyIDYzLjA5MzhDMTY5LjEyMSA2My4xNDA2IDE2OC45NTUgNjMuMjEwOSAxNjguODIyIDYzLjMwNDdDMTY4LjY4OSA2My4zOTg0IDE2OC41OSA2My41MTE3IDE2OC41MjMgNjMuNjQ0NUMxNjguNDU3IDYzLjc3NzMgMTY4LjQyNCA2My45Mjc3IDE2OC40MjQgNjQuMDk1N0MxNjguNDI0IDY0LjI2MzcgMTY4LjQ2MyA2NC40MTggMTY4LjU0MSA2NC41NTg2QzE2OC42MTkgNjQuNjk1MyAxNjguNzMyIDY0LjgwMjcgMTY4Ljg4MSA2NC44ODA5QzE2OS4wMzMgNjQuOTU5IDE2OS4yMTcgNjQuOTk4IDE2OS40MzIgNjQuOTk4QzE2OS43MjEgNjQuOTk4IDE2OS45NzMgNjQuOTM5NSAxNzAuMTg4IDY0LjgyMjNDMTcwLjQwNiA2NC43MDEyIDE3MC41NzggNjQuNTU0NyAxNzAuNzAzIDY0LjM4MjhDMTcwLjgyOCA2NC4yMDcgMTcwLjg5NSA2NC4wNDEgMTcwLjkwMiA2My44ODQ4TDE3MS4zNTkgNjQuNTExN0MxNzEuMzEyIDY0LjY3MTkgMTcxLjIzMiA2NC44NDM4IDE3MS4xMTkgNjUuMDI3M0MxNzEuMDA2IDY1LjIxMDkgMTcwLjg1NyA2NS4zODY3IDE3MC42NzQgNjUuNTU0N0MxNzAuNDk0IDY1LjcxODggMTcwLjI3NyA2NS44NTM1IDE3MC4wMjMgNjUuOTU5QzE2OS43NzMgNjYuMDY0NSAxNjkuNDg0IDY2LjExNzIgMTY5LjE1NiA2Ni4xMTcyQzE2OC43NDIgNjYuMTE3MiAxNjguMzczIDY2LjAzNTIgMTY4LjA0OSA2NS44NzExQzE2Ny43MjUgNjUuNzAzMSAxNjcuNDcxIDY1LjQ3ODUgMTY3LjI4NyA2NS4xOTczQzE2Ny4xMDQgNjQuOTEyMSAxNjcuMDEyIDY0LjU4OTggMTY3LjAxMiA2NC4yMzA1QzE2Ny4wMTIgNjMuODk0NSAxNjcuMDc0IDYzLjU5NzcgMTY3LjE5OSA2My4zMzk4QzE2Ny4zMjggNjMuMDc4MSAxNjcuNTE2IDYyLjg1OTQgMTY3Ljc2MiA2Mi42ODM2QzE2OC4wMTIgNjIuNTA3OCAxNjguMzE2IDYyLjM3NSAxNjguNjc2IDYyLjI4NTJDMTY5LjAzNSA2Mi4xOTE0IDE2OS40NDUgNjIuMTQ0NSAxNjkuOTA2IDYyLjE0NDVIMTcxLjAxNFpNMTc4LjAxNCA1OS42NjAySDE3OS4yOTdWNjUuODI0MkMxNzkuMjk3IDY2LjM5NDUgMTc5LjE3NiA2Ni44Nzg5IDE3OC45MzQgNjcuMjc3M0MxNzguNjkxIDY3LjY3NTggMTc4LjM1NCA2Ny45Nzg1IDE3Ny45MiA2OC4xODU1QzE3Ny40ODYgNjguMzk2NSAxNzYuOTg0IDY4LjUwMiAxNzYuNDE0IDY4LjUwMkMxNzYuMTcyIDY4LjUwMiAxNzUuOTAyIDY4LjQ2NjggMTc1LjYwNSA2OC4zOTY1QzE3NS4zMTIgNjguMzI2MiAxNzUuMDI3IDY4LjIxMjkgMTc0Ljc1IDY4LjA1NjZDMTc0LjQ3NyA2Ny45MDQzIDE3NC4yNDggNjcuNzAzMSAxNzQuMDY0IDY3LjQ1MzFMMTc0LjcyNyA2Ni42MjExQzE3NC45NTMgNjYuODkwNiAxNzUuMjAzIDY3LjA4NzkgMTc1LjQ3NyA2Ny4yMTI5QzE3NS43NSA2Ny4zMzc5IDE3Ni4wMzcgNjcuNDAwNCAxNzYuMzM4IDY3LjQwMDRDMTc2LjY2MiA2Ny40MDA0IDE3Ni45MzggNjcuMzM5OCAxNzcuMTY0IDY3LjIxODhDMTc3LjM5NSA2Ny4xMDE2IDE3Ny41NzIgNjYuOTI3NyAxNzcuNjk3IDY2LjY5NzNDMTc3LjgyMiA2Ni40NjY4IDE3Ny44ODUgNjYuMTg1NSAxNzcuODg1IDY1Ljg1MzVWNjEuMDk1N0wxNzguMDE0IDU5LjY2MDJaTTE3My43MDcgNjIuOTAwNFY2Mi43NzczQzE3My43MDcgNjIuMjk2OSAxNzMuNzY2IDYxLjg1OTQgMTczLjg4MyA2MS40NjQ4QzE3NCA2MS4wNjY0IDE3NC4xNjggNjAuNzI0NiAxNzQuMzg3IDYwLjQzOTVDMTc0LjYwNSA2MC4xNTA0IDE3NC44NzEgNTkuOTI5NyAxNzUuMTg0IDU5Ljc3NzNDMTc1LjQ5NiA1OS42MjExIDE3NS44NSA1OS41NDMgMTc2LjI0NCA1OS41NDNDMTc2LjY1NCA1OS41NDMgMTc3LjAwNCA1OS42MTcyIDE3Ny4yOTMgNTkuNzY1NkMxNzcuNTg2IDU5LjkxNDEgMTc3LjgzIDYwLjEyNyAxNzguMDI1IDYwLjQwNDNDMTc4LjIyMSA2MC42Nzc3IDE3OC4zNzMgNjEuMDA1OSAxNzguNDgyIDYxLjM4ODdDMTc4LjU5NiA2MS43Njc2IDE3OC42OCA2Mi4xODk1IDE3OC43MzQgNjIuNjU0M1Y2My4wNDY5QzE3OC42ODQgNjMuNSAxNzguNTk4IDYzLjkxNDEgMTc4LjQ3NyA2NC4yODkxQzE3OC4zNTUgNjQuNjY0MSAxNzguMTk1IDY0Ljk4ODMgMTc3Ljk5NiA2NS4yNjE3QzE3Ny43OTcgNjUuNTM1MiAxNzcuNTUxIDY1Ljc0NjEgMTc3LjI1OCA2NS44OTQ1QzE3Ni45NjkgNjYuMDQzIDE3Ni42MjcgNjYuMTE3MiAxNzYuMjMyIDY2LjExNzJDMTc1Ljg0NiA2Ni4xMTcyIDE3NS40OTYgNjYuMDM3MSAxNzUuMTg0IDY1Ljg3N0MxNzQuODc1IDY1LjcxNjggMTc0LjYwOSA2NS40OTIyIDE3NC4zODcgNjUuMjAzMUMxNzQuMTY4IDY0LjkxNDEgMTc0IDY0LjU3NDIgMTczLjg4MyA2NC4xODM2QzE3My43NjYgNjMuNzg5MSAxNzMuNzA3IDYzLjM2MTMgMTczLjcwNyA2Mi45MDA0Wk0xNzUuMTE5IDYyLjc3NzNWNjIuOTAwNEMxNzUuMTE5IDYzLjE4OTUgMTc1LjE0NiA2My40NTkgMTc1LjIwMSA2My43MDlDMTc1LjI2IDYzLjk1OSAxNzUuMzQ4IDY0LjE3OTcgMTc1LjQ2NSA2NC4zNzExQzE3NS41ODYgNjQuNTU4NiAxNzUuNzM4IDY0LjcwNyAxNzUuOTIyIDY0LjgxNjRDMTc2LjEwOSA2NC45MjE5IDE3Ni4zMyA2NC45NzQ2IDE3Ni41ODQgNjQuOTc0NkMxNzYuOTE2IDY0Ljk3NDYgMTc3LjE4OCA2NC45MDQzIDE3Ny4zOTggNjQuNzYzN0MxNzcuNjEzIDY0LjYyMyAxNzcuNzc3IDY0LjQzMzYgMTc3Ljg5MSA2NC4xOTUzQzE3OC4wMDggNjMuOTUzMSAxNzguMDkgNjMuNjgzNiAxNzguMTM3IDYzLjM4NjdWNjIuMzI2MkMxNzguMTEzIDYyLjA5NTcgMTc4LjA2NCA2MS44ODA5IDE3Ny45OSA2MS42ODE2QzE3Ny45MiA2MS40ODI0IDE3Ny44MjQgNjEuMzA4NiAxNzcuNzAzIDYxLjE2MDJDMTc3LjU4MiA2MS4wMDc4IDE3Ny40MyA2MC44OTA2IDE3Ny4yNDYgNjAuODA4NkMxNzcuMDYyIDYwLjcyMjcgMTc2Ljg0NiA2MC42Nzk3IDE3Ni41OTYgNjAuNjc5N0MxNzYuMzQyIDYwLjY3OTcgMTc2LjEyMSA2MC43MzQ0IDE3NS45MzQgNjAuODQzOEMxNzUuNzQ2IDYwLjk1MzEgMTc1LjU5MiA2MS4xMDM1IDE3NS40NzEgNjEuMjk0OUMxNzUuMzU0IDYxLjQ4NjMgMTc1LjI2NiA2MS43MDkgMTc1LjIwNyA2MS45NjI5QzE3NS4xNDggNjIuMjE2OCAxNzUuMTE5IDYyLjQ4ODMgMTc1LjExOSA2Mi43NzczWk0xODAuNzQyIDYyLjkwMDRWNjIuNzY1NkMxODAuNzQyIDYyLjMwODYgMTgwLjgwOSA2MS44ODQ4IDE4MC45NDEgNjEuNDk0MUMxODEuMDc0IDYxLjA5OTYgMTgxLjI2NiA2MC43NTc4IDE4MS41MTYgNjAuNDY4OEMxODEuNzcgNjAuMTc1OCAxODIuMDc4IDU5Ljk0OTIgMTgyLjQ0MSA1OS43ODkxQzE4Mi44MDkgNTkuNjI1IDE4My4yMjMgNTkuNTQzIDE4My42ODQgNTkuNTQzQzE4NC4xNDggNTkuNTQzIDE4NC41NjIgNTkuNjI1IDE4NC45MjYgNTkuNzg5MUMxODUuMjkzIDU5Ljk0OTIgMTg1LjYwNCA2MC4xNzU4IDE4NS44NTcgNjAuNDY4OEMxODYuMTExIDYwLjc1NzggMTg2LjMwNSA2MS4wOTk2IDE4Ni40MzggNjEuNDk0MUMxODYuNTcgNjEuODg0OCAxODYuNjM3IDYyLjMwODYgMTg2LjYzNyA2Mi43NjU2VjYyLjkwMDRDMTg2LjYzNyA2My4zNTc0IDE4Ni41NyA2My43ODEyIDE4Ni40MzggNjQuMTcxOUMxODYuMzA1IDY0LjU2MjUgMTg2LjExMSA2NC45MDQzIDE4NS44NTcgNjUuMTk3M0MxODUuNjA0IDY1LjQ4NjMgMTg1LjI5NSA2NS43MTI5IDE4NC45MzIgNjUuODc3QzE4NC41NjggNjYuMDM3MSAxODQuMTU2IDY2LjExNzIgMTgzLjY5NSA2Ni4xMTcyQzE4My4yMyA2Ni4xMTcyIDE4Mi44MTQgNjYuMDM3MSAxODIuNDQ3IDY1Ljg3N0MxODIuMDg0IDY1LjcxMjkgMTgxLjc3NSA2NS40ODYzIDE4MS41MjEgNjUuMTk3M0MxODEuMjY4IDY0LjkwNDMgMTgxLjA3NCA2NC41NjI1IDE4MC45NDEgNjQuMTcxOUMxODAuODA5IDYzLjc4MTIgMTgwLjc0MiA2My4zNTc0IDE4MC43NDIgNjIuOTAwNFpNMTgyLjE1NCA2Mi43NjU2VjYyLjkwMDRDMTgyLjE1NCA2My4xODU1IDE4Mi4xODQgNjMuNDU1MSAxODIuMjQyIDYzLjcwOUMxODIuMzAxIDYzLjk2MjkgMTgyLjM5MyA2NC4xODU1IDE4Mi41MTggNjQuMzc3QzE4Mi42NDMgNjQuNTY4NCAxODIuODAzIDY0LjcxODggMTgyLjk5OCA2NC44MjgxQzE4My4xOTMgNjQuOTM3NSAxODMuNDI2IDY0Ljk5MjIgMTgzLjY5NSA2NC45OTIyQzE4My45NTcgNjQuOTkyMiAxODQuMTg0IDY0LjkzNzUgMTg0LjM3NSA2NC44MjgxQzE4NC41NyA2NC43MTg4IDE4NC43MyA2NC41Njg0IDE4NC44NTUgNjQuMzc3QzE4NC45OCA2NC4xODU1IDE4NS4wNzIgNjMuOTYyOSAxODUuMTMxIDYzLjcwOUMxODUuMTkzIDYzLjQ1NTEgMTg1LjIyNSA2My4xODU1IDE4NS4yMjUgNjIuOTAwNFY2Mi43NjU2QzE4NS4yMjUgNjIuNDg0NCAxODUuMTkzIDYyLjIxODggMTg1LjEzMSA2MS45Njg4QzE4NS4wNzIgNjEuNzE0OCAxODQuOTc5IDYxLjQ5MDIgMTg0Ljg1IDYxLjI5NDlDMTg0LjcyNSA2MS4wOTk2IDE4NC41NjQgNjAuOTQ3MyAxODQuMzY5IDYwLjgzNzlDMTg0LjE3OCA2MC43MjQ2IDE4My45NDkgNjAuNjY4IDE4My42ODQgNjAuNjY4QzE4My40MTggNjAuNjY4IDE4My4xODggNjAuNzI0NiAxODIuOTkyIDYwLjgzNzlDMTgyLjgwMSA2MC45NDczIDE4Mi42NDMgNjEuMDk5NiAxODIuNTE4IDYxLjI5NDlDMTgyLjM5MyA2MS40OTAyIDE4Mi4zMDEgNjEuNzE0OCAxODIuMjQyIDYxLjk2ODhDMTgyLjE4NCA2Mi4yMTg4IDE4Mi4xNTQgNjIuNDg0NCAxODIuMTU0IDYyLjc2NTZaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjM4Ii8+CjxwYXRoIGQ9Ik0yODMuNTc0IDYzLjEyNVY2OEgyNTguNzkzVjYzLjgxMDVMMjcwLjgyOCA1MC42ODM2QzI3Mi4xNDggNDkuMTk0IDI3My4xODkgNDcuOTA3NiAyNzMuOTUxIDQ2LjgyNDJDMjc0LjcxMyA0NS43NDA5IDI3NS4yNDYgNDQuNzY3NiAyNzUuNTUxIDQzLjkwNDNDMjc1Ljg3MiA0My4wMjQxIDI3Ni4wMzMgNDIuMTY5MyAyNzYuMDMzIDQxLjMzOThDMjc2LjAzMyA0MC4xNzE5IDI3NS44MTMgMzkuMTQ3OCAyNzUuMzczIDM4LjI2NzZDMjc0Ljk1IDM3LjM3MDQgMjc0LjMyNCAzNi42NjggMjczLjQ5NCAzNi4xNjAyQzI3Mi42NjUgMzUuNjM1NCAyNzEuNjU4IDM1LjM3MyAyNzAuNDczIDM1LjM3M0MyNjkuMTAyIDM1LjM3MyAyNjcuOTUxIDM1LjY2OTMgMjY3LjAyIDM2LjI2MTdDMjY2LjA4OSAzNi44NTQyIDI2NS4zODYgMzcuNjc1MSAyNjQuOTEyIDM4LjcyNDZDMjY0LjQzOCAzOS43NTcyIDI2NC4yMDEgNDAuOTQyMSAyNjQuMjAxIDQyLjI3OTNIMjU4LjA4MkMyNTguMDgyIDQwLjEyOTYgMjU4LjU3MyAzOC4xNjYgMjU5LjU1NSAzNi4zODg3QzI2MC41MzYgMzQuNTk0NCAyNjEuOTU4IDMzLjE3MjUgMjYzLjgyIDMyLjEyM0MyNjUuNjgyIDMxLjA1NjYgMjY3LjkyNSAzMC41MjM0IDI3MC41NDkgMzAuNTIzNEMyNzMuMDIgMzAuNTIzNCAyNzUuMTE5IDMwLjkzODIgMjc2Ljg0NiAzMS43Njc2QzI3OC41NzIgMzIuNTk3IDI3OS44ODQgMzMuNzczNCAyODAuNzgxIDM1LjI5NjlDMjgxLjY5NSAzNi44MjAzIDI4Mi4xNTIgMzguNjIzIDI4Mi4xNTIgNDAuNzA1MUMyODIuMTUyIDQxLjg1NjEgMjgxLjk2NiA0Mi45OTg3IDI4MS41OTQgNDQuMTMyOEMyODEuMjIxIDQ1LjI2NjkgMjgwLjY4OCA0Ni40MDEgMjc5Ljk5NCA0Ny41MzUyQzI3OS4zMTcgNDguNjUyMyAyNzguNTEzIDQ5Ljc3OCAyNzcuNTgyIDUwLjkxMjFDMjc2LjY1MSA1Mi4wMjkzIDI3NS42MjcgNTMuMTYzNCAyNzQuNTEgNTQuMzE0NUwyNjYuNTEyIDYzLjEyNUgyODMuNTc0Wk0zMTIuMjE5IDYzLjEyNVY2OEgyODcuNDM4VjYzLjgxMDVMMjk5LjQ3MyA1MC42ODM2QzMwMC43OTMgNDkuMTk0IDMwMS44MzQgNDcuOTA3NiAzMDIuNTk2IDQ2LjgyNDJDMzAzLjM1OCA0NS43NDA5IDMwMy44OTEgNDQuNzY3NiAzMDQuMTk1IDQzLjkwNDNDMzA0LjUxNyA0My4wMjQxIDMwNC42NzggNDIuMTY5MyAzMDQuNjc4IDQxLjMzOThDMzA0LjY3OCA0MC4xNzE5IDMwNC40NTggMzkuMTQ3OCAzMDQuMDE4IDM4LjI2NzZDMzAzLjU5NSAzNy4zNzA0IDMwMi45NjggMzYuNjY4IDMwMi4xMzkgMzYuMTYwMkMzMDEuMzA5IDM1LjYzNTQgMzAwLjMwMiAzNS4zNzMgMjk5LjExNyAzNS4zNzNDMjk3Ljc0NiAzNS4zNzMgMjk2LjU5NSAzNS42NjkzIDI5NS42NjQgMzYuMjYxN0MyOTQuNzMzIDM2Ljg1NDIgMjk0LjAzMSAzNy42NzUxIDI5My41NTcgMzguNzI0NkMyOTMuMDgzIDM5Ljc1NzIgMjkyLjg0NiA0MC45NDIxIDI5Mi44NDYgNDIuMjc5M0gyODYuNzI3QzI4Ni43MjcgNDAuMTI5NiAyODcuMjE4IDM4LjE2NiAyODguMTk5IDM2LjM4ODdDMjg5LjE4MSAzNC41OTQ0IDI5MC42MDMgMzMuMTcyNSAyOTIuNDY1IDMyLjEyM0MyOTQuMzI3IDMxLjA1NjYgMjk2LjU3IDMwLjUyMzQgMjk5LjE5NCAzMC41MjM0QzMwMS42NjUgMzAuNTIzNCAzMDMuNzY0IDMwLjkzODIgMzA1LjQ5IDMxLjc2NzZDMzA3LjIxNyAzMi41OTcgMzA4LjUyOSAzMy43NzM0IDMwOS40MjYgMzUuMjk2OUMzMTAuMzQgMzYuODIwMyAzMTAuNzk3IDM4LjYyMyAzMTAuNzk3IDQwLjcwNTFDMzEwLjc5NyA0MS44NTYxIDMxMC42MTEgNDIuOTk4NyAzMTAuMjM4IDQ0LjEzMjhDMzA5Ljg2NiA0NS4yNjY5IDMwOS4zMzMgNDYuNDAxIDMwOC42MzkgNDcuNTM1MkMzMDcuOTYyIDQ4LjY1MjMgMzA3LjE1OCA0OS43NzggMzA2LjIyNyA1MC45MTIxQzMwNS4yOTYgNTIuMDI5MyAzMDQuMjcyIDUzLjE2MzQgMzAzLjE1NCA1NC4zMTQ1TDI5NS4xNTYgNjMuMTI1SDMxMi4yMTlaTTMxNi41NjUgMzcuMzAyN0MzMTYuNTY1IDM2LjA2NzEgMzE2Ljg2OSAzNC45MzI5IDMxNy40NzkgMzMuOTAwNEMzMTguMDg4IDMyLjg2NzggMzE4LjkwMSAzMi4wNDY5IDMxOS45MTYgMzEuNDM3NUMzMjAuOTQ5IDMwLjgxMTIgMzIyLjA2NiAzMC40OTggMzIzLjI2OCAzMC40OThDMzI0LjQ4NyAzMC40OTggMzI1LjU5NSAzMC44MTEyIDMyNi41OTQgMzEuNDM3NUMzMjcuNTkzIDMyLjA0NjkgMzI4LjM4OCAzMi44Njc4IDMyOC45ODEgMzMuOTAwNEMzMjkuNTkgMzQuOTMyOSAzMjkuODk1IDM2LjA2NzEgMzI5Ljg5NSAzNy4zMDI3QzMyOS44OTUgMzguNTM4NCAzMjkuNTkgMzkuNjcyNSAzMjguOTgxIDQwLjcwNTFDMzI4LjM4OCA0MS43MjA3IDMyNy41OTMgNDIuNTI0NyAzMjYuNTk0IDQzLjExNzJDMzI1LjU5NSA0My43MDk2IDMyNC40ODcgNDQuMDA1OSAzMjMuMjY4IDQ0LjAwNTlDMzIyLjA2NiA0NC4wMDU5IDMyMC45NDkgNDMuNzA5NiAzMTkuOTE2IDQzLjExNzJDMzE4LjkwMSA0Mi41MjQ3IDMxOC4wODggNDEuNzIwNyAzMTcuNDc5IDQwLjcwNTFDMzE2Ljg2OSAzOS42NzI1IDMxNi41NjUgMzguNTM4NCAzMTYuNTY1IDM3LjMwMjdaTTMxOS45OTMgMzcuMzAyN0MzMTkuOTkzIDM4LjIxNjggMzIwLjMxNCAzOC45ODcgMzIwLjk1NyAzOS42MTMzQzMyMS42MDEgNDAuMjIyNyAzMjIuMzcxIDQwLjUyNzMgMzIzLjI2OCA0MC41MjczQzMyNC4xNjUgNDAuNTI3MyAzMjQuOTE4IDQwLjIyMjcgMzI1LjUyOCAzOS42MTMzQzMyNi4xMzcgMzkuMDAzOSAzMjYuNDQyIDM4LjIzMzcgMzI2LjQ0MiAzNy4zMDI3QzMyNi40NDIgMzYuMzU0OCAzMjYuMTM3IDM1LjU2NzcgMzI1LjUyOCAzNC45NDE0QzMyNC45MTggMzQuMzE1MSAzMjQuMTY1IDM0LjAwMiAzMjMuMjY4IDM0LjAwMkMzMjIuMzcxIDM0LjAwMiAzMjEuNjAxIDM0LjMxNTEgMzIwLjk1NyAzNC45NDE0QzMyMC4zMTQgMzUuNTY3NyAzMTkuOTkzIDM2LjM1NDggMzE5Ljk5MyAzNy4zMDI3Wk0zNTcuODc5IDU1Ljk2NDhIMzY0LjIyN0MzNjQuMDI0IDU4LjM4NTQgMzYzLjM0NyA2MC41NDM2IDM2Mi4xOTYgNjIuNDM5NUMzNjEuMDQ1IDY0LjMxODQgMzU5LjQyOCA2NS43OTk1IDM1Ny4zNDYgNjYuODgyOEMzNTUuMjY0IDY3Ljk2NjEgMzUyLjczNCA2OC41MDc4IDM0OS43NTQgNjguNTA3OEMzNDcuNDY5IDY4LjUwNzggMzQ1LjQxMyA2OC4xMDE2IDM0My41ODQgNjcuMjg5MUMzNDEuNzU2IDY2LjQ1OTYgMzQwLjE5MSA2NS4yOTE3IDMzOC44ODcgNjMuNzg1MkMzMzcuNTg0IDYyLjI2MTcgMzM2LjU4NSA2MC40MjUxIDMzNS44OTEgNTguMjc1NEMzMzUuMjE0IDU2LjEyNTcgMzM0Ljg3NSA1My43MjIgMzM0Ljg3NSA1MS4wNjQ1VjQ3Ljk5MjJDMzM0Ljg3NSA0NS4zMzQ2IDMzNS4yMjIgNDIuOTMxIDMzNS45MTYgNDAuNzgxMkMzMzYuNjI3IDM4LjYzMTUgMzM3LjY0MyAzNi43OTQ5IDMzOC45NjMgMzUuMjcxNUMzNDAuMjg0IDMzLjczMTEgMzQxLjg2NiAzMi41NTQ3IDM0My43MTEgMzEuNzQyMkMzNDUuNTczIDMwLjkyOTcgMzQ3LjY2NCAzMC41MjM0IDM0OS45ODMgMzAuNTIzNEMzNTIuOTI4IDMwLjUyMzQgMzU1LjQxNiAzMS4wNjUxIDM1Ny40NDggMzIuMTQ4NEMzNTkuNDc5IDMzLjIzMTggMzYxLjA1MyAzNC43Mjk4IDM2Mi4xNyAzNi42NDI2QzM2My4zMDUgMzguNTU1MyAzNjMuOTk5IDQwLjc0NzQgMzY0LjI1MiA0My4yMTg4SDM1Ny45MDVDMzU3LjczNSA0MS42Mjc2IDM1Ny4zNjMgNDAuMjY1IDM1Ni43ODggMzkuMTMwOUMzNTYuMjI5IDM3Ljk5NjcgMzU1LjQgMzcuMTMzNSAzNTQuMjk5IDM2LjU0MUMzNTMuMTk5IDM1LjkzMTYgMzUxLjc2IDM1LjYyNyAzNDkuOTgzIDM1LjYyN0MzNDguNTI3IDM1LjYyNyAzNDcuMjU4IDM1Ljg5NzggMzQ2LjE3NCAzNi40Mzk1QzM0NS4wOTEgMzYuOTgxMSAzNDQuMTg1IDM3Ljc3NjcgMzQzLjQ1NyAzOC44MjYyQzM0Mi43MyAzOS44NzU3IDM0Mi4xOCA0MS4xNzA2IDM0MS44MDcgNDIuNzEwOUMzNDEuNDUyIDQ0LjIzNDQgMzQxLjI3NCA0NS45Nzc5IDM0MS4yNzQgNDcuOTQxNFY1MS4wNjQ1QzM0MS4yNzQgNTIuOTI2NCAzNDEuNDM1IDU0LjYxOTEgMzQxLjc1NiA1Ni4xNDI2QzM0Mi4wOTUgNTcuNjQ5MSAzNDIuNjAzIDU4Ljk0NCAzNDMuMjggNjAuMDI3M0MzNDMuOTc0IDYxLjExMDcgMzQ0Ljg1NCA2MS45NDg2IDM0NS45MiA2Mi41NDFDMzQ2Ljk4NyA2My4xMzM1IDM0OC4yNjUgNjMuNDI5NyAzNDkuNzU0IDYzLjQyOTdDMzUxLjU2NiA2My40Mjk3IDM1My4wMyA2My4xNDE5IDM1NC4xNDcgNjIuNTY2NEMzNTUuMjgxIDYxLjk5MDkgMzU2LjEzNiA2MS4xNTMgMzU2LjcxMSA2MC4wNTI3QzM1Ny4zMDQgNTguOTM1NSAzNTcuNjkzIDU3LjU3MjkgMzU3Ljg3OSA1NS45NjQ4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8L2c+CjxkZWZzPgo8ZmlsdGVyIGlkPSJmaWx0ZXIwX2RfMTI0Nl80NDQ0NyIgeD0iMCIgeT0iMCIgd2lkdGg9IjM5OSIgaGVpZ2h0PSIxMDgiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz4KPGZlQ29sb3JNYXRyaXggaW49IlNvdXJjZUFscGhhIiB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMTI3IDAiIHJlc3VsdD0iaGFyZEFscGhhIi8+CjxmZU9mZnNldCBkeT0iNCIvPgo8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI0Ii8+CjxmZUNvbXBvc2l0ZSBpbjI9ImhhcmRBbHBoYSIgb3BlcmF0b3I9Im91dCIvPgo8ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMC4wNCAwIi8+CjxmZUJsZW5kIG1vZGU9Im5vcm1hbCIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0iZWZmZWN0MV9kcm9wU2hhZG93XzEyNDZfNDQ0NDciLz4KPGZlQmxlbmQgbW9kZT0ibm9ybWFsIiBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3dfMTI0Nl80NDQ0NyIgcmVzdWx0PSJzaGFwZSIvPgo8L2ZpbHRlcj4KPC9kZWZzPgo8L3N2Zz4K", "description": "Designed to display single value of the selected attribute or timeseries data. Widget styles are customizable.", "descriptor": { "type": "latest", @@ -259,10 +259,10 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px'\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n absoluteHeader: true\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", - "settingsDirective": "", + "settingsDirective": "tb-value-card-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-value-card-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\"}" diff --git a/ui-ngx/src/app/core/services/dashboard-utils.service.ts b/ui-ngx/src/app/core/services/dashboard-utils.service.ts index 8355ce2f61..a2a33b73a1 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -348,10 +348,8 @@ export class DashboardUtilsService { private convertDatasourcesFromWidgetType(widgetTypeDescriptor: WidgetTypeDescriptor, config: WidgetConfig, datasources?: Datasource[]): Datasource[] { const newDatasources: Datasource[] = []; - if (datasources) { - datasources.forEach(datasource => { - newDatasources.push(this.convertDatasourceFromWidgetType(widgetTypeDescriptor, config, datasource)); - }); + if (datasources?.length) { + newDatasources.push(this.convertDatasourceFromWidgetType(widgetTypeDescriptor, config, datasources[0])); } return newDatasources; } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss index 6c3b90da84..3856547508 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.scss @@ -21,9 +21,9 @@ position: relative; } @media #{$mat-gt-xs} { - width: 1200px; + width: 900px; .mat-mdc-dialog-content { - height: 600px; + height: 900px; } } } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index 39940546c2..cead69ab46 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -1177,6 +1177,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC Widget>(AddWidgetDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + maxWidth: '95vw', data: { dashboard: this.dashboard, aliasController: this.dashboardCtx.aliasController, diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss index a82f9c2f8b..e86f828111 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss @@ -45,6 +45,8 @@ } .preview { + width: 100%; + height: 100%; max-width: 100%; max-height: 100%; object-fit: contain; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html index b5808a8c96..51bb854826 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html @@ -55,7 +55,7 @@
-
+
{{ 'widgets.value-card.icon' | translate }} @@ -87,18 +87,38 @@
-
-
- - {{ 'widgets.value-card.date' | translate }} - -
- - - - - +
+ + {{ 'widgets.value-card.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + +
+ + diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts index 762b26ac42..f00ec8e2e6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts @@ -74,6 +74,16 @@ export class ValueCardBasicConfigComponent extends BasicWidgetConfigComponent { datePreviewFn = this._datePreviewFn.bind(this); + get dateEnabled(): boolean { + const layout: ValueCardLayout = this.valueCardWidgetConfigForm.get('layout').value; + return ![ValueCardLayout.vertical, ValueCardLayout.simplified].includes(layout); + } + + get iconEnabled(): boolean { + const layout: ValueCardLayout = this.valueCardWidgetConfigForm.get('layout').value; + return layout !== ValueCardLayout.simplified; + } + constructor(protected store: Store, protected widgetConfigComponent: WidgetConfigComponent, private cd: ChangeDetectorRef, diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html index b603f98a4d..22c4c2aace 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html @@ -22,7 +22,7 @@ {{ 'datakey.latest' | translate }} - + @@ -44,7 +44,7 @@ matTooltipPosition="above">timeline
-
+
@@ -139,7 +139,7 @@ - +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss index 41a003985e..fabd561a97 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.scss @@ -38,7 +38,16 @@ } .tb-source-field { - width: 140px; + width: 120px; + min-width: 120px; + } + + .tb-key-field { + flex: 1 1 60%; + } + + .tb-label-field { + flex: 1 1 40%; } .tb-color-field, .tb-units-field, .tb-decimals-field { @@ -50,9 +59,11 @@ .tb-units-field { width: 80px; + min-width: 80px; } .tb-color-field, .tb-decimals-field { width: 60px; + min-width: 60px; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html index 03e1b4761b..a2cddcde90 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html @@ -20,8 +20,8 @@
datakey.source
-
datakey.key
-
datakey.label
+
datakey.key
+
datakey.label
datakey.color
widget-config.units-short
widget-config.decimals-short
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.scss index 6ce13d7adc..7d33fd50a4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.scss @@ -15,15 +15,25 @@ */ .tb-form-table-header-cell { &.tb-source-header { - width: 140px; + width: 120px; + min-width: 120px; + } + &.tb-key-header { + flex: 1 1 60%; + } + &.tb-label-header { + flex: 1 1 40%; } &.tb-units-header { width: 80px; + min-width: 80px; } &.tb-color-header, &.tb-decimals-header { width: 60px; + min-width: 60px; } &.tb-actions-header { width: 114px; + min-width: 114px; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html index 0b4c774393..e024af20ee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html @@ -65,7 +65,7 @@ {{key.label}}
:
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss index 7d01f41cb5..415c69ec53 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss @@ -65,9 +65,11 @@ font-weight: normal; font-size: 14px; line-height: 20px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + &.tb-chip-text { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } .mat-icon.tb-datakey-icon { margin-right: 4px; margin-left: 4px; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts index cc482bfd4e..bf2144cdfd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.component.ts @@ -44,6 +44,7 @@ import { widgetSettingsComponentsMap } from '@home/components/widget/lib/setting import { Dashboard } from '@shared/models/dashboard.models'; import { WidgetService } from '@core/http/widget.service'; import { IAliasController } from '@core/api/widget-api.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; @Component({ selector: 'tb-widget-settings', @@ -73,6 +74,9 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On @Input() widget: Widget; + @Input() + widgetConfig: WidgetConfigComponentData; + private settingsDirective: string; definedDirectiveError: string; @@ -126,6 +130,11 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On this.definedSettingsComponent.aliasController = this.aliasController; } } + if (propName === 'widgetConfig') { + if (this.definedSettingsComponent) { + this.definedSettingsComponent.widgetConfig = this.widgetConfig; + } + } } } } @@ -214,6 +223,7 @@ export class WidgetSettingsComponent implements ControlValueAccessor, OnInit, On this.definedSettingsComponent.aliasController = this.aliasController; this.definedSettingsComponent.dashboard = this.dashboard; this.definedSettingsComponent.widget = this.widget; + this.definedSettingsComponent.widgetConfig = this.widgetConfig; this.definedSettingsComponent.functionScopeVariables = this.widgetService.getWidgetScopeVariables(); this.changeSubscription = this.definedSettingsComponent.settingsChanged.subscribe((settings) => { this.updateModel(settings); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts index 34f2ac464b..0fa061de72 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts @@ -276,6 +276,14 @@ export enum BackgroundType { color = 'color' } +export const backgroundTypeTranslations = new Map( + [ + [BackgroundType.image, 'widgets.background.background-type-image'], + [BackgroundType.imageUrl, 'widgets.background.background-type-image-url'], + [BackgroundType.color, 'widgets.background.background-type-color'] + ] +); + export interface OverlaySettings { enabled: boolean; color: string; @@ -313,11 +321,13 @@ export const backgroundStyle = (background: BackgroundSettings): ComponentStyle }; } else { const imageUrl = background.type === BackgroundType.image ? background.imageBase64 : background.imageUrl; - return { - background: `url(${imageUrl}) no-repeat`, - backgroundSize: 'cover', - backgroundPosition: '50% 50%' - }; + if (imageUrl) { + return { + background: `url(${imageUrl}) no-repeat 50% 50% / cover` + }; + } else { + return {}; + } } }; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html new file mode 100644 index 0000000000..423c727a8d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html @@ -0,0 +1,89 @@ + + +
+
widgets.value-card.value-card-style
+ + + {{ valueCardLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.value-card.label' | translate }} + +
+ + + + +
+
+
+ + {{ 'widgets.value-card.icon' | translate }} + +
+ + + + + + + + +
+
+
+
widgets.value-card.value
+
+ + + + +
+
+
+ + {{ 'widgets.value-card.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts new file mode 100644 index 0000000000..6f76546ac1 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts @@ -0,0 +1,200 @@ +/// +/// Copyright © 2016-2023 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 { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { + valueCardDefaultSettings, + ValueCardLayout, valueCardLayoutImages, + valueCardLayouts, valueCardLayoutTranslations +} from '@home/components/widget/lib/cards/value-card-widget.models'; +import { formatValue, isDefinedAndNotNull } from '@core/utils'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { + DateFormatProcessor, + DateFormatSettings, + getLabel +} from '@home/components/widget/config/widget-settings.models'; + +@Component({ + selector: 'tb-value-card-widget-settings', + templateUrl: './value-card-widget-settings.component.html', + styleUrls: [] +}) +export class ValueCardWidgetSettingsComponent extends WidgetSettingsComponent { + + valueCardLayouts: ValueCardLayout[] = []; + + valueCardLayoutTranslationMap = valueCardLayoutTranslations; + valueCardLayoutImageMap = valueCardLayoutImages; + + horizontal = false; + + valueCardWidgetSettingsForm: UntypedFormGroup; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + datePreviewFn = this._datePreviewFn.bind(this); + + + get label(): string { + return getLabel(this.widgetConfig.config.datasources); + } + + get dateEnabled(): boolean { + const layout: ValueCardLayout = this.valueCardWidgetSettingsForm.get('layout').value; + return ![ValueCardLayout.vertical, ValueCardLayout.simplified].includes(layout); + } + + get iconEnabled(): boolean { + const layout: ValueCardLayout = this.valueCardWidgetSettingsForm.get('layout').value; + return layout !== ValueCardLayout.simplified; + } + + constructor(protected store: Store, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.valueCardWidgetSettingsForm; + } + + protected onWidgetConfigSet(widgetConfig: WidgetConfigComponentData) { + const params = widgetConfig.typeParameters as any; + this.horizontal = isDefinedAndNotNull(params.horizontal) ? params.horizontal : false; + this.valueCardLayouts = valueCardLayouts(this.horizontal); + } + + protected defaultSettings(): WidgetSettings { + return valueCardDefaultSettings(this.horizontal); + } + + protected onSettingsSet(settings: WidgetSettings) { + this.valueCardWidgetSettingsForm = this.fb.group({ + layout: [settings.layout, []], + + showLabel: [settings.showLabel, []], + labelFont: [settings.labelFont, []], + labelColor: [settings.labelColor, []], + + showIcon: [settings.showIcon, []], + iconSize: [settings.iconSize, [Validators.min(0)]], + iconSizeUnit: [settings.iconSizeUnit, []], + icon: [settings.icon, []], + iconColor: [settings.iconColor, []], + + valueFont: [settings.valueFont, []], + valueColor: [settings.valueColor, []], + + showDate: [settings.showDate, []], + dateFormat: [settings.dateFormat, []], + dateFont: [settings.dateFont, []], + dateColor: [settings.dateColor, []], + + background: [settings.background, []] + }); + } + + protected validatorTriggers(): string[] { + return ['layout', 'showLabel', 'showIcon', 'showDate']; + } + + protected updateValidators(emitEvent: boolean) { + const layout: ValueCardLayout = this.valueCardWidgetSettingsForm.get('layout').value; + const showLabel: boolean = this.valueCardWidgetSettingsForm.get('showLabel').value; + const showIcon: boolean = this.valueCardWidgetSettingsForm.get('showIcon').value; + const showDate: boolean = this.valueCardWidgetSettingsForm.get('showDate').value; + + const dateEnabled = ![ValueCardLayout.vertical, ValueCardLayout.simplified].includes(layout); + const iconEnabled = layout !== ValueCardLayout.simplified; + + if (showLabel) { + this.valueCardWidgetSettingsForm.get('labelFont').enable(); + this.valueCardWidgetSettingsForm.get('labelColor').enable(); + } else { + this.valueCardWidgetSettingsForm.get('labelFont').disable(); + this.valueCardWidgetSettingsForm.get('labelColor').disable(); + } + + if (iconEnabled) { + this.valueCardWidgetSettingsForm.get('showIcon').enable({emitEvent: false}); + if (showIcon) { + this.valueCardWidgetSettingsForm.get('iconSize').enable(); + this.valueCardWidgetSettingsForm.get('iconSizeUnit').enable(); + this.valueCardWidgetSettingsForm.get('icon').enable(); + this.valueCardWidgetSettingsForm.get('iconColor').enable(); + } else { + this.valueCardWidgetSettingsForm.get('iconSize').disable(); + this.valueCardWidgetSettingsForm.get('iconSizeUnit').disable(); + this.valueCardWidgetSettingsForm.get('icon').disable(); + this.valueCardWidgetSettingsForm.get('iconColor').disable(); + } + } else { + this.valueCardWidgetSettingsForm.get('showIcon').disable({emitEvent: false}); + this.valueCardWidgetSettingsForm.get('iconSize').disable(); + this.valueCardWidgetSettingsForm.get('iconSizeUnit').disable(); + this.valueCardWidgetSettingsForm.get('icon').disable(); + this.valueCardWidgetSettingsForm.get('iconColor').disable(); + } + + if (dateEnabled) { + this.valueCardWidgetSettingsForm.get('showDate').enable({emitEvent: false}); + if (showDate) { + this.valueCardWidgetSettingsForm.get('dateFormat').enable(); + this.valueCardWidgetSettingsForm.get('dateFont').enable(); + this.valueCardWidgetSettingsForm.get('dateColor').enable(); + } else { + this.valueCardWidgetSettingsForm.get('dateFormat').disable(); + this.valueCardWidgetSettingsForm.get('dateFont').disable(); + this.valueCardWidgetSettingsForm.get('dateColor').disable(); + } + } else { + this.valueCardWidgetSettingsForm.get('showDate').disable({emitEvent: false}); + this.valueCardWidgetSettingsForm.get('dateFormat').disable(); + this.valueCardWidgetSettingsForm.get('dateFont').disable(); + this.valueCardWidgetSettingsForm.get('dateColor').disable(); + } + this.valueCardWidgetSettingsForm.get('showIcon').updateValueAndValidity({emitEvent: false}); + this.valueCardWidgetSettingsForm.get('showDate').updateValueAndValidity({emitEvent: false}); + this.valueCardWidgetSettingsForm.get('labelFont').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('labelColor').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('iconSize').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('iconSizeUnit').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('icon').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('iconColor').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('dateFormat').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('dateFont').updateValueAndValidity({emitEvent}); + this.valueCardWidgetSettingsForm.get('dateColor').updateValueAndValidity({emitEvent}); + } + + private _valuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(22, decimals, units, true); + } + + private _datePreviewFn(): string { + const dateFormat: DateFormatSettings = this.valueCardWidgetSettingsForm.get('dateFormat').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 new file mode 100644 index 0000000000..ca5d4bc8b9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.html @@ -0,0 +1,87 @@ + +
+
widgets.background.background-settings
+
+
+
widgets.background.background
+ + + {{ backgroundTypeTranslationsMap.get(type) | translate }} + + +
+ +
+
widgets.background.image-url
+ + + +
+
+
widgets.color.color
+ + +
+
+
+
widgets.background.overlay
+ + {{ 'widgets.background.enable-overlay' | translate }} + +
+
widgets.color.color
+ + +
+
+
widgets.background.blur
+ + +
px
+
+
+
+
+
+ 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 new file mode 100644 index 0000000000..258117512a --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.scss @@ -0,0 +1,73 @@ +/** + * Copyright © 2016-2023 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-background-settings-panel { + width: 620px; + display: flex; + flex-direction: column; + gap: 16px; + @media #{$mat-lt-md} { + width: 90vw; + } + .tb-background-settings-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-background-settings-preview { + flex: 1; + background: rgba(0, 0, 0, 0.04); + display: flex; + flex-direction: column; + padding: 12px 16px 24px 16px; + align-items: center; + gap: 12px; + } + .tb-background-settings-preview-title { + align-self: stretch; + font-size: 16px; + font-style: normal; + font-weight: 500; + line-height: 24px; + color: rgba(0, 0, 0, 0.38); + } + .tb-background-settings-preview-box { + position: relative; + width: 136px; + height: 118px; + border-radius: 2.666px; + } + .tb-background-settings-preview-overlay { + position: absolute; + border-radius: 2.666px; + top: 7.998px; + bottom: 7.998px; + left: 7.998px; + right: 7.998px; + } + .tb-background-settings-panel-buttons { + height: 40px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} 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 new file mode 100644 index 0000000000..51d2ddec1b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings-panel.component.ts @@ -0,0 +1,120 @@ +/// +/// Copyright © 2016-2023 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, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { + backgroundStyle, + overlayStyle, + BackgroundSettings, + BackgroundType, + backgroundTypeTranslations, ComponentStyle +} from '@home/components/widget/config/widget-settings.models'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; + +@Component({ + selector: 'tb-background-settings-panel', + templateUrl: './background-settings-panel.component.html', + providers: [], + styleUrls: ['./background-settings-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class BackgroundSettingsPanelComponent extends PageComponent implements OnInit { + + @Input() + backgroundSettings: BackgroundSettings; + + @Input() + popover: TbPopoverComponent; + + @Output() + backgroundSettingsApplied = new EventEmitter(); + + backgroundType = BackgroundType; + + backgroundTypes = Object.keys(BackgroundType) as BackgroundType[]; + + backgroundTypeTranslationsMap = backgroundTypeTranslations; + + backgroundSettingsFormGroup: UntypedFormGroup; + + backgroundStyle: ComponentStyle = {}; + overlayStyle: ComponentStyle = {}; + + constructor(private fb: UntypedFormBuilder, + protected store: Store) { + super(store); + } + + ngOnInit(): void { + 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({ + enabled: [this.backgroundSettings?.overlay?.enabled, []], + color: [this.backgroundSettings?.overlay?.color, []], + blur: [this.backgroundSettings?.overlay?.blur, []] + }) + } + ); + this.backgroundSettingsFormGroup.get('type').valueChanges.subscribe(() => { + setTimeout(() => {this.popover?.updatePosition();}, 0); + }); + this.backgroundSettingsFormGroup.get('overlay').get('enabled').valueChanges.subscribe(() => { + this.updateValidators(); + }); + this.backgroundSettingsFormGroup.valueChanges.subscribe(() => { + this.updateBackgroundStyle(); + }); + this.updateValidators(); + this.updateBackgroundStyle(); + } + + cancel() { + this.popover?.hide(); + } + + applyColorSettings() { + const backgroundSettings = this.backgroundSettingsFormGroup.value; + this.backgroundSettingsApplied.emit(backgroundSettings); + } + + 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(); + } else { + this.backgroundSettingsFormGroup.get('overlay').get('color').disable(); + this.backgroundSettingsFormGroup.get('overlay').get('blur').disable(); + } + this.backgroundSettingsFormGroup.get('overlay').get('color').updateValueAndValidity({emitEvent: false}); + this.backgroundSettingsFormGroup.get('overlay').get('blur').updateValueAndValidity({emitEvent: false}); + } + + private updateBackgroundStyle() { + const background: BackgroundSettings = this.backgroundSettingsFormGroup.value; + this.backgroundStyle = backgroundStyle(background); + this.overlayStyle = overlayStyle(background.overlay); + } + +} 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 new file mode 100644 index 0000000000..e9e1b99b0e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.html @@ -0,0 +1,30 @@ + + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.scss new file mode 100644 index 0000000000..6f73fbffa4 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.scss @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2023 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. + */ +button.mat-mdc-button-base.tb-box-button.tb-background-settings { + padding: 0; + .mat-mdc-button-persistent-ripple { + z-index: 2; + } + .tb-color-preview { + width: 38px; + min-width: 38px; + height: 38px; + &.box { + .tb-color-result { + &:after { + border: none; + } + } + .tb-color-overlay { + position: absolute; + border-radius: 3px; + top: 4px; + bottom: 4px; + left: 4px; + right: 4px; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts new file mode 100644 index 0000000000..f8162575a3 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts @@ -0,0 +1,120 @@ +/// +/// Copyright © 2016-2023 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, forwardRef, Input, OnInit, Renderer2, ViewContainerRef, ViewEncapsulation } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { + BackgroundSettings, + backgroundStyle, + BackgroundType, + ComponentStyle, + overlayStyle +} from '@home/components/widget/config/widget-settings.models'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { + BackgroundSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/background-settings-panel.component'; + +@Component({ + selector: 'tb-background-settings', + templateUrl: './background-settings.component.html', + styleUrls: ['./background-settings.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => BackgroundSettingsComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None +}) +export class BackgroundSettingsComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + backgroundType = BackgroundType; + + modelValue: BackgroundSettings; + + backgroundStyle: ComponentStyle = {}; + + overlayStyle: ComponentStyle = {}; + + private propagateChange = null; + + constructor(private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + this.updateBackgroundStyle(); + } + + writeValue(value: BackgroundSettings): void { + this.modelValue = value; + this.updateBackgroundStyle(); + } + + openBackgroundSettingsPopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + backgroundSettings: this.modelValue + }; + const backgroundSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, BackgroundSettingsPanelComponent, 'left', true, null, + ctx, + {}, + {}, {}, true); + backgroundSettingsPanelPopover.tbComponentRef.instance.popover = backgroundSettingsPanelPopover; + backgroundSettingsPanelPopover.tbComponentRef.instance.backgroundSettingsApplied.subscribe((backgroundSettings) => { + backgroundSettingsPanelPopover.hide(); + this.modelValue = backgroundSettings; + this.updateBackgroundStyle(); + this.propagateChange(this.modelValue); + }); + } + } + + private updateBackgroundStyle() { + if (!this.disabled) { + this.backgroundStyle = backgroundStyle(this.modelValue); + this.overlayStyle = overlayStyle(this.modelValue.overlay); + } else { + this.backgroundStyle = {}; + this.overlayStyle = {}; + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts index e538653703..d75c4a5fc9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.ts @@ -21,14 +21,14 @@ import { Directive, ElementRef, forwardRef, - Input, + Input, OnChanges, OnDestroy, OnInit, - QueryList, + QueryList, SimpleChanges, ViewEncapsulation } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; import { coerceBoolean } from '@shared/decorators/coercion'; -import { Observable, Subject } from 'rxjs'; +import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs'; import { map, share, startWith, takeUntil } from 'rxjs/operators'; import { BreakpointObserver } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; @@ -73,7 +73,7 @@ export class ImageCardsSelectOptionDirective { ], encapsulation: ViewEncapsulation.None }) -export class ImageCardsSelectComponent implements ControlValueAccessor, OnInit, AfterContentInit, OnDestroy { +export class ImageCardsSelectComponent implements ControlValueAccessor, OnInit, OnChanges, AfterContentInit, OnDestroy { @ContentChildren(ImageCardsSelectOptionDirective) imageCardsSelectOptions: QueryList; @@ -107,20 +107,33 @@ export class ImageCardsSelectComponent implements ControlValueAccessor, OnInit, private _destroyed = new Subject(); + private _colsChanged = new BehaviorSubject(null); + constructor(private breakpointObserver: BreakpointObserver) { this.valueFormControl = new UntypedFormControl(''); } ngOnInit(): void { const gridColumns = this.breakpointObserver.isMatched(MediaBreakpoints['lt-md']) ? this.colsLtMd : this.cols; - this.cols$ = this.breakpointObserver - .observe(MediaBreakpoints['lt-md']).pipe( - map((state) => state.matches ? this.colsLtMd : this.cols), + this.cols$ = combineLatest({state: this.breakpointObserver + .observe(MediaBreakpoints['lt-md']), colsChanged: this._colsChanged.asObservable()}).pipe( + map((data) => data.state.matches ? this.colsLtMd : this.cols), startWith(gridColumns), share() ); } + ngOnChanges(changes: SimpleChanges): void { + for (const propName of Object.keys(changes)) { + const change = changes[propName]; + if (!change.firstChange && change.currentValue !== change.previousValue) { + if (['cols', 'colsLtMd'].includes(propName)) { + this._colsChanged.next(null); + } + } + } + } + ngAfterContentInit(): void { this.imageCardsSelectOptions.changes.pipe(startWith(null), takeUntil(this._destroyed)).subscribe(() => { this.syncImageCardsSelectOptions(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index 68b84578c1..748d90649d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -281,6 +281,13 @@ import { DateFormatSelectComponent } from '@home/components/widget/lib/settings/ import { DateFormatSettingsPanelComponent } from '@home/components/widget/lib/settings/common/date-format-settings-panel.component'; +import { BackgroundSettingsComponent } from '@home/components/widget/lib/settings/common/background-settings.component'; +import { + BackgroundSettingsPanelComponent +} from '@home/components/widget/lib/settings/common/background-settings-panel.component'; +import { + ValueCardWidgetSettingsComponent +} from '@home/components/widget/lib/settings/cards/value-card-widget-settings.component'; @NgModule({ declarations: [ @@ -391,7 +398,10 @@ import { ColorSettingsPanelComponent, CssUnitSelectComponent, DateFormatSelectComponent, - DateFormatSettingsPanelComponent + DateFormatSettingsPanelComponent, + BackgroundSettingsComponent, + BackgroundSettingsPanelComponent, + ValueCardWidgetSettingsComponent ], imports: [ CommonModule, @@ -506,7 +516,10 @@ import { ColorSettingsPanelComponent, CssUnitSelectComponent, DateFormatSelectComponent, - DateFormatSettingsPanelComponent + DateFormatSettingsPanelComponent, + BackgroundSettingsComponent, + BackgroundSettingsPanelComponent, + ValueCardWidgetSettingsComponent ] }) export class WidgetSettingsModule { @@ -575,5 +588,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html index 6601aa96db..43b54884ec 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html @@ -19,7 +19,6 @@ [fullscreenBackgroundStyle]="dashboardStyle" [fullscreenBackgroundImage]="backgroundImage" (fullscreenChanged)="onFullscreenChanged($event)" - fxLayout="column" class="tb-widget" [ngClass]="{ 'tb-highlighted': isHighlighted(widget), @@ -32,8 +31,11 @@ (mousedown)="onMouseDown($event)" (click)="onClicked($event)" (contextmenu)="onContextMenu($event)"> -
-
+
+
-
- + diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss index a364189372..52caeb2a5c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss @@ -14,9 +14,14 @@ * limitations under the License. */ -tb-widget.tb-widget { - position: relative; - height: 100%; +.tb-widget-container { + position: absolute; + inset: 0; +} + +.tb-widget { + position: absolute; + inset: 0; margin: 0; overflow: hidden; outline: none; @@ -25,15 +30,27 @@ tb-widget.tb-widget { } div.tb-widget { - position: relative; - height: 100%; - margin: 0; - overflow: hidden; - outline: none; - - transition: all .2s ease-in-out; + display: flex; + flex-direction: column; + .tb-widget-header { + display: flex; + flex-direction: row; + place-content: flex-start space-between; + align-items: flex-start; + &-absolute { + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 1; + } + } .tb-widget-title { + display: flex; + flex-direction: column; + place-content: flex-start center; + align-items: flex-start; max-height: 65px; padding-top: 5px; padding-left: 5px; @@ -63,6 +80,10 @@ div.tb-widget { } .tb-widget-actions { + display: flex; + flex-direction: row; + place-content: center flex-start; + align-items: center; z-index: 19; margin: 5px 0 0; @@ -104,13 +125,11 @@ div.tb-widget { } .tb-widget-content { + flex: 1; + position: relative; &.tb-no-interaction { pointer-events: none; } - tb-widget { - position: relative; - width: 100%; - } } &.tb-highlighted { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 7e9b9cb6e7..c276999d83 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -409,6 +409,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI elem.classList.add(this.widgetContext.widgetNamespace); this.widgetType = this.widgetInfo.widgetTypeFunction; this.typeParameters = this.widgetInfo.typeParameters; + this.widgetContext.absoluteHeader = this.typeParameters.absoluteHeader; if (!this.widgetType) { this.widgetTypeInstance = {}; diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index b16e880e02..18c8ccd19e 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -265,6 +265,8 @@ export class WidgetContext { hiddenData?: Array<{data: DataSet}>; timeWindow?: WidgetTimewindow; + absoluteHeader?: boolean; + hideTitlePanel = false; widgetTitle?: string; diff --git a/ui-ngx/src/app/shared/components/unit-input.component.html b/ui-ngx/src/app/shared/components/unit-input.component.html index d001a43ef2..0ae14b8ba9 100644 --- a/ui-ngx/src/app/shared/components/unit-input.component.html +++ b/ui-ngx/src/app/shared/components/unit-input.component.html @@ -15,7 +15,7 @@ limitations under the License. --> - + > { if (this.fetchUnits$ === null) { - this.fetchUnits$ = this.resourcesService.loadJsonResource>(unitsModels).pipe( + this.fetchUnits$ = getUnits(this.resourcesService).pipe( map(units => units.map(u => ({ symbol: u.symbol, name: this.translate.instant(u.name), diff --git a/ui-ngx/src/app/shared/models/unit.models.ts b/ui-ngx/src/app/shared/models/unit.models.ts index 797e8a0c4a..7d9f88a068 100644 --- a/ui-ngx/src/app/shared/models/unit.models.ts +++ b/ui-ngx/src/app/shared/models/unit.models.ts @@ -14,6 +14,9 @@ /// limitations under the License. /// +import { ResourcesService } from '@core/services/resources.service'; +import { Observable } from 'rxjs'; + export interface Unit { name: string; symbol: string; @@ -30,3 +33,6 @@ export const searchUnits = (_units: Array, searchText: string): Array> => + resourcesService.loadJsonResource('/assets/metadata/units.json'); diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 716a4cf8b4..e0d9918540 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -19,7 +19,6 @@ import { TenantId } from '@shared/models/id/tenant-id'; import { WidgetTypeId } from '@shared/models/id/widget-type-id'; import { AggregationType, ComparisonDuration, Timewindow } from '@shared/models/time/time.models'; import { EntityType } from '@shared/models/entity-type.models'; -import { AlarmSearchStatus, AlarmSeverity } from '@shared/models/alarm.models'; import { DataKeyType } from './telemetry/telemetry.models'; import { EntityId } from '@shared/models/id/entity-id'; import * as moment_ from 'moment'; @@ -40,6 +39,7 @@ import { Observable } from 'rxjs'; import { Dashboard } from '@shared/models/dashboard.models'; import { IAliasController } from '@core/api/widget-api.models'; import { isEmptyStr } from '@core/utils'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; export enum widgetType { timeseries = 'timeseries', @@ -182,6 +182,7 @@ export interface WidgetTypeParameters { processNoDataByWidget?: boolean; previewWidth?: string; previewHeight?: string; + absoluteHeader?: boolean; } export interface WidgetControllerDescriptor { @@ -706,6 +707,7 @@ export interface IWidgetSettingsComponent { aliasController: IAliasController; dashboard: Dashboard; widget: Widget; + widgetConfig: WidgetConfigComponentData; functionScopeVariables: string[]; settings: WidgetSettings; settingsChanged: Observable; @@ -737,6 +739,17 @@ export abstract class WidgetSettingsComponent extends PageComponent implements widget: Widget; + widgetConfigValue: WidgetConfigComponentData; + + set widgetConfig(value: WidgetConfigComponentData) { + this.widgetConfigValue = value; + this.onWidgetConfigSet(value); + } + + get widgetConfig(): WidgetConfigComponentData { + return this.widgetConfigValue; + } + functionScopeVariables: string[]; settingsValue: WidgetSettings; @@ -848,4 +861,7 @@ export abstract class WidgetSettingsComponent extends PageComponent implements return {}; } + protected onWidgetConfigSet(widgetConfig: WidgetConfigComponentData) { + } + } 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 0f96a5f1dc..536c2dcc4d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4690,6 +4690,7 @@ "advanced-widget-style": "Advanced widget style", "card-buttons": "Card buttons", "show-card-buttons": "Show card buttons", + "card-border-radius": "Card border radius", "card-appearance": "Card appearance", "color": "Color" }, @@ -4702,6 +4703,18 @@ "invalid-widget-type-file-error": "Unable to import widget type: Invalid widget type data structure." }, "widgets": { + "background": { + "background": "Background", + "background-settings": "Background settings", + "background-type-image": "Upload image", + "background-type-image-url": "Image URL", + "background-type-color": "Solid color", + "image-url": "Image URL", + "overlay": "Overlay", + "enable-overlay": "Enable overlay", + "blur": "Blur", + "preview": "Preview" + }, "chart": { "common-settings": "Common settings", "enable-stacking-mode": "Enable stacking mode", @@ -5665,7 +5678,8 @@ "label": "Label", "icon": "Icon", "value": "Value", - "date": "Date" + "date": "Date", + "value-card-style": "Value card style" }, "table": { "common-table-settings": "Common Table Settings", diff --git a/ui-ngx/src/assets/model/units.json b/ui-ngx/src/assets/metadata/units.json similarity index 100% rename from ui-ngx/src/assets/model/units.json rename to ui-ngx/src/assets/metadata/units.json diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index d8bbdf743d..75fc0845cf 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -306,10 +306,7 @@ pre.tb-highlight { .tb-fullscreen { position: fixed !important; - top: 0; - left: 0; - width: 100% !important; - height: 100% !important; + inset: 0 !important; } .tb-fullscreen-parent { @@ -983,10 +980,7 @@ mat-label { min-width: 100%; max-width: none !important; position: absolute !important; - top: 0; - bottom: 0; - left: 0; - right: 0; + inset: 0; .mat-mdc-dialog-container { > *:first-child, form { min-width: 100% !important; @@ -1004,10 +998,7 @@ mat-label { min-width: 100%; max-width: none !important; position: absolute !important; - top: 0; - bottom: 0; - left: 0; - right: 0; + inset: 0; .mat-mdc-dialog-container { > *:first-child, form { min-width: 100% !important; @@ -1022,10 +1013,7 @@ mat-label { .tb-absolute-fill { position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; + inset: 0; } .tb-layout-fill { @@ -1037,10 +1025,7 @@ mat-label { .tb-progress-cover { position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; + inset: 0; z-index: 6; background-color: #eee; opacity: 1; From dc3f3ceafbfbf9cc06d402c1a8e0bc5c16b77094 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 27 Jul 2023 17:23:53 +0300 Subject: [PATCH 327/421] UI: Add color picker input for multiple input widget --- .../widget/lib/multiple-input-widget.component.html | 11 +++++++++++ .../widget/lib/multiple-input-widget.component.ts | 2 +- ...te-multiple-attributes-key-settings.component.html | 3 +++ ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 0a757fd34f..c0886046c0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -172,6 +172,17 @@
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index 534be7c676..05a972e296 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -54,7 +54,7 @@ type FieldAlignment = 'row' | 'column'; type MultipleInputWidgetDataKeyType = 'server' | 'shared' | 'timeseries'; export type MultipleInputWidgetDataKeyValueType = 'string' | 'double' | 'integer' | 'JSON' | 'booleanCheckbox' | 'booleanSwitch' | - 'dateTime' | 'date' | 'time' | 'select'; + 'dateTime' | 'date' | 'time' | 'select' | 'colorPicker'; type MultipleInputWidgetDataKeyEditableType = 'editable' | 'disabled' | 'readonly'; type ConvertGetValueFunction = (value: any, ctx: WidgetContext) => any; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html index 3c62810000..22eb191ec3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html @@ -69,6 +69,9 @@ {{ 'widgets.input-widgets.datakey-value-type-json' | translate }} + + {{ 'widgets.input-widgets.datakey-value-type-color-picker' | translate }} + 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 c5ec1fca40..fbfb96cac0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4792,6 +4792,7 @@ "datakey-value-type-date": "Date", "datakey-value-type-time": "Time", "datakey-value-type-select": "Select", + "datakey-value-type-color-picker": "Color Picker", "value-is-required": "Value is required", "ability-to-edit-attribute": "Ability to edit attribute", "ability-to-edit-attribute-editable": "Editable (default)", From 80fbc89e20b8a78b79cc150d9df436c89855423e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 27 Jul 2023 17:39:04 +0300 Subject: [PATCH 328/421] UI: use .mat-icon class selector instead of mat-icon tag for tb-icon component compatibility. --- .../components/attribute/attribute-table.component.scss | 2 +- .../home/components/widget/config/data-keys.component.scss | 2 +- .../widget/lib/edges-overview-widget.component.scss | 4 ++-- .../widget/lib/entities-hierarchy-widget.component.scss | 4 ++-- .../widget/lib/navigation-card-widget.component.scss | 2 +- .../widget/lib/trip-animation/trip-animation.component.scss | 2 +- ui-ngx/src/app/modules/home/menu/side-menu.component.scss | 2 +- .../home/pages/rulechain/rulechain-page.component.scss | 4 ++-- .../modules/home/pages/rulechain/rulenode.component.scss | 2 +- .../modules/home/pages/widget/widget-editor.component.scss | 2 +- ui-ngx/src/app/shared/components/fab-toolbar.component.scss | 6 +++--- .../time/history-selector/history-selector.component.scss | 4 ++-- ui-ngx/src/app/shared/components/user-menu.component.scss | 2 +- ui-ngx/src/theme.scss | 2 +- 14 files changed, 20 insertions(+), 20 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.scss b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.scss index 831762d1e4..b33dfdbb20 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.scss +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.scss @@ -104,7 +104,7 @@ } mat-cell.tb-value-cell { cursor: pointer; - mat-icon { + .mat-icon { height: 24px; width: 24px; font-size: 24px; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss index 415c69ec53..1664dafb7f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss @@ -49,7 +49,7 @@ padding: 3px; height: 24px; cursor: move; - mat-icon { + .mat-icon { pointer-events: none; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.scss index f5844d8aac..9b2d35e030 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/edges-overview-widget.component.scss @@ -71,7 +71,7 @@ background-size: 18px 18px; } - mat-icon.node-icon { + .mat-icon.node-icon { width: 22px; min-width: 22px; height: 22px; @@ -109,7 +109,7 @@ background-size: 24px 24px; } - mat-icon.node-icon { + .mat-icon.node-icon { width: 40px; min-width: 40px; height: 40px; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.scss index 6731690b0b..426d81b723 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.scss @@ -64,7 +64,7 @@ background-size: 18px 18px; } - mat-icon.node-icon { + .mat-icon.node-icon { width: 22px; min-width: 22px; height: 22px; @@ -102,7 +102,7 @@ background-size: 24px 24px; } - mat-icon.node-icon { + .mat-icon.node-icon { width: 40px; min-width: 40px; height: 40px; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss index a04f82dce7..b9c3e034a7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/navigation-card-widget.component.scss @@ -31,7 +31,7 @@ display: flex; flex-direction: column; align-items: center; - mat-icon { + .mat-icon { margin: auto !important; } span.mdc-button__label { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/trip-animation/trip-animation.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/trip-animation/trip-animation.component.scss index d379c9ff8a..4118a26800 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/trip-animation/trip-animation.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/trip-animation/trip-animation.component.scss @@ -54,7 +54,7 @@ line-height: 24px; z-index: 999; - mat-icon { + .mat-icon { width: 24px; height: 24px; diff --git a/ui-ngx/src/app/modules/home/menu/side-menu.component.scss b/ui-ngx/src/app/modules/home/menu/side-menu.component.scss index fc9df865a1..dbba5e78a9 100644 --- a/ui-ngx/src/app/modules/home/menu/side-menu.component.scss +++ b/ui-ngx/src/app/modules/home/menu/side-menu.component.scss @@ -49,7 +49,7 @@ &.tb-active { background-color: rgba(255, 255, 255, .15); } - mat-icon { + .mat-icon { margin-right: 8px; margin-left: 0; min-width: 1.125rem; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss index b109b4753d..db8d6322f3 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.scss @@ -117,7 +117,7 @@ min-height: 32px; padding: 6px; line-height: 20px; - mat-icon { + .mat-icon { width: 20px; min-width: 20px; height: 20px; @@ -216,7 +216,7 @@ cursor: pointer; box-sizing: border-box; - mat-icon{ + .mat-icon{ width: 16px; min-width: 16px; height: 16px; diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.scss b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.scss index 38ef76feaa..0811288423 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.scss +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulenode.component.scss @@ -86,7 +86,7 @@ background-color: #a3eaa9; } - mat-icon, img { + .mat-icon, img { margin: auto; width: 20px; min-width: 20px; diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss index b8359b38db..f928dde955 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss @@ -185,7 +185,7 @@ mat-toolbar.tb-edit-toolbar { white-space: nowrap; height: 28px; - mat-icon { + .mat-icon { height: 20px; width: 20px; font-size: 20px; diff --git a/ui-ngx/src/app/shared/components/fab-toolbar.component.scss b/ui-ngx/src/app/shared/components/fab-toolbar.component.scss index e8e0c0b9f2..42f2e0c9eb 100644 --- a/ui-ngx/src/app/shared/components/fab-toolbar.component.scss +++ b/ui-ngx/src/app/shared/components/fab-toolbar.component.scss @@ -74,7 +74,7 @@ mat-fab-toolbar { button.mat-mdc-fab { overflow: visible !important; opacity: .5; - mat-icon { + .mat-icon { position: relative; z-index: $z-index-fab + 2; opacity: 1; @@ -146,7 +146,7 @@ mat-fab-toolbar { box-shadow: none; opacity: 1; - mat-icon { + .mat-icon { opacity: 0; } } @@ -163,7 +163,7 @@ mat-fab-toolbar { mat-fab-trigger { button.mat-mdc-fab { transition: opacity .3s cubic-bezier(.55, 0, .55, .2) .2s; - mat-icon { + .mat-icon { transition: all $icon-delay ease-in; } } diff --git a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.scss b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.scss index 6f38e6a6a5..f6f24e2608 100644 --- a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.scss +++ b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.scss @@ -51,7 +51,7 @@ margin: 2px; line-height: 24px; - mat-icon { + .mat-icon { width: 24px; height: 24px; @@ -93,7 +93,7 @@ margin: 0; line-height: 28px; - mat-icon { + .mat-icon { width: 24px; height: 24px; font-size: 24px; diff --git a/ui-ngx/src/app/shared/components/user-menu.component.scss b/ui-ngx/src/app/shared/components/user-menu.component.scss index b0d3acbf51..c435fe2867 100644 --- a/ui-ngx/src/app/shared/components/user-menu.component.scss +++ b/ui-ngx/src/app/shared/components/user-menu.component.scss @@ -36,7 +36,7 @@ } - mat-icon.tb-mini-avatar { + .mat-icon.tb-mini-avatar { width: 36px; height: 36px; margin: auto 8px; diff --git a/ui-ngx/src/theme.scss b/ui-ngx/src/theme.scss index 9aa3e61d39..df1b2bca3e 100644 --- a/ui-ngx/src/theme.scss +++ b/ui-ngx/src/theme.scss @@ -212,7 +212,7 @@ $tb-dark-theme: map_merge($tb-dark-theme, $color); &.mat-primary { @include _mat-toolbar-inverse-color($primary); button.mat-mdc-icon-button { - mat-icon { + .mat-icon { color: mat.get-color-from-palette($primary); } } From 0f5841e9cb3cbf70c8946f17b5abd87b87144edd Mon Sep 17 00:00:00 2001 From: rusikv Date: Thu, 27 Jul 2023 18:07:50 +0300 Subject: [PATCH 329/421] Added dialog for creation latest telemetry key value --- .../add-attribute-dialog.component.html | 2 +- .../add-attribute-dialog.component.ts | 27 ++++++++++++------- .../attribute/attribute-table.component.html | 2 +- .../attribute/attribute-table.component.ts | 2 +- .../assets/locale/locale.constant-en_US.json | 3 ++- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html index c48299986e..17e31854cc 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html @@ -17,7 +17,7 @@ --> -

{{ 'attribute.add' | translate }}

+

{{ title | translate }}

-
- - -
+ +
From a659d1b7e6c8614923e4d9b1e42df524165dabab Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 28 Jul 2023 11:02:27 +0300 Subject: [PATCH 340/421] UI: Change value type for color --- .../widget/lib/multiple-input-widget.component.html | 2 +- .../components/widget/lib/multiple-input-widget.component.ts | 2 +- .../update-multiple-attributes-key-settings.component.html | 4 ++-- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 9d5bf1420c..fa51899c4a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -173,7 +173,7 @@
any; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html index 22eb191ec3..d69a4b0713 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-multiple-attributes-key-settings.component.html @@ -69,8 +69,8 @@ {{ 'widgets.input-widgets.datakey-value-type-json' | translate }} - - {{ 'widgets.input-widgets.datakey-value-type-color-picker' | translate }} + + {{ 'widgets.input-widgets.datakey-value-type-color' | translate }} 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 fbfb96cac0..af441665bd 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4792,7 +4792,7 @@ "datakey-value-type-date": "Date", "datakey-value-type-time": "Time", "datakey-value-type-select": "Select", - "datakey-value-type-color-picker": "Color Picker", + "datakey-value-type-color": "Color", "value-is-required": "Value is required", "ability-to-edit-attribute": "Ability to edit attribute", "ability-to-edit-attribute-editable": "Editable (default)", From 3f18c2e43636633766bdc0fdb4dce787a06e66bd Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 28 Jul 2023 11:57:32 +0300 Subject: [PATCH 341/421] UI: update label --- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e0c07480cf..9ce52d14ab 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -938,7 +938,7 @@ "selected-customers": "{ count, plural, =1 {1 customer} other {# customers} } selected", "edges": "Customer edge instances", "manage-edges": "Manage edges", - "assign-customer": "Assign customer" + "assign-customer": "Assign to customer" }, "datetime": { "date-from": "Date from", From aec44cf72c335cff6eb2adbacca93b38915174a0 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 28 Jul 2023 12:06:30 +0300 Subject: [PATCH 342/421] UI: Refactoring --- .../home/components/wizard/device-wizard-dialog.component.html | 2 +- ui-ngx/src/assets/locale/locale.constant-en_US.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index 08d71e1229..fd427923f7 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -76,7 +76,7 @@
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 9ce52d14ab..42fb38ed54 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -937,8 +937,7 @@ "search": "Search customers", "selected-customers": "{ count, plural, =1 {1 customer} other {# customers} } selected", "edges": "Customer edge instances", - "manage-edges": "Manage edges", - "assign-customer": "Assign to customer" + "manage-edges": "Manage edges" }, "datetime": { "date-from": "Date from", From d9c39c362eba7c579061b1a7a75248d2effaf3e4 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 28 Jul 2023 14:20:33 +0200 Subject: [PATCH 343/421] refactored due to comments --- .../src/main/resources/thingsboard.yml | 2 +- .../queue/discovery/ZkDiscoveryService.java | 26 +++++--- .../discovery/ZkDiscoveryServiceTest.java | 62 ++++++++++++------- .../src/main/resources/tb-vc-executor.yml | 2 +- .../src/main/resources/tb-coap-transport.yml | 2 +- .../src/main/resources/tb-http-transport.yml | 2 +- .../src/main/resources/tb-lwm2m-transport.yml | 2 +- .../src/main/resources/tb-mqtt-transport.yml | 2 +- .../src/main/resources/tb-snmp-transport.yml | 2 +- 9 files changed, 62 insertions(+), 40 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 9cec475335..b6fd99dcec 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -96,7 +96,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cluster: stats: diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index 50378d3387..44999d016a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.queue.discovery; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolStringList; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.curator.framework.CuratorFramework; @@ -68,7 +69,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi private Integer zkSessionTimeout; @Value("${zk.zk_dir}") private String zkDir; - @Value("${zk.recalculate_delay:120000}") + @Value("${zk.recalculate_delay:60000}") private Long recalculateDelay; protected final ConcurrentHashMap> delayedTasks; @@ -294,35 +295,39 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi log.error("Failed to decode server instance for node {}", data.getPath(), e); throw e; } - log.debug("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), instance.getServiceId()); + + String serviceId = instance.getServiceId(); + ProtocolStringList serviceTypesList = instance.getServiceTypesList(); + + log.trace("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), serviceId); switch (pathChildrenCacheEvent.getType()) { case CHILD_ADDED: - ScheduledFuture task = delayedTasks.remove(instance.getServiceId()); + ScheduledFuture task = delayedTasks.remove(serviceId); if (task != null) { if (task.cancel(false)) { log.debug("[{}] Recalculate partitions ignored. Service was restarted in time [{}].", - instance.getServiceId(), instance.getServiceTypesList()); + serviceId, serviceTypesList); } else { log.debug("[{}] Going to recalculate partitions. Service was not restarted in time [{}]!", - instance.getServiceId(), instance.getServiceTypesList()); + serviceId, serviceTypesList); recalculatePartitions(); } } else { - log.debug("[{}] Going to recalculate partitions due to adding new node [{}].", - instance.getServiceId(), instance.getServiceTypesList()); + log.trace("[{}] Going to recalculate partitions due to adding new node [{}].", + serviceId, serviceTypesList); recalculatePartitions(); } break; case CHILD_REMOVED: ScheduledFuture future = zkExecutorService.schedule(() -> { log.debug("[{}] Going to recalculate partitions due to removed node [{}]", - instance.getServiceId(), instance.getServiceTypesList()); - ScheduledFuture removedTask = delayedTasks.remove(instance.getServiceId()); + serviceId, serviceTypesList); + ScheduledFuture removedTask = delayedTasks.remove(serviceId); if (removedTask != null) { recalculatePartitions(); } }, recalculateDelay, TimeUnit.MILLISECONDS); - delayedTasks.put(instance.getServiceId(), future); + delayedTasks.put(serviceId, future); break; default: break; @@ -334,6 +339,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi * Synchronized to ensure that other servers info is up to date * */ synchronized void recalculatePartitions() { + delayedTasks.values().forEach(future -> future.cancel(false)); delayedTasks.clear(); partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), getOtherServers()); } diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java index 38cad217aa..a8810efd0e 100644 --- a/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java +++ b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java @@ -63,68 +63,76 @@ public class ZkDiscoveryServiceTest { @Mock private PathChildrenCache cache; - private ScheduledExecutorService zkExecutorService; - @Mock private CuratorFramework curatorFramework; private ZkDiscoveryService zkDiscoveryService; + private static final long RECALCULATE_DELAY = 100L; + + final TransportProtos.ServiceInfo currentInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-rule-engine-0").build(); + final ChildData currentData = new ChildData("/thingsboard/nodes/0000000010", null, currentInfo.toByteArray()); + final TransportProtos.ServiceInfo childInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-rule-engine-1").build(); + final ChildData childData = new ChildData("/thingsboard/nodes/0000000020", null, childInfo.toByteArray()); + @Before public void setup() { zkDiscoveryService = Mockito.spy(new ZkDiscoveryService(serviceInfoProvider, partitionService)); - zkExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("zk-discovery")); + ScheduledExecutorService zkExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("zk-discovery")); when(client.getState()).thenReturn(CuratorFrameworkState.STARTED); ReflectionTestUtils.setField(zkDiscoveryService, "stopped", false); ReflectionTestUtils.setField(zkDiscoveryService, "client", client); ReflectionTestUtils.setField(zkDiscoveryService, "cache", cache); ReflectionTestUtils.setField(zkDiscoveryService, "nodePath", "/thingsboard/nodes/0000000010"); ReflectionTestUtils.setField(zkDiscoveryService, "zkExecutorService", zkExecutorService); - ReflectionTestUtils.setField(zkDiscoveryService, "recalculateDelay", 1000L); + ReflectionTestUtils.setField(zkDiscoveryService, "recalculateDelay", RECALCULATE_DELAY); ReflectionTestUtils.setField(zkDiscoveryService, "zkDir", "/thingsboard"); - } - - @Test - public void restartNodeTest() throws Exception { - var currentInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("currentId").build(); - var currentData = new ChildData("/thingsboard/nodes/0000000010", null, currentInfo.toByteArray()); - var childInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("childId").build(); - var childData = new ChildData("/thingsboard/nodes/0000000020", null, childInfo.toByteArray()); when(serviceInfoProvider.getServiceInfo()).thenReturn(currentInfo); + List dataList = new ArrayList<>(); dataList.add(currentData); when(cache.getCurrentData()).thenReturn(dataList); + } + @Test + public void restartNodeInTimeTest() throws Exception { startNode(childData); verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); reset(partitionService); - //Restart in timeAssert.assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); stopNode(childData); assertEquals(1, zkDiscoveryService.delayedTasks.size()); - verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + verify(partitionService, never()).recalculatePartitions(any(), any()); startNode(childData); - verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + verify(partitionService, never()).recalculatePartitions(any(), any()); - Thread.sleep(2000); + Thread.sleep(RECALCULATE_DELAY * 2); - verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + verify(partitionService, never()).recalculatePartitions(any(), any()); assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + } + + @Test + public void restartNodeNotInTimeTest() throws Exception { + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); - //Restart not in time stopNode(childData); assertEquals(1, zkDiscoveryService.delayedTasks.size()); - Thread.sleep(2000); + Thread.sleep(RECALCULATE_DELAY * 2); assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); @@ -135,11 +143,19 @@ public class ZkDiscoveryServiceTest { verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); reset(partitionService); + } - //Start another node during restart - var anotherInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("anotherId").build(); + @Test + public void startAnotherNodeDuringRestartTest() throws Exception { + var anotherInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-transport").build(); var anotherData = new ChildData("/thingsboard/nodes/0000000030", null, anotherInfo.toByteArray()); + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + stopNode(childData); assertEquals(1, zkDiscoveryService.delayedTasks.size()); @@ -151,9 +167,9 @@ public class ZkDiscoveryServiceTest { verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo))); reset(partitionService); - Thread.sleep(2000); + Thread.sleep(RECALCULATE_DELAY * 2); - verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + verify(partitionService, never()).recalculatePartitions(any(), any()); startNode(childData); diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 2c90082eb5..1c567588df 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" queue: type: "${TB_QUEUE_TYPE:kafka}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index aef46a1234..1f8861ced9 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 4bce6e28d7..7c5103cfac 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -68,7 +68,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index eab5b107c8..4ab59aec01 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index f0968aa6b9..a103edf1f4 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index c7dcd70574..44a86dc6dd 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" From b71ae531bb79db83231d051bab8e32e8a53cdea9 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 28 Jul 2023 15:51:21 +0300 Subject: [PATCH 344/421] UI: Clear code and rename state action --- ui-ngx/src/app/core/auth/auth.actions.ts | 8 ++++---- ui-ngx/src/app/core/auth/auth.effects.ts | 4 ++-- ui-ngx/src/app/core/auth/auth.reducer.ts | 2 +- ui-ngx/src/app/core/utils.ts | 4 +++- .../device/device-check-connectivity-dialog.component.ts | 4 ++-- ui-ngx/src/app/shared/components/markdown.component.scss | 2 +- ui-ngx/src/form.scss | 7 ------- 7 files changed, 13 insertions(+), 18 deletions(-) diff --git a/ui-ngx/src/app/core/auth/auth.actions.ts b/ui-ngx/src/app/core/auth/auth.actions.ts index 2e8c82ae2d..9e5640a97d 100644 --- a/ui-ngx/src/app/core/auth/auth.actions.ts +++ b/ui-ngx/src/app/core/auth/auth.actions.ts @@ -27,7 +27,7 @@ export enum AuthActionTypes { UPDATE_LAST_PUBLIC_DASHBOARD_ID = '[Auth] Update Last Public Dashboard Id', UPDATE_HAS_REPOSITORY = '[Auth] Change Has Repository', UPDATE_OPENED_MENU_SECTION = '[Preferences] Update Opened Menu Section', - UPDATE_USER_SETTINGS = '[Preferences] Update user settings', + PUT_USER_SETTINGS = '[Preferences] Put user settings', DELETE_USER_SETTINGS = '[Preferences] Delete user settings', } @@ -71,8 +71,8 @@ export class ActionPreferencesUpdateOpenedMenuSection implements Action { constructor(readonly payload: { path: string; opened: boolean }) {} } -export class ActionPreferencesUpdateUserSettings implements Action { - readonly type = AuthActionTypes.UPDATE_USER_SETTINGS; +export class ActionPreferencesPutUserSettings implements Action { + readonly type = AuthActionTypes.PUT_USER_SETTINGS; constructor(readonly payload: Partial) {} } @@ -85,4 +85,4 @@ export class ActionPreferencesDeleteUserSettings implements Action { export type AuthActions = ActionAuthAuthenticated | ActionAuthUnauthenticated | ActionAuthLoadUser | ActionAuthUpdateUserDetails | ActionAuthUpdateLastPublicDashboardId | ActionAuthUpdateHasRepository | - ActionPreferencesUpdateOpenedMenuSection | ActionPreferencesUpdateUserSettings | ActionPreferencesDeleteUserSettings; + ActionPreferencesUpdateOpenedMenuSection | ActionPreferencesPutUserSettings | ActionPreferencesDeleteUserSettings; diff --git a/ui-ngx/src/app/core/auth/auth.effects.ts b/ui-ngx/src/app/core/auth/auth.effects.ts index 76b9dce9fa..3e5eb28d72 100644 --- a/ui-ngx/src/app/core/auth/auth.effects.ts +++ b/ui-ngx/src/app/core/auth/auth.effects.ts @@ -40,9 +40,9 @@ export class AuthEffects { mergeMap(([action, state]) => this.userSettingsService.putUserSettings({ openedMenuSections: state.userSettings.openedMenuSections })) ), {dispatch: false}); - updatedUserSettings = createEffect(() => this.actions$.pipe( + putUserSettings = createEffect(() => this.actions$.pipe( ofType( - AuthActionTypes.UPDATE_USER_SETTINGS, + AuthActionTypes.PUT_USER_SETTINGS, ), mergeMap((state) => this.userSettingsService.putUserSettings(state.payload)) ), {dispatch: false}); diff --git a/ui-ngx/src/app/core/auth/auth.reducer.ts b/ui-ngx/src/app/core/auth/auth.reducer.ts index 6fd80d7052..4bcf71104b 100644 --- a/ui-ngx/src/app/core/auth/auth.reducer.ts +++ b/ui-ngx/src/app/core/auth/auth.reducer.ts @@ -76,7 +76,7 @@ export const authReducer = ( userSettings = {...state.userSettings, ...{ openedMenuSections: Array.from(openedMenuSections)}}; return { ...state, ...{ userSettings }}; - case AuthActionTypes.UPDATE_USER_SETTINGS: + case AuthActionTypes.PUT_USER_SETTINGS: userSettings = {...state.userSettings, ...action.payload}; return { ...state, ...{ userSettings }}; diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index c823c2bfea..9a369cb5aa 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -355,7 +355,9 @@ const SNAKE_CASE_REGEXP = /[A-Z]/g; export function snakeCase(name: string, separator: string): string { separator = separator || '_'; - return name.replace(SNAKE_CASE_REGEXP, (letter, pos) => (pos ? separator : '') + letter.toLowerCase()); + return name.replace(SNAKE_CASE_REGEXP, (letter, pos) => { + return (pos ? separator : '') + letter.toLowerCase(); + }); } export function getDescendantProp(obj: any, path: string): any { diff --git a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts index 2135a3aeea..7516e0f3e1 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device-check-connectivity-dialog.component.ts @@ -40,7 +40,7 @@ import { NetworkTransportType, PublishTelemetryCommand } from '@shared/models/device.models'; -import { ActionPreferencesUpdateUserSettings } from '@core/auth/auth.actions'; +import { ActionPreferencesPutUserSettings } from '@core/auth/auth.actions'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { getOS } from '@core/utils'; @@ -121,7 +121,7 @@ export class DeviceCheckConnectivityDialogComponent extends close(): void { if (this.notShowAgain && this.showDontShowAgain) { - this.store.dispatch(new ActionPreferencesUpdateUserSettings({ notDisplayConnectivityAfterAddDevice: true })); + this.store.dispatch(new ActionPreferencesPutUserSettings({ notDisplayConnectivityAfterAddDevice: true })); this.dialogRef.close(null); } else { this.dialogRef.close(null); diff --git a/ui-ngx/src/app/shared/components/markdown.component.scss b/ui-ngx/src/app/shared/components/markdown.component.scss index e23111fc6b..757a26c587 100644 --- a/ui-ngx/src/app/shared/components/markdown.component.scss +++ b/ui-ngx/src/app/shared/components/markdown.component.scss @@ -88,7 +88,7 @@ } } - a:not(.ignore-style-a) { + a { font-weight: 500; color: #2a7dec; text-decoration: none; diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index bb82e937bf..00e9492af0 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -152,13 +152,6 @@ &.space-between { justify-content: space-between; } - &.no-border { - border: none; - border-radius: 0; - } - &.no-padding { - padding: 0; - } .mat-divider-vertical { height: 56px; margin-top: -7px; From 907c8f3e1c644c8a359e9ec704ce9b8fafc3597d Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 28 Jul 2023 16:58:12 +0300 Subject: [PATCH 345/421] UI: Optimize gets tabs in routerTabs components --- .../home/components/router-tabs.component.ts | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/router-tabs.component.ts b/ui-ngx/src/app/modules/home/components/router-tabs.component.ts index c5ffb11908..5735499262 100644 --- a/ui-ngx/src/app/modules/home/components/router-tabs.component.ts +++ b/ui-ngx/src/app/modules/home/components/router-tabs.component.ts @@ -20,8 +20,8 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { MenuService } from '@core/services/menu.service'; -import { distinctUntilChanged, filter, map, mergeMap, take } from 'rxjs/operators'; -import { merge } from 'rxjs'; +import { distinctUntilChanged, filter, map, mergeMap, startWith, take } from 'rxjs/operators'; +import { merge, Observable } from 'rxjs'; import { MenuSection } from '@core/services/menu.models'; import { ActiveComponentService } from '@core/services/active-component.service'; import { TbAnchorComponent } from '@shared/components/tb-anchor.component'; @@ -39,14 +39,7 @@ export class RouterTabsComponent extends PageComponent implements OnInit { hideCurrentTabs = false; - tabs$ = merge(this.menuService.menuSections(), - this.router.events.pipe( - filter((event) => event instanceof NavigationEnd ), - distinctUntilChanged()) - ).pipe( - mergeMap(() => this.menuService.menuSections().pipe(take(1))), - map((sections) => this.buildTabs(this.activatedRoute, sections)) - ); + tabs$: Observable>; constructor(protected store: Store, private activatedRoute: ActivatedRoute, @@ -57,6 +50,23 @@ export class RouterTabsComponent extends PageComponent implements OnInit { } ngOnInit() { + if (this.activatedRoute.snapshot.data.useChildrenRoutesForTabs) { + this.tabs$ = this.router.events.pipe( + filter((event) => event instanceof NavigationEnd), + startWith(''), + map(() => this.buildTabsForRoutes(this.activatedRoute)) + ); + } else { + this.tabs$ = merge(this.menuService.menuSections(), + this.router.events.pipe( + filter((event) => event instanceof NavigationEnd ), + distinctUntilChanged()) + ).pipe( + mergeMap(() => this.menuService.menuSections().pipe(take(1))), + map((sections) => this.buildTabs(this.activatedRoute, sections)) + ); + } + this.activatedRoute.data.subscribe( (data) => this.buildTabsHeaderComponent(data) ); @@ -80,16 +90,26 @@ export class RouterTabsComponent extends PageComponent implements OnInit { } } - private buildTabs(activatedRoute: ActivatedRoute, sections: MenuSection[]): Array { - const sectionPath = '/' + activatedRoute.pathFromRoot.map(r => r.snapshot.url) + private getSectionPath(activatedRoute: ActivatedRoute): string { + return '/' + activatedRoute.pathFromRoot.map(r => r.snapshot.url) .filter(f => !!f[0]).map(f => f.map(f1 => f1.path).join('/')).join('/'); + } + + private buildTabs(activatedRoute: ActivatedRoute, sections: MenuSection[]): Array { + const sectionPath = this.getSectionPath(activatedRoute); const found = this.findRootSection(sections, sectionPath); if (found) { const rootPath = sectionPath.substring(0, sectionPath.length - found.path.length); const isRoot = rootPath === ''; const tabs: Array = found ? found.pages.filter(page => !page.disabled && (!page.rootOnly || isRoot)) : []; return tabs.map((tab) => ({...tab, path: rootPath + tab.path})); - } else if (activatedRoute.snapshot.data.useChildrenRoutesForTabs && sectionPath.endsWith(activatedRoute.routeConfig.path)) { + } + return []; + } + + private buildTabsForRoutes(activatedRoute: ActivatedRoute): Array { + const sectionPath = this.getSectionPath(activatedRoute); + if (activatedRoute.routeConfig.children.length) { const activeRouterChildren = activatedRoute.routeConfig.children.filter(page => page.path !== ''); return activeRouterChildren.map(tab => ({ id: tab.component.name, @@ -98,9 +118,8 @@ export class RouterTabsComponent extends PageComponent implements OnInit { icon: tab.data?.breadcrumb?.icon ?? '', path: `${sectionPath}/${tab.path}` })); - } else { - return []; } + return []; } private findRootSection(sections: MenuSection[], sectionPath: string): MenuSection { From 5b2918de9589bbdd763dbfe1317a5b3c11d869a4 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 28 Jul 2023 17:27:38 +0200 Subject: [PATCH 346/421] minor improvements --- .../thingsboard/server/controller/BaseController.java | 4 ---- .../server/controller/DeviceConnectivityController.java | 9 +++++---- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 77aa31df20..68a987a0bc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -113,7 +113,6 @@ import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.ClaimDevicesService; -import org.thingsboard.server.dao.device.DeviceConnectivityService; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; @@ -209,9 +208,6 @@ public abstract class BaseController { @Autowired protected DeviceService deviceService; - @Autowired - protected DeviceConnectivityService deviceConnectivityService; - @Autowired protected DeviceProfileService deviceProfileService; diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java index b9b12da17d..04b1b4c522 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java @@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.dao.device.DeviceConnectivityService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.system.SystemSecurityService; @@ -46,7 +47,6 @@ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL; import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL_PARAM_DESCRIPTION; -import static org.thingsboard.server.controller.ControllerConstants.SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.PEM_CERT_FILE_NAME; @@ -57,6 +57,7 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.PEM_CERT_FI @Slf4j public class DeviceConnectivityController extends BaseController { + private final DeviceConnectivityService deviceConnectivityService; private final SystemSecurityService systemSecurityService; @ApiOperation(value = "Get commands to publish device telemetry (getDevicePublishTelemetryCommands)", @@ -86,11 +87,11 @@ public class DeviceConnectivityController extends BaseController { return deviceConnectivityService.findDevicePublishTelemetryCommands(baseUrl, device); } - @ApiOperation(value = "Download mqtt ssl certificate using file path defined in device.connectivity properties (downloadMqttServerCertificate)", notes = "Download Mqtt server certificate." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) + @ApiOperation(value = "Download server certificate using file path defined in device.connectivity properties (downloadServerCertificate)", notes = "Download server certificate.") @RequestMapping(value = "/device-connectivity/{protocol}/certificate/download", method = RequestMethod.GET) @ResponseBody - public ResponseEntity downloadMqttServerCertificate(@ApiParam(value = PROTOCOL_PARAM_DESCRIPTION) - @PathVariable(PROTOCOL) String protocol) throws ThingsboardException, IOException { + public ResponseEntity downloadServerCertificate(@ApiParam(value = PROTOCOL_PARAM_DESCRIPTION) + @PathVariable(PROTOCOL) String protocol) throws ThingsboardException, IOException { checkParameter(PROTOCOL, protocol); var pemCert = checkNotNull(deviceConnectivityService.getPemCertFile(protocol), protocol + " pem cert file is not found!"); 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 18e97ecef1..27c6768980 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1397,7 +1397,7 @@ "device-created-check-connectivity": "Device created. Let's check connectivity!", "loading-check-connectivity-command": "Loading check connectivity commands...", "use-following-instructions": "Use the following instructions for sending telemetry on behalf of the device using shell", - "execute-following-command": "Executive the following command", + "execute-following-command": "Execute the following command", "install-curl-windows": "Starting Windows 10 b17063, cURL is available by default", "install-mqtt-windows": "Use the instructions to download, install, setup and run mosquitto_pub", "install-coap-client": "Use the instructions to download, install, setup and run coap-client", From 49b149d484e99c802715eb81283ab245f2ee25f2 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 28 Jul 2023 18:32:36 +0300 Subject: [PATCH 347/421] UI: Refactoring for new style --- .../lib/multiple-input-widget.component.html | 42 ++++++++++++------- .../lib/multiple-input-widget.component.scss | 26 +++++++++++- .../components/color-input.component.ts | 5 ++- 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index fa51899c4a..9c228ec93f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -28,7 +28,7 @@
- + {{key.label}}
- + {{key.label}}
- + {{key.label}} - + {{key.label}}
- + {{key.label}}
- - + +
+
+ + {{key.settings.icon}} + + icon + + + {{key.label}} +
+
+ + + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss index d0dd324e52..8fec24cf05 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss @@ -21,7 +21,7 @@ flex-direction: column; .tb-multiple-input-container { - padding: 0 8px; + padding: 8px 8px 0; flex: 1 1 100%; overflow-x: hidden; overflow-y: auto; @@ -37,6 +37,30 @@ } } + .color-picker-input { + height: 56px; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 7px 16px 7px 12px; + margin: 0 10px 22px 0; + border: 1px solid rgba(0, 0, 0, 0.4); + border-radius: 6px; + + .mat-icon, img { + margin-right: 5px; + } + + .mat-divider-vertical { + height: 56px; + margin-top: -7px; + margin-bottom: -7px; + border-right-color: rgba(0, 0, 0, 0.4); + } + } + .input-field { padding-right: 10px; diff --git a/ui-ngx/src/app/shared/components/color-input.component.ts b/ui-ngx/src/app/shared/components/color-input.component.ts index fa6c73116e..88a49f756e 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.ts +++ b/ui-ngx/src/app/shared/components/color-input.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -91,6 +91,8 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro @Input() disabled: boolean; + @Output() colorChanged: EventEmitter = new EventEmitter(); + private modelValue: string; private propagateChange = null; @@ -150,6 +152,7 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro if (this.modelValue !== color) { this.modelValue = color; this.propagateChange(this.modelValue); + this.colorChanged.emit(color); } } From 08bd89d0bee76a86b51244ef3548a64b5dd6e423 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 28 Jul 2023 18:44:22 +0300 Subject: [PATCH 348/421] UI: Remove divider --- .../widget/lib/multiple-input-widget.component.html | 1 - .../widget/lib/multiple-input-widget.component.scss | 7 ------- 2 files changed, 8 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 67c28bd878..6c749cab3b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -184,7 +184,6 @@ {{key.label}}
- Date: Mon, 31 Jul 2023 07:56:31 +0300 Subject: [PATCH 349/421] Fix for removing user from sysadmin level alarm unassignment --- .../entitiy/user/DefaultUserService.java | 2 +- .../controller/AlarmControllerTest.java | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java index 0c04e46ff5..d9f11dacb5 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java @@ -82,7 +82,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse UserId userId = tbUser.getId(); try { - tbAlarmService.unassignUserAlarms(tenantId, tbUser, System.currentTimeMillis()); + tbAlarmService.unassignUserAlarms(tbUser.getTenantId(), tbUser, System.currentTimeMillis()); userService.deleteUser(tenantId, userId); notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, userId, tbUser, user, ActionType.DELETED, true, null, customerId.toString()); diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index 50761be096..6ce6e22e9a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -531,6 +531,55 @@ public class AlarmControllerTest extends AbstractControllerTest { tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.ALARM_UNASSIGNED); } + @Test + public void testUnassignTenantUserAlarmOnUserRemoving() throws Exception { + loginDifferentTenant(); + + User user = new User(); + user.setAuthority(Authority.TENANT_ADMIN); + user.setTenantId(tenantId); + user.setEmail("tenantForAssign@thingsboard.org"); + User savedUser = createUser(user, "password"); + + Device device = createDevice("Different tenant device", "default", "differentTenantTest"); + + Alarm alarm = Alarm.builder() + .type(TEST_ALARM_TYPE) + .tenantId(savedDifferentTenant.getId()) + .originator(device.getId()) + .severity(AlarmSeverity.MAJOR) + .build(); + alarm = doPost("/api/alarm", alarm, Alarm.class); + Assert.assertNotNull(alarm); + + alarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(alarm); + + Mockito.reset(tbClusterService, auditLogService); + long beforeAssignmentTs = System.currentTimeMillis(); + + doPost("/api/alarm/" + alarm.getId() + "/assign/" + savedUser.getId().getId()).andExpect(status().isOk()); + AlarmInfo foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertEquals(savedUser.getId(), foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + + beforeAssignmentTs = System.currentTimeMillis(); + + Mockito.reset(tbClusterService, auditLogService); + + loginSysAdmin(); + + doDelete("/api/user/" + savedUser.getId().getId()).andExpect(status().isOk()); + + loginDifferentTenant(); + + foundAlarm = doGet("/api/alarm/info/" + alarm.getId(), AlarmInfo.class); + Assert.assertNotNull(foundAlarm); + Assert.assertNull(foundAlarm.getAssigneeId()); + Assert.assertTrue(foundAlarm.getAssignTs() >= beforeAssignmentTs); + } + @Test public void testUnassignAlarmOnUserRemoving() throws Exception { loginDifferentTenant(); From 037dbd25d07b2a45699d9752b012d3a5f1660625 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Mon, 31 Jul 2023 09:28:08 +0300 Subject: [PATCH 350/421] Enabled test with this message for OUT messages with errors --- .../src/app/modules/home/components/event/event-table-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 026624dbf3..d574a3593a 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -360,7 +360,7 @@ export class EventTableConfig extends EntityTableConfig { this.cellActionDescriptors.push({ name: this.translate.instant('rulenode.test-with-this-message', {test: this.translate.instant(this.testButtonLabel)}), icon: 'bug_report', - isEnabled: (entity) => entity.body.type === 'IN', + isEnabled: (entity) => entity.body.type === 'IN' || entity.body.error !== undefined, onAction: ($event, entity) => { this.debugEventSelected.next(entity.body); } From 054b1901448f2d48abaeb9ad13d786f027dbbfe2 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Mon, 31 Jul 2023 12:25:48 +0300 Subject: [PATCH 351/421] UI: Add routes tab settings replaceUrl --- .../modules/home/components/router-tabs.component.html | 1 + .../modules/home/components/router-tabs.component.ts | 6 ++++++ ui-ngx/src/app/modules/home/home.component.ts | 9 ++++----- .../home/pages/account/account-routing.module.ts | 10 ++++++++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/router-tabs.component.html b/ui-ngx/src/app/modules/home/components/router-tabs.component.html index f16a761c3e..5ad09403c2 100644 --- a/ui-ngx/src/app/modules/home/components/router-tabs.component.html +++ b/ui-ngx/src/app/modules/home/components/router-tabs.component.html @@ -20,6 +20,7 @@
-
-
-
+
+
{{ 'widgets.input-widgets.no-entity-selected' | translate }}
-
+
{{ 'widgets.input-widgets.not-allowed-entity' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss index 7a27c39907..f6edd1fb52 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss @@ -37,17 +37,22 @@ } } - .color-picker-input { - height: 56px; + .tb-multiple-input-layout { display: flex; flex-direction: row; - align-items: center; - justify-content: space-between; - gap: 16px; + align-items: start; + } + + .color-picker-input { padding: 7px 16px 7px 12px; margin: 0 10px 22px 0; - border: 1px solid rgba(0, 0, 0, 0.4); - border-radius: 6px; + border-color: rgba(0, 0, 0, 0.4); + + .label-container { + display: flex; + flex-direction: row; + align-items: center; + } .mat-icon, img { margin-right: 5px; @@ -78,6 +83,30 @@ .vertical-alignment { flex-direction: column; } + + &--buttons-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: end; + &__button { + max-height: 50px; + margin-right:20px; + } + } + + &__errors { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + &__error { + text-align: center; + font-size: 18px; + color: #a0a0a0; + } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index 4c7fb1cfec..6f29a495cf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -390,6 +390,12 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } }); } + } else if (key.settings.dataKeyValueType === 'color') { + formControl.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => { + this.inputChanged(source, key); + }); } this.multipleInputFormGroup.addControl(key.formId, formControl); } diff --git a/ui-ngx/src/app/shared/components/color-input.component.ts b/ui-ngx/src/app/shared/components/color-input.component.ts index 8997409e7c..f22b91fde2 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.ts +++ b/ui-ngx/src/app/shared/components/color-input.component.ts @@ -14,17 +14,7 @@ /// limitations under the License. /// -import { - ChangeDetectorRef, - Component, - EventEmitter, - forwardRef, - Input, - OnInit, - Output, - Renderer2, - ViewContainerRef -} from '@angular/core'; +import { ChangeDetectorRef, Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -110,8 +100,6 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro @Input() disabled: boolean; - @Output() colorChanged: EventEmitter = new EventEmitter(); - private modelValue: string; private propagateChange = null; @@ -174,7 +162,6 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro if (this.modelValue !== color) { this.modelValue = color; this.propagateChange(this.modelValue); - this.colorChanged.emit(color); } } From 1569bee351715f203cb141377050e96d0fd3797c Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 31 Jul 2023 13:34:37 +0300 Subject: [PATCH 355/421] UI: Refactoring error container --- .../widget/lib/multiple-input-widget.component.html | 6 +++--- .../widget/lib/multiple-input-widget.component.scss | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 39b135b77a..ae739332be 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -207,11 +207,11 @@ {{ saveButtonLabel }}
-
-
+
+
{{ 'widgets.input-widgets.no-entity-selected' | translate }}
-
+
{{ 'widgets.input-widgets.not-allowed-entity' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss index f6edd1fb52..3185bc8b17 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.scss @@ -95,17 +95,17 @@ } } - &__errors { + &--errors-container { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; - } - &__error { - text-align: center; - font-size: 18px; - color: #a0a0a0; + &__error { + text-align: center; + font-size: 18px; + color: #a0a0a0; + } } } } From 68149d96739ed1445f3ad3c25c622ea72dc7810b Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 16 Jun 2023 15:40:29 +0200 Subject: [PATCH 356/421] added recalculetePartitions delay for node restart --- .../src/main/resources/thingsboard.yml | 1 + .../queue/discovery/ZkDiscoveryService.java | 31 ++++++++++++++++++- .../src/main/resources/tb-vc-executor.yml | 1 + .../src/main/resources/tb-coap-transport.yml | 1 + .../src/main/resources/tb-http-transport.yml | 1 + .../src/main/resources/tb-lwm2m-transport.yml | 1 + .../src/main/resources/tb-mqtt-transport.yml | 1 + .../src/main/resources/tb-snmp-transport.yml | 1 + 8 files changed, 37 insertions(+), 1 deletion(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 3666678561..19804c0588 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -96,6 +96,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cluster: stats: diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index fcf80bcf3d..17d046a4cb 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -44,8 +44,10 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.List; import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -66,6 +68,10 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi private Integer zkSessionTimeout; @Value("${zk.zk_dir}") private String zkDir; + @Value("${zk.recalculate_delay:120000}") + private Long recalculateDelay; + + private final ConcurrentHashMap> delayedTasks; private final TbServiceInfoProvider serviceInfoProvider; private final PartitionService partitionService; @@ -82,6 +88,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi PartitionService partitionService) { this.serviceInfoProvider = serviceInfoProvider; this.partitionService = partitionService; + delayedTasks = new ConcurrentHashMap<>(); } @PostConstruct @@ -290,8 +297,30 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi log.debug("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), instance.getServiceId()); switch (pathChildrenCacheEvent.getType()) { case CHILD_ADDED: + ScheduledFuture task = delayedTasks.remove(instance.getServiceId()); + if (task != null) { + if (!task.cancel(false)) { + log.debug("[{}] Going to recalculate partitions due to adding new node [{}]", + instance.getServiceId(), instance.getServiceTypesList()); + recalculatePartitions(); + } else { + log.debug("[{}] Recalculate partitions ignored. Service restarted in time [{}]", + instance.getServiceId(), instance.getServiceTypesList()); + } + } else { + log.debug("[{}] Going to recalculate partitions due to adding new node [{}]", + instance.getServiceId(), instance.getServiceTypesList()); + recalculatePartitions(); + } + break; case CHILD_REMOVED: - recalculatePartitions(); + ScheduledFuture future = zkExecutorService.schedule(() -> { + log.debug("[{}] Going to recalculate partitions due to removed node [{}]", + instance.getServiceId(), instance.getServiceTypesList()); + delayedTasks.remove(instance.getServiceId()); + recalculatePartitions(); + }, recalculateDelay, TimeUnit.MILLISECONDS); + delayedTasks.put(instance.getServiceId(), future); break; default: break; diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 352f94e091..0dbb19a71a 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" queue: type: "${TB_QUEUE_TYPE:kafka}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 7ea553fe5c..c8f4b5a099 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 346ec48eae..fe181f12f2 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -68,6 +68,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 4e8167d89d..d80279f582 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 1e0b1ebcd4..fcbf542287 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 9f086bcbc5..0e84d54fce 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -41,6 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" cache: type: "${CACHE_TYPE:redis}" From ce9552e1a8ca44f58a369051bfc9f5bc24ca1477 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 6 Jul 2023 13:31:25 +0200 Subject: [PATCH 357/421] improvements --- .../queue/discovery/ZkDiscoveryService.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index 17d046a4cb..24a7863b24 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -299,16 +299,16 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi case CHILD_ADDED: ScheduledFuture task = delayedTasks.remove(instance.getServiceId()); if (task != null) { - if (!task.cancel(false)) { - log.debug("[{}] Going to recalculate partitions due to adding new node [{}]", + if (task.cancel(false)) { + log.debug("[{}] Recalculate partitions ignored. Service was restarted in time [{}].", instance.getServiceId(), instance.getServiceTypesList()); - recalculatePartitions(); } else { - log.debug("[{}] Recalculate partitions ignored. Service restarted in time [{}]", + log.debug("[{}] Going to recalculate partitions. Service was not restarted in time [{}]!", instance.getServiceId(), instance.getServiceTypesList()); + recalculatePartitions(); } } else { - log.debug("[{}] Going to recalculate partitions due to adding new node [{}]", + log.debug("[{}] Going to recalculate partitions due to adding new node [{}].", instance.getServiceId(), instance.getServiceTypesList()); recalculatePartitions(); } @@ -317,8 +317,10 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi ScheduledFuture future = zkExecutorService.schedule(() -> { log.debug("[{}] Going to recalculate partitions due to removed node [{}]", instance.getServiceId(), instance.getServiceTypesList()); - delayedTasks.remove(instance.getServiceId()); - recalculatePartitions(); + ScheduledFuture removedTask = delayedTasks.remove(instance.getServiceId()); + if (removedTask != null) { + recalculatePartitions(); + } }, recalculateDelay, TimeUnit.MILLISECONDS); delayedTasks.put(instance.getServiceId(), future); break; @@ -332,6 +334,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi * Synchronized to ensure that other servers info is up to date * */ synchronized void recalculatePartitions() { + delayedTasks.clear(); partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), getOtherServers()); } From 948f517898ff2207e6ba797e83ca2f77a3194790 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 14 Jul 2023 19:45:23 +0200 Subject: [PATCH 358/421] added zk restart node tests --- .../queue/discovery/ZkDiscoveryService.java | 2 +- .../discovery/ZkDiscoveryServiceTest.java | 173 ++++++++++++++++++ 2 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index 24a7863b24..50378d3387 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -71,7 +71,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi @Value("${zk.recalculate_delay:120000}") private Long recalculateDelay; - private final ConcurrentHashMap> delayedTasks; + protected final ConcurrentHashMap> delayedTasks; private final TbServiceInfoProvider serviceInfoProvider; private final PartitionService partitionService; diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java new file mode 100644 index 0000000000..38cad217aa --- /dev/null +++ b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java @@ -0,0 +1,173 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.queue.discovery; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.imps.CuratorFrameworkState; +import org.apache.curator.framework.recipes.cache.ChildData; +import org.apache.curator.framework.recipes.cache.PathChildrenCache; +import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.gen.transport.TransportProtos; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_ADDED; +import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_REMOVED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ZkDiscoveryServiceTest { + + @Mock + private TbServiceInfoProvider serviceInfoProvider; + + @Mock + private PartitionService partitionService; + + @Mock + private CuratorFramework client; + + @Mock + private PathChildrenCache cache; + + private ScheduledExecutorService zkExecutorService; + + @Mock + private CuratorFramework curatorFramework; + + private ZkDiscoveryService zkDiscoveryService; + + @Before + public void setup() { + zkDiscoveryService = Mockito.spy(new ZkDiscoveryService(serviceInfoProvider, partitionService)); + zkExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("zk-discovery")); + when(client.getState()).thenReturn(CuratorFrameworkState.STARTED); + ReflectionTestUtils.setField(zkDiscoveryService, "stopped", false); + ReflectionTestUtils.setField(zkDiscoveryService, "client", client); + ReflectionTestUtils.setField(zkDiscoveryService, "cache", cache); + ReflectionTestUtils.setField(zkDiscoveryService, "nodePath", "/thingsboard/nodes/0000000010"); + ReflectionTestUtils.setField(zkDiscoveryService, "zkExecutorService", zkExecutorService); + ReflectionTestUtils.setField(zkDiscoveryService, "recalculateDelay", 1000L); + ReflectionTestUtils.setField(zkDiscoveryService, "zkDir", "/thingsboard"); + } + + @Test + public void restartNodeTest() throws Exception { + var currentInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("currentId").build(); + var currentData = new ChildData("/thingsboard/nodes/0000000010", null, currentInfo.toByteArray()); + var childInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("childId").build(); + var childData = new ChildData("/thingsboard/nodes/0000000020", null, childInfo.toByteArray()); + + when(serviceInfoProvider.getServiceInfo()).thenReturn(currentInfo); + List dataList = new ArrayList<>(); + dataList.add(currentData); + when(cache.getCurrentData()).thenReturn(dataList); + + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + + //Restart in timeAssert.assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + stopNode(childData); + + assertEquals(1, zkDiscoveryService.delayedTasks.size()); + + verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + + startNode(childData); + + verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + + Thread.sleep(2000); + + verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + + assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + + //Restart not in time + stopNode(childData); + + assertEquals(1, zkDiscoveryService.delayedTasks.size()); + + Thread.sleep(2000); + + assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(Collections.emptyList())); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + + //Start another node during restart + var anotherInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("anotherId").build(); + var anotherData = new ChildData("/thingsboard/nodes/0000000030", null, anotherInfo.toByteArray()); + + stopNode(childData); + + assertEquals(1, zkDiscoveryService.delayedTasks.size()); + + startNode(anotherData); + + assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo))); + reset(partitionService); + + Thread.sleep(2000); + + verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo, childInfo))); + } + + private void startNode(ChildData data) throws Exception { + cache.getCurrentData().add(data); + zkDiscoveryService.childEvent(curatorFramework, new PathChildrenCacheEvent(CHILD_ADDED, data)); + } + + private void stopNode(ChildData data) throws Exception { + cache.getCurrentData().remove(data); + zkDiscoveryService.childEvent(curatorFramework, new PathChildrenCacheEvent(CHILD_REMOVED, data)); + } + +} From ac2aac8aa7a264e8ff9452714818cd1dfcc9ba00 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 28 Jul 2023 14:20:33 +0200 Subject: [PATCH 359/421] refactored due to comments --- .../src/main/resources/thingsboard.yml | 2 +- .../queue/discovery/ZkDiscoveryService.java | 26 +++++--- .../discovery/ZkDiscoveryServiceTest.java | 62 ++++++++++++------- .../src/main/resources/tb-vc-executor.yml | 2 +- .../src/main/resources/tb-coap-transport.yml | 2 +- .../src/main/resources/tb-http-transport.yml | 2 +- .../src/main/resources/tb-lwm2m-transport.yml | 2 +- .../src/main/resources/tb-mqtt-transport.yml | 2 +- .../src/main/resources/tb-snmp-transport.yml | 2 +- 9 files changed, 62 insertions(+), 40 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 19804c0588..1f16fbc414 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -96,7 +96,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cluster: stats: diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index 50378d3387..44999d016a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.queue.discovery; import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.ProtocolStringList; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.curator.framework.CuratorFramework; @@ -68,7 +69,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi private Integer zkSessionTimeout; @Value("${zk.zk_dir}") private String zkDir; - @Value("${zk.recalculate_delay:120000}") + @Value("${zk.recalculate_delay:60000}") private Long recalculateDelay; protected final ConcurrentHashMap> delayedTasks; @@ -294,35 +295,39 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi log.error("Failed to decode server instance for node {}", data.getPath(), e); throw e; } - log.debug("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), instance.getServiceId()); + + String serviceId = instance.getServiceId(); + ProtocolStringList serviceTypesList = instance.getServiceTypesList(); + + log.trace("Processing [{}] event for [{}]", pathChildrenCacheEvent.getType(), serviceId); switch (pathChildrenCacheEvent.getType()) { case CHILD_ADDED: - ScheduledFuture task = delayedTasks.remove(instance.getServiceId()); + ScheduledFuture task = delayedTasks.remove(serviceId); if (task != null) { if (task.cancel(false)) { log.debug("[{}] Recalculate partitions ignored. Service was restarted in time [{}].", - instance.getServiceId(), instance.getServiceTypesList()); + serviceId, serviceTypesList); } else { log.debug("[{}] Going to recalculate partitions. Service was not restarted in time [{}]!", - instance.getServiceId(), instance.getServiceTypesList()); + serviceId, serviceTypesList); recalculatePartitions(); } } else { - log.debug("[{}] Going to recalculate partitions due to adding new node [{}].", - instance.getServiceId(), instance.getServiceTypesList()); + log.trace("[{}] Going to recalculate partitions due to adding new node [{}].", + serviceId, serviceTypesList); recalculatePartitions(); } break; case CHILD_REMOVED: ScheduledFuture future = zkExecutorService.schedule(() -> { log.debug("[{}] Going to recalculate partitions due to removed node [{}]", - instance.getServiceId(), instance.getServiceTypesList()); - ScheduledFuture removedTask = delayedTasks.remove(instance.getServiceId()); + serviceId, serviceTypesList); + ScheduledFuture removedTask = delayedTasks.remove(serviceId); if (removedTask != null) { recalculatePartitions(); } }, recalculateDelay, TimeUnit.MILLISECONDS); - delayedTasks.put(instance.getServiceId(), future); + delayedTasks.put(serviceId, future); break; default: break; @@ -334,6 +339,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi * Synchronized to ensure that other servers info is up to date * */ synchronized void recalculatePartitions() { + delayedTasks.values().forEach(future -> future.cancel(false)); delayedTasks.clear(); partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), getOtherServers()); } diff --git a/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java index 38cad217aa..a8810efd0e 100644 --- a/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java +++ b/common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java @@ -63,68 +63,76 @@ public class ZkDiscoveryServiceTest { @Mock private PathChildrenCache cache; - private ScheduledExecutorService zkExecutorService; - @Mock private CuratorFramework curatorFramework; private ZkDiscoveryService zkDiscoveryService; + private static final long RECALCULATE_DELAY = 100L; + + final TransportProtos.ServiceInfo currentInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-rule-engine-0").build(); + final ChildData currentData = new ChildData("/thingsboard/nodes/0000000010", null, currentInfo.toByteArray()); + final TransportProtos.ServiceInfo childInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-rule-engine-1").build(); + final ChildData childData = new ChildData("/thingsboard/nodes/0000000020", null, childInfo.toByteArray()); + @Before public void setup() { zkDiscoveryService = Mockito.spy(new ZkDiscoveryService(serviceInfoProvider, partitionService)); - zkExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("zk-discovery")); + ScheduledExecutorService zkExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("zk-discovery")); when(client.getState()).thenReturn(CuratorFrameworkState.STARTED); ReflectionTestUtils.setField(zkDiscoveryService, "stopped", false); ReflectionTestUtils.setField(zkDiscoveryService, "client", client); ReflectionTestUtils.setField(zkDiscoveryService, "cache", cache); ReflectionTestUtils.setField(zkDiscoveryService, "nodePath", "/thingsboard/nodes/0000000010"); ReflectionTestUtils.setField(zkDiscoveryService, "zkExecutorService", zkExecutorService); - ReflectionTestUtils.setField(zkDiscoveryService, "recalculateDelay", 1000L); + ReflectionTestUtils.setField(zkDiscoveryService, "recalculateDelay", RECALCULATE_DELAY); ReflectionTestUtils.setField(zkDiscoveryService, "zkDir", "/thingsboard"); - } - - @Test - public void restartNodeTest() throws Exception { - var currentInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("currentId").build(); - var currentData = new ChildData("/thingsboard/nodes/0000000010", null, currentInfo.toByteArray()); - var childInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("childId").build(); - var childData = new ChildData("/thingsboard/nodes/0000000020", null, childInfo.toByteArray()); when(serviceInfoProvider.getServiceInfo()).thenReturn(currentInfo); + List dataList = new ArrayList<>(); dataList.add(currentData); when(cache.getCurrentData()).thenReturn(dataList); + } + @Test + public void restartNodeInTimeTest() throws Exception { startNode(childData); verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); reset(partitionService); - //Restart in timeAssert.assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); stopNode(childData); assertEquals(1, zkDiscoveryService.delayedTasks.size()); - verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + verify(partitionService, never()).recalculatePartitions(any(), any()); startNode(childData); - verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + verify(partitionService, never()).recalculatePartitions(any(), any()); - Thread.sleep(2000); + Thread.sleep(RECALCULATE_DELAY * 2); - verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + verify(partitionService, never()).recalculatePartitions(any(), any()); assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); + } + + @Test + public void restartNodeNotInTimeTest() throws Exception { + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); - //Restart not in time stopNode(childData); assertEquals(1, zkDiscoveryService.delayedTasks.size()); - Thread.sleep(2000); + Thread.sleep(RECALCULATE_DELAY * 2); assertTrue(zkDiscoveryService.delayedTasks.isEmpty()); @@ -135,11 +143,19 @@ public class ZkDiscoveryServiceTest { verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); reset(partitionService); + } - //Start another node during restart - var anotherInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("anotherId").build(); + @Test + public void startAnotherNodeDuringRestartTest() throws Exception { + var anotherInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-transport").build(); var anotherData = new ChildData("/thingsboard/nodes/0000000030", null, anotherInfo.toByteArray()); + startNode(childData); + + verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(childInfo))); + + reset(partitionService); + stopNode(childData); assertEquals(1, zkDiscoveryService.delayedTasks.size()); @@ -151,9 +167,9 @@ public class ZkDiscoveryServiceTest { verify(partitionService, times(1)).recalculatePartitions(eq(currentInfo), eq(List.of(anotherInfo))); reset(partitionService); - Thread.sleep(2000); + Thread.sleep(RECALCULATE_DELAY * 2); - verify(partitionService, never()).recalculatePartitions(eq(currentInfo), any()); + verify(partitionService, never()).recalculatePartitions(any(), any()); startNode(childData); diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 0dbb19a71a..66c6b4d3da 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" queue: type: "${TB_QUEUE_TYPE:kafka}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index c8f4b5a099..f4b5e0bc94 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index fe181f12f2..f92da86b99 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -68,7 +68,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index d80279f582..05388473f0 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index fcbf542287..e131788929 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 0e84d54fce..a7928eb49f 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:120000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" cache: type: "${CACHE_TYPE:redis}" From 20db421a8aefba1109d75524e7814d3cb5dd4199 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 31 Jul 2023 14:19:34 +0300 Subject: [PATCH 360/421] UI: Implement pagination support on overflow for toggle select/header component. --- .../add-widget-dialog.component.html | 2 +- .../dashboard-page.component.html | 2 +- .../components/toggle-header.component.html | 33 +++- .../components/toggle-header.component.scss | 26 +++ .../components/toggle-header.component.ts | 179 +++++++++++++++++- .../components/toggle-select.component.html | 1 + .../components/toggle-select.component.ts | 9 +- 7 files changed, 238 insertions(+), 14 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html index 7a17157b31..7de7acf413 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html @@ -20,7 +20,7 @@

widget.add

: {{data.widgetInfo.widgetName}}
- + {{ 'widget.basic-mode' | translate }} {{ 'widget.advanced-mode' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index 6432a3f234..b627783d47 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -360,7 +360,7 @@ [isReadOnly]="true" (closeDetails)="onEditWidgetClosed()">
- + {{ 'widget.basic-mode' | translate }} {{ 'widget.advanced-mode' | translate }} diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.html b/ui-ngx/src/app/shared/components/toggle-header.component.html index d7ed76de90..c2136558e3 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.html +++ b/ui-ngx/src/app/shared/components/toggle-header.component.html @@ -15,14 +15,31 @@ limitations under the License. --> - - {{ option.name }} - + +
+ + {{ option.name }} + +
+ diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.scss b/ui-ngx/src/app/shared/components/toggle-header.component.scss index 6a6785c11b..dd983f3de9 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.scss +++ b/ui-ngx/src/app/shared/components/toggle-header.component.scss @@ -17,8 +17,34 @@ @import "../../../theme"; @import "../../../scss/constants"; +:host { + max-width: 100%; + display: grid; + grid-template-columns: min-content minmax(auto, 1fr) min-content; + .tb-toggle-header-pagination-button { + display: none; + } + &.tb-toggle-header-pagination-controls-enabled { + .tb-toggle-header-pagination-button { + display: block; + } + } + .tb-toggle-container { + display: inline-grid; + grid-column: 2; + overflow: hidden; + &.tb-disable-pagination { + overflow: visible; + } + } + .tb-toggle-header { + transition: transform 500ms cubic-bezier(0.35, 0, 0.25, 1); + } +} + :host ::ng-deep { .mat-button-toggle-group.mat-button-toggle-group-appearance-standard.tb-toggle-header { + overflow: visible; width: 100%; border-radius: 100px; height: 32px; diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.ts b/ui-ngx/src/app/shared/components/toggle-header.component.ts index 35daad0e3f..6599a6fe35 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.ts +++ b/ui-ngx/src/app/shared/components/toggle-header.component.ts @@ -15,18 +15,22 @@ /// import { + AfterContentChecked, AfterContentInit, + AfterViewInit, ChangeDetectorRef, Component, ContentChildren, Directive, ElementRef, EventEmitter, + HostBinding, Input, OnDestroy, OnInit, Output, - QueryList + QueryList, + ViewChild } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; @@ -36,6 +40,8 @@ import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; import { coerceBoolean } from '@shared/decorators/coercion'; import { startWith, takeUntil } from 'rxjs/operators'; +import { Platform } from '@angular/cdk/platform'; +import { MatButtonToggle, MatButtonToggleGroup } from '@angular/material/button-toggle'; export interface ToggleHeaderOption { name: string; @@ -44,6 +50,8 @@ export interface ToggleHeaderOption { export type ToggleHeaderAppearance = 'fill' | 'fill-invert' | 'stroked'; +export type ScrollDirection = 'after' | 'before'; + @Directive( { // eslint-disable-next-line @angular-eslint/directive-selector @@ -72,7 +80,7 @@ export abstract class _ToggleBase extends PageComponent implements AfterContentI @Input() options: ToggleHeaderOption[] = []; - private _destroyed = new Subject(); + protected _destroyed = new Subject(); protected constructor(protected store: Store) { super(store); @@ -109,7 +117,34 @@ export abstract class _ToggleBase extends PageComponent implements AfterContentI templateUrl: './toggle-header.component.html', styleUrls: ['./toggle-header.component.scss'] }) -export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterContentInit, OnDestroy { +export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterViewInit, AfterContentInit, AfterContentChecked, OnDestroy { + + @ViewChild('toggleGroup', {static: false}) + toggleGroup: ElementRef; + + @ViewChild(MatButtonToggleGroup, {static: false}) + buttonToggleGroup: MatButtonToggleGroup; + + @ViewChild('toggleGroupContainer', {static: false}) + toggleGroupContainer: ElementRef; + + @HostBinding('class.tb-toggle-header-pagination-controls-enabled') + private showPaginationControls = false; + + private toggleGroupResize$: ResizeObserver; + + leftPaginationEnabled = false; + rightPaginationEnabled = false; + + private _scrollDistance = 0; + private _scrollDistanceChanged: boolean; + + get scrollDistance(): number { + return this._scrollDistance; + } + set scrollDistance(value: number) { + this._scrollTo(value); + } @Input() value: any; @@ -120,6 +155,10 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterC @Input() name: string; + @Input() + @coerceBoolean() + disablePagination = false; + @Input() @coerceBoolean() useSelectOnMdLg = true; @@ -141,6 +180,7 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterC constructor(protected store: Store, private cd: ChangeDetectorRef, + private platform: Platform, private breakpointObserver: BreakpointObserver) { super(store); } @@ -154,9 +194,142 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterC this.cd.markForCheck(); } ); + if (!this.disablePagination) { + this.valueChange.pipe(takeUntil(this._destroyed)).subscribe(() => { + this.scrollToToggleOptionValue(); + }); + } + } + + ngOnDestroy() { + if (this.toggleGroupResize$) { + this.toggleGroupResize$.disconnect(); + } + super.ngOnDestroy(); + } + + ngAfterViewInit() { + if (!this.disablePagination && !this.useSelectOnMdLg) { + this.toggleGroupResize$ = new ResizeObserver(() => { + this.updatePagination(); + }); + this.toggleGroupResize$.observe(this.toggleGroupContainer.nativeElement); + } + } + + ngAfterContentChecked() { + if (this._scrollDistanceChanged) { + this.updateToggleHeaderScrollPosition(); + this._scrollDistanceChanged = false; + this.cd.markForCheck(); + } } trackByHeaderOption(index: number, option: ToggleHeaderOption){ return option.value; } + + handlePaginatorClick(direction: ScrollDirection, $event: Event) { + if ($event) { + $event.stopPropagation(); + } + this.scrollHeader(direction); + } + + handlePaginatorTouchStart(direction: ScrollDirection, $event: Event) { + if (direction === 'before' && !this.leftPaginationEnabled || + direction === 'after' && !this.rightPaginationEnabled) { + $event.preventDefault(); + } + } + + private scrollHeader(direction: ScrollDirection) { + const viewLength = this.toggleGroup.nativeElement.offsetWidth; + // Move the scroll distance one-third the length of the tab list's viewport. + const scrollAmount = ((direction === 'before' ? -1 : 1) * viewLength) / 3; + return this._scrollTo(this._scrollDistance + scrollAmount); + } + + private scrollToToggleOptionValue() { + if (this.buttonToggleGroup && this.buttonToggleGroup.selected) { + const selectedToggleButton = this.buttonToggleGroup.selected as MatButtonToggle; + const viewLength = this.toggleGroupContainer.nativeElement.offsetWidth; + const {offsetLeft, offsetWidth} = (selectedToggleButton._buttonElement.nativeElement.offsetParent as HTMLElement); + const labelBeforePos = offsetLeft; // this.toggleGroup.nativeElement.offsetWidth - offsetLeft; + const labelAfterPos = labelBeforePos + offsetWidth; + const beforeVisiblePos = this.scrollDistance; + const afterVisiblePos = this.scrollDistance + viewLength; + if (labelBeforePos < beforeVisiblePos) { + this.scrollDistance -= beforeVisiblePos - labelBeforePos; + } else if (labelAfterPos > afterVisiblePos) { + this.scrollDistance += Math.min( + labelAfterPos - afterVisiblePos, + labelBeforePos - beforeVisiblePos, + ); + } + } + } + + private updatePagination() { + this.checkPaginationEnabled(); + this.checkPaginationControls(); + this.updateToggleHeaderScrollPosition(); + } + + private checkPaginationEnabled() { + if (this.toggleGroupContainer) { + const isEnabled = this.toggleGroup.nativeElement.scrollWidth > this.toggleGroupContainer.nativeElement.offsetWidth; + if (isEnabled !== this.showPaginationControls) { + if (!isEnabled) { + this.scrollDistance = 0; + } else { + setTimeout(() => { + this.scrollToToggleOptionValue(); + }, 0); + } + this.cd.markForCheck(); + this.showPaginationControls = isEnabled; + } + } else { + this.showPaginationControls = false; + } + } + + private checkPaginationControls() { + if (!this.showPaginationControls) { + this.leftPaginationEnabled = this.rightPaginationEnabled = false; + } else { + // Check if the pagination arrows should be activated. + this.leftPaginationEnabled = this.scrollDistance > 0; + this.rightPaginationEnabled = this.scrollDistance < this.getMaxScrollDistance(); + this.cd.markForCheck(); + } + } + + private getMaxScrollDistance(): number { + const lengthOfToggleGroup = this.toggleGroup.nativeElement.scrollWidth; + const viewLength = this.toggleGroupContainer.nativeElement.offsetWidth; + return lengthOfToggleGroup - viewLength || 0; + } + + private _scrollTo(position: number) { + if (!this.showPaginationControls) { + return {maxScrollDistance: 0, distance: 0}; + } else { + const maxScrollDistance = this.getMaxScrollDistance(); + this._scrollDistance = Math.max(0, Math.min(maxScrollDistance, position)); + this._scrollDistanceChanged = true; + this.checkPaginationControls(); + return {maxScrollDistance, distance: this._scrollDistance}; + } + } + + private updateToggleHeaderScrollPosition() { + const scrollDistance = this.scrollDistance; + const translateX = -scrollDistance; + this.toggleGroup.nativeElement.style.transform = `translateX(${Math.round(translateX)}px)`; + if (this.platform.TRIDENT || this.platform.EDGE) { + this.toggleGroupContainer.nativeElement.scrollLeft = 0; + } + } } diff --git a/ui-ngx/src/app/shared/components/toggle-select.component.html b/ui-ngx/src/app/shared/components/toggle-select.component.html index a5ce7778b5..819dc76ee4 100644 --- a/ui-ngx/src/app/shared/components/toggle-select.component.html +++ b/ui-ngx/src/app/shared/components/toggle-select.component.html @@ -20,6 +20,7 @@ useSelectOnMdLg="false" [disabled]="disabled" [appearance]="appearance" + [disablePagination]="disablePagination" [options]="options" [value]="modelValue" (valueChange)="updateModel($event)"> diff --git a/ui-ngx/src/app/shared/components/toggle-select.component.ts b/ui-ngx/src/app/shared/components/toggle-select.component.ts index 8338e04f6a..3eee0cf841 100644 --- a/ui-ngx/src/app/shared/components/toggle-select.component.ts +++ b/ui-ngx/src/app/shared/components/toggle-select.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input } from '@angular/core'; +import { Component, forwardRef, HostBinding, Input } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; @@ -35,6 +35,9 @@ import { coerceBoolean } from '@shared/decorators/coercion'; }) export class ToggleSelectComponent extends _ToggleBase implements ControlValueAccessor { + @HostBinding('style.maxWidth') + get maxWidth() { return '100%'; } + @Input() @coerceBoolean() disabled: boolean; @@ -42,6 +45,10 @@ export class ToggleSelectComponent extends _ToggleBase implements ControlValueAc @Input() appearance: ToggleHeaderAppearance = 'stroked'; + @Input() + @coerceBoolean() + disablePagination = false; + modelValue: any; private propagateChange = null; From bc43a39643448132ec65f0a35a875a269ea85900 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 31 Jul 2023 16:05:27 +0300 Subject: [PATCH 361/421] UI: Refactoring --- .../entity/entity-select.component.ts | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts index 93452e4620..6e235a2dad 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts @@ -121,18 +121,12 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte } writeValue(value: EntityId | null): void { - if (value != null) { - this.modelValue = value; - this.entitySelectFormGroup.get('entityType').patchValue(value.entityType, {emitEvent: false}); - this.entitySelectFormGroup.get('entityId').patchValue(value, {emitEvent: false}); - } else { - this.modelValue = { - entityType: this.defaultEntityType, - id: null - }; - this.entitySelectFormGroup.get('entityType').patchValue(this.defaultEntityType, {emitEvent: false}); - this.entitySelectFormGroup.get('entityId').patchValue(null, {emitEvent: false}); - } + this.modelValue = { + entityType: value?.entityType ? value.entityType : this.defaultEntityType, + id: value?.id ? value.id : null + }; + this.entitySelectFormGroup.get('entityType').patchValue(this.modelValue.entityType, {emitEvent: false}); + this.entitySelectFormGroup.get('entityId').patchValue(this.modelValue.id, {emitEvent: false}); } updateView(entityType: EntityType | AliasEntityType | null, entityId: string | null) { @@ -146,6 +140,8 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte || this.modelValue.entityType === AliasEntityType.CURRENT_USER || this.modelValue.entityType === AliasEntityType.CURRENT_USER_OWNER) { this.modelValue.id = NULL_UUID; + } else if (this.modelValue.entityType === AliasEntityType.CURRENT_CUSTOMER && !this.modelValue.id) { + this.modelValue.id = NULL_UUID; } if (this.modelValue.entityType && this.modelValue.id) { From 3f963107da0454183e89dda9dc868b44ba6ea433 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 31 Jul 2023 16:34:03 +0300 Subject: [PATCH 362/421] UI: Refactoring --- .../components/entity/entity-select.component.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts index 6e235a2dad..5190f486ad 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts @@ -121,10 +121,17 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte } writeValue(value: EntityId | null): void { - this.modelValue = { - entityType: value?.entityType ? value.entityType : this.defaultEntityType, - id: value?.id ? value.id : null - }; + if (value != null) { + this.modelValue = { + entityType: value.entityType, + id: value.id !== NULL_UUID ? value.id : null + }; + } else { + this.modelValue = { + entityType: value?.entityType ? value.entityType : this.defaultEntityType, + id: null + }; + } this.entitySelectFormGroup.get('entityType').patchValue(this.modelValue.entityType, {emitEvent: false}); this.entitySelectFormGroup.get('entityId').patchValue(this.modelValue.id, {emitEvent: false}); } From 6cee9caad73e7ce1d26b6887d70f9d54616ab1a5 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 31 Jul 2023 17:01:41 +0300 Subject: [PATCH 363/421] UI: Refactoring --- .../src/app/shared/components/entity/entity-select.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts index 5190f486ad..4874c6c186 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-select.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-select.component.ts @@ -128,7 +128,7 @@ export class EntitySelectComponent implements ControlValueAccessor, OnInit, Afte }; } else { this.modelValue = { - entityType: value?.entityType ? value.entityType : this.defaultEntityType, + entityType: this.defaultEntityType, id: null }; } From d39ab98cfa21c06e445ec2db2dc3b5bcb7bc2b82 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 1 Aug 2023 10:35:59 +0300 Subject: [PATCH 364/421] UI: Refactoring for tabs --- ui-ngx/src/app/core/services/menu.service.ts | 100 ------------------ .../pages/account/account-routing.module.ts | 6 +- .../notification-settings-routing.modules.ts | 2 +- 3 files changed, 6 insertions(+), 102 deletions(-) diff --git a/ui-ngx/src/app/core/services/menu.service.ts b/ui-ngx/src/app/core/services/menu.service.ts index 42431c01cb..0de3346af9 100644 --- a/ui-ngx/src/app/core/services/menu.service.ts +++ b/ui-ngx/src/app/core/services/menu.service.ts @@ -136,42 +136,6 @@ export class MenuService { } ] }, - { - id: 'account', - name: 'profile.profile', - type: 'link', - path: '/account', - disabled: true, - icon: 'mdi:message-badge', - isMdiIcon: true, - pages: [ - { - id: 'personal_info', - name: 'account.personal-info', - fullName: 'account.personal-info', - type: 'link', - path: '/account/profile', - icon: 'mdi:badge-account-horizontal', - isMdiIcon: true - }, - { - id: 'security', - name: 'security.security', - fullName: 'security.security', - type: 'link', - path: '/account/security', - icon: 'lock' - }, - { - id: 'notificationSettings', - name: 'account.notification-settings', - fullName: 'account.notification-settings', - type: 'link', - path: '/account/notificationSettings', - icon: 'settings' - } - ] - }, { id: 'notifications_center', name: 'notification.notification-center', @@ -540,42 +504,6 @@ export class MenuService { } ] }, - { - id: 'account', - name: 'profile.profile', - type: 'link', - path: '/account', - disabled: true, - icon: 'mdi:message-badge', - isMdiIcon: true, - pages: [ - { - id: 'personal_info', - name: 'account.personal-info', - fullName: 'account.personal-info', - type: 'link', - path: '/account/profile', - icon: 'mdi:badge-account-horizontal', - isMdiIcon: true - }, - { - id: 'security', - name: 'security.security', - fullName: 'security.security', - type: 'link', - path: '/account/security', - icon: 'lock' - }, - { - id: 'notificationSettings', - name: 'account.notification-settings', - fullName: 'account.notification-settings', - type: 'link', - path: '/account/notificationSettings', - icon: 'settings' - } - ] - }, { id: 'notifications_center', name: 'notification.notification-center', @@ -904,34 +832,6 @@ export class MenuService { icon: 'view_quilt' } ] - }, - { - id: 'account', - name: 'profile.profile', - type: 'link', - path: '/account', - disabled: true, - icon: 'mdi:message-badge', - isMdiIcon: true, - pages: [ - { - id: 'personal_info', - name: 'account.personal-info', - fullName: 'account.personal-info', - type: 'link', - path: '/account/profile', - icon: 'mdi:badge-account-horizontal', - isMdiIcon: true - }, - { - id: 'security', - name: 'security.security', - fullName: 'security.security', - type: 'link', - path: '/account/security', - icon: 'lock' - } - ] } ); if (authState.edgesSupportEnabled) { diff --git a/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts b/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts index 9fcaecddfd..e2c997f654 100644 --- a/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/account/account-routing.module.ts @@ -23,6 +23,9 @@ import { profileRoutes } from '@home/pages/profile/profile-routing.module'; import { getCurrentAuthState } from '@core/auth/auth.selectors'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; +import { + notificationUserSettingsRoutes +} from '@home/pages/notification/settings/notification-settings-routing.modules'; const routes: Routes = [ { @@ -49,7 +52,8 @@ const routes: Routes = [ } }, ...profileRoutes, - ...securityRoutes + ...securityRoutes, + ...notificationUserSettingsRoutes ] } ]; diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts index 8e93ef4390..e6aababc33 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts @@ -36,7 +36,7 @@ export class NotificationUserSettingsResolver implements Resolve { } } -export const NotificationUserSettingsRoutes: Routes = [ +export const notificationUserSettingsRoutes: Routes = [ { path: 'notificationSettings', component: NotificationSettingsComponent, From 84c82dbc12bac2dcdeac70345e6ab4ab650c6fc9 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 1 Aug 2023 11:56:46 +0300 Subject: [PATCH 365/421] UI: Refactoring --- .../modules/home/menu/side-menu.component.ts | 12 +------ .../notification-settings-routing.modules.ts | 34 +++---------------- .../assets/locale/locale.constant-en_US.json | 8 ++--- 3 files changed, 7 insertions(+), 47 deletions(-) diff --git a/ui-ngx/src/app/modules/home/menu/side-menu.component.ts b/ui-ngx/src/app/modules/home/menu/side-menu.component.ts index cf3e5ca4db..f6e1f30624 100644 --- a/ui-ngx/src/app/modules/home/menu/side-menu.component.ts +++ b/ui-ngx/src/app/modules/home/menu/side-menu.component.ts @@ -17,8 +17,6 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { MenuService } from '@core/services/menu.service'; import { MenuSection } from '@core/services/menu.models'; -import { Observable, of } from 'rxjs'; -import { mergeMap, share } from 'rxjs/operators'; @Component({ selector: 'tb-side-menu', @@ -28,23 +26,15 @@ import { mergeMap, share } from 'rxjs/operators'; }) export class SideMenuComponent implements OnInit { - menuSections$: Observable>; + menuSections$ = this.menuService.menuSections(); constructor(private menuService: MenuService) { - this.menuSections$ = this.menuService.menuSections().pipe( - mergeMap((sections) => this.filterSections(sections)), - share() - ); } trackByMenuSection(index: number, section: MenuSection){ return section.id; } - private filterSections(sections: Array): Observable> { - return of(sections.filter(section => !section.disabled)); - } - ngOnInit() { } diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts index e6aababc33..3d61e4b227 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts @@ -14,28 +14,13 @@ /// limitations under the License. /// -import { Resolve, RouterModule, Routes } from '@angular/router'; +import { Routes } from '@angular/router'; import { ConfirmOnExitGuard } from '@core/guards/confirm-on-exit.guard'; import { Authority } from '@shared/models/authority.enum'; -import { Injectable, NgModule } from '@angular/core'; +import { inject, NgModule } from '@angular/core'; import { NotificationSettingsComponent } from '@home/pages/notification/settings/notification-settings.component'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; -import { Observable } from 'rxjs'; import { NotificationService } from '@core/http/notification.service'; -@Injectable() -export class NotificationUserSettingsResolver implements Resolve { - - constructor(private store: Store, - private notificationService: NotificationService) { - } - - resolve(): Observable { - return this.notificationService.getNotificationUserSettings(); - } -} - export const notificationUserSettingsRoutes: Routes = [ { path: 'notificationSettings', @@ -50,21 +35,10 @@ export const notificationUserSettingsRoutes: Routes = [ } }, resolve: { - userSettings: NotificationUserSettingsResolver + userSettings: () => inject(NotificationService).getNotificationUserSettings() } } ]; -const routes: Routes = [ - { - path: 'notificationSettings', - redirectTo: '/account/notificationSettings' - } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], - providers: [NotificationUserSettingsResolver] -}) +@NgModule({}) export class NotificationSettingsRoutingModules { } 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 dadc52e670..bc22dfb195 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -11,7 +11,8 @@ "permission-denied-text": "You don't have permission to perform this operation!" }, "account": { - "account": "Account" + "account": "Account", + "notification-settings": "Notification settings" }, "action": { "activate": "Activate", @@ -3221,11 +3222,6 @@ "profiles": { "profiles": "Profiles" }, - "account": { - "account": "Account", - "personal-info": "Personal info", - "notification-settings": "Notification settings" - }, "security": { "security": "Security", "general-settings": "General security settings", From 8fa41c3d5e9f8922032b9e9db57c04c68c30fb97 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 1 Aug 2023 12:02:37 +0300 Subject: [PATCH 366/421] UI: Remove class --- .../modules/home/pages/notification/notification.module.ts | 4 ---- .../settings/notification-settings-routing.modules.ts | 3 --- 2 files changed, 7 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/notification/notification.module.ts b/ui-ngx/src/app/modules/home/pages/notification/notification.module.ts index f041e632fa..389bf358d6 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/notification.module.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/notification.module.ts @@ -36,9 +36,6 @@ import { EscalationsComponent } from '@home/pages/notification/rule/escalations. import { RuleNotificationDialogComponent } from '@home/pages/notification/rule/rule-notification-dialog.component'; import { RuleTableHeaderComponent } from '@home/pages/notification/rule/rule-table-header.component'; import { NotificationSettingsComponent } from '@home/pages/notification/settings/notification-settings.component'; -import { - NotificationSettingsRoutingModules -} from '@home/pages/notification/settings/notification-settings-routing.modules'; import { NotificationSettingFormComponent } from '@home/pages/notification/settings/notification-setting-form.component'; @@ -64,7 +61,6 @@ import { CommonModule, SharedModule, NotificationRoutingModule, - NotificationSettingsRoutingModules, HomeComponentsModule ] }) diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts index 3d61e4b227..6a65e554bf 100644 --- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts +++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings-routing.modules.ts @@ -39,6 +39,3 @@ export const notificationUserSettingsRoutes: Routes = [ } } ]; - -@NgModule({}) -export class NotificationSettingsRoutingModules { } From 698dfba952ecf9430bd5a43dc104f851b37001d6 Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 1 Aug 2023 14:56:50 +0300 Subject: [PATCH 367/421] tbel: rollback validation switch --- .../script/api/tbel/DefaultTbelInvokeService.java | 7 ------- pom.xml | 2 +- ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js | 9 ++------- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java index bbf441a659..2a60980f84 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java @@ -66,8 +66,6 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem protected final Map scriptIdToHash = new ConcurrentHashMap<>(); protected final Map scriptMap = new ConcurrentHashMap<>(); - private final String tbelSwitch = "switch"; - private final String tbelSwitchErrorMsg = "TBEL does not support the 'switch'."; protected Cache compiledScriptsCache; private SandboxedParserConfiguration parserConfig; @@ -183,11 +181,6 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem lock.unlock(); } return scriptId; - } catch (CompileException ce) { - if ( ce.getExpr() != null && new String(ce.getExpr()).contains(tbelSwitch)) { - ce = new CompileException(tbelSwitchErrorMsg, ce.getExpr(), ce.getCursor(), ce.getCause()); - } - throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, ce); } catch (Exception e) { throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, e); } diff --git a/pom.xml b/pom.xml index 59d1eff5d3..df8c6ed8d6 100755 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ 3.8.1 3.21.9 1.42.1 - 1.0.6 + 1.0.7 1.18.18 1.2.4 1.2.5 diff --git a/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js b/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js index 3a4b3d90b8..d1d47d0c75 100644 --- a/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js +++ b/ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js @@ -5229,10 +5229,6 @@ var JSHINT = (function() { var a = [], p; while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { - if (state.tokens.next.value === "switch") { - warning("E067", state.tokens.next, "switch"); - break; - } if (state.tokens.next.id === ";") { p = peek(); @@ -9219,7 +9215,7 @@ var JSHINT = (function() { statements(0); } - if (state.tokens.next.id !== "(end)"&& state.tokens.next.value !== "switch") { + if (state.tokens.next.id !== "(end)") { quit("E041", state.tokens.curr); } @@ -11270,8 +11266,7 @@ var errors = { E064: "Super call may only be used within class method bodies.", E065: "Functions defined outside of strict mode with non-simple parameter lists may not " + "enable strict mode.", - E066: "Asynchronous iteration is only available with for-of loops.", - E067: "Expected an 'if/else' and instead saw 'switch'. TBEL does not support the 'switch' statement." + E066: "Asynchronous iteration is only available with for-of loops." }; var warnings = { From 165b1068bccb932e03e995187bcbe52cdbc335cb Mon Sep 17 00:00:00 2001 From: rusikv Date: Tue, 1 Aug 2023 17:54:39 +0300 Subject: [PATCH 368/421] Refactoring --- .../attribute/attribute-table.component.html | 12 +-- .../attribute/attribute-table.component.ts | 16 +++- .../delete-timeseries-panel.component.html | 16 ++-- .../delete-timeseries-panel.component.scss | 2 +- .../delete-timeseries-panel.component.ts | 90 +++++++++++++------ 5 files changed, 87 insertions(+), 49 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html index 95ade10645..788aeeaabc 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html @@ -85,20 +85,12 @@ 'attribute.selected-telemetry' : 'attribute.selected-attributes') | translate:{count: dataSource.selection.selected.length} }} - -
-
+ diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss index c0f26644d5..d223b29b47 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss @@ -22,7 +22,7 @@ } :host ::ng-deep{ - div .mat-toolbar { + form .mat-toolbar { background: none; } } diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts index 364ecd2c9a..96eaa5aa1b 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts @@ -14,13 +14,15 @@ /// limitations under the License. /// -import { Component, Inject, InjectionToken, OnInit } from '@angular/core'; +import { Component, Inject, InjectionToken, OnDestroy, OnInit } from '@angular/core'; import { OverlayRef } from '@angular/cdk/overlay'; import { TimeseriesDeleteStrategy, timeseriesDeleteStrategyTranslations } from '@shared/models/telemetry/telemetry.models'; import { MINUTE } from '@shared/models/time/time.models'; +import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Subscription } from 'rxjs'; export const DELETE_TIMESERIES_PANEL_DATA = new InjectionToken('DeleteTimeseriesPanelData'); @@ -33,17 +35,15 @@ export interface DeleteTimeseriesPanelData { templateUrl: './delete-timeseries-panel.component.html', styleUrls: ['./delete-timeseries-panel.component.scss'] }) -export class DeleteTimeseriesPanelComponent implements OnInit { +export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { - strategy: string = TimeseriesDeleteStrategy.DELETE_ALL_DATA; + deleteTimeseriesFormGroup: UntypedFormGroup; - result: string = null; - - startDateTime: Date; + startDateTimeSubscription: Subscription; - endDateTime: Date; + endDateTimeSubscription: Subscription; - rewriteLatestIfDeleted: boolean = true; + result: string = null; strategiesTranslationsMap = timeseriesDeleteStrategyTranslations; @@ -53,22 +53,40 @@ export class DeleteTimeseriesPanelComponent implements OnInit { ]; constructor(@Inject(DELETE_TIMESERIES_PANEL_DATA) public data: DeleteTimeseriesPanelData, - public overlayRef: OverlayRef) { } + public overlayRef: OverlayRef, + public fb: UntypedFormBuilder) { } ngOnInit(): void { - let today = new Date(); - this.startDateTime = new Date(today.getFullYear(), today.getMonth() - 1, today.getDate()); - this.endDateTime = today; + const today = new Date(); if (this.data.isMultipleDeletion) { this.strategiesTranslationsMap = new Map(Array.from(this.strategiesTranslationsMap.entries()) .filter(([strategy]) => { return this.multipleDeletionStrategies.includes(strategy); })) } + this.deleteTimeseriesFormGroup = this.fb.group({ + strategy: [TimeseriesDeleteStrategy.DELETE_ALL_DATA], + startDateTime: [new Date(today.getFullYear(), today.getMonth() - 1, today.getDate())], + endDateTime: [today], + rewriteLatest: [true] + }) + this.startDateTimeSubscription = this.getStartDateTimeFormControl().valueChanges.subscribe( + value => this.onStartDateTimeChange(value) + ) + this.endDateTimeSubscription = this.getEndDateTimeFormControl().valueChanges.subscribe( + value => this.onEndDateTimeChange(value) + ) + } + + ngOnDestroy(): void { + this.startDateTimeSubscription.unsubscribe(); + this.startDateTimeSubscription = null; + this.endDateTimeSubscription.unsubscribe(); + this.endDateTimeSubscription = null; } delete(): void { - this.result = this.strategy; + this.result = this.getStrategyFormControl().value; this.overlayRef.dispose(); } @@ -77,28 +95,50 @@ export class DeleteTimeseriesPanelComponent implements OnInit { } isPeriodStrategy(): boolean { - return this.strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD; + return this.getStrategyFormControl().value === TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD; } isDeleteLatestStrategy(): boolean { - return this.strategy === TimeseriesDeleteStrategy.DELETE_LATEST_VALUE; + return this.getStrategyFormControl().value === TimeseriesDeleteStrategy.DELETE_LATEST_VALUE; + } + + getStrategyFormControl(): AbstractControl { + return this.deleteTimeseriesFormGroup.get('strategy'); + } + + getStartDateTimeFormControl(): AbstractControl { + return this.deleteTimeseriesFormGroup.get('startDateTime'); + } + + getEndDateTimeFormControl(): AbstractControl { + return this.deleteTimeseriesFormGroup.get('endDateTime'); + } + + getRewriteLatestFormControl(): AbstractControl { + return this.deleteTimeseriesFormGroup.get('rewriteLatest'); } onStartDateTimeChange(newStartDateTime: Date) { - const endDateTimeTs = this.endDateTime.getTime(); - if (newStartDateTime.getTime() >= endDateTimeTs) { - this.startDateTime = new Date(endDateTimeTs - MINUTE); - } else { - this.startDateTime = newStartDateTime; + if (newStartDateTime) { + const endDateTimeTs = this.deleteTimeseriesFormGroup.get('endDateTime').value.getTime(); + const startDateTimeControl = this.getStartDateTimeFormControl(); + if (newStartDateTime.getTime() >= endDateTimeTs) { + startDateTimeControl.patchValue(new Date(endDateTimeTs - MINUTE), {onlySelf: true, emitEvent: false}); + } else { + startDateTimeControl.patchValue(newStartDateTime, {onlySelf: true, emitEvent: false}); + } } } onEndDateTimeChange(newEndDateTime: Date) { - const startDateTimeTs = this.startDateTime.getTime(); - if (newEndDateTime.getTime() <= startDateTimeTs) { - this.endDateTime = new Date(startDateTimeTs + MINUTE); - } else { - this.endDateTime = newEndDateTime; + if (newEndDateTime) { + const startDateTimeTs = this.deleteTimeseriesFormGroup.get('startDateTime').value.getTime(); + const endDateTimeControl = this.getEndDateTimeFormControl(); + if (newEndDateTime.getTime() <= startDateTimeTs) { + endDateTimeControl.patchValue(new Date(startDateTimeTs + MINUTE), {onlySelf: true, emitEvent: false}); + } else { + endDateTimeControl.patchValue(newEndDateTime, {onlySelf: true, emitEvent: false}); + } } } } From bd24bb7335f4501a46ff016494a3f148cb3435e7 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 1 Aug 2023 19:58:59 +0300 Subject: [PATCH 369/421] Widgets UI config: Responsive layout improvements. --- .../add-widget-dialog.component.html | 18 +++-- .../add-widget-dialog.component.scss | 9 +++ .../dashboard-page.component.html | 25 +++++-- .../dashboard-page.component.ts | 2 +- .../dashboard-toolbar.component.scss | 37 ++++++++++ .../dashboard-page/edit-widget.component.html | 44 +++++++---- .../dashboard-page/edit-widget.component.scss | 2 +- .../components/details-panel.component.html | 2 +- .../components/details-panel.component.scss | 13 ++-- .../alarms-table-basic-config.component.html | 2 +- .../widget/config/basic/basic-config.scss | 6 ++ ...entities-table-basic-config.component.html | 2 +- .../simple-card-basic-config.component.html | 2 +- ...meseries-table-basic-config.component.html | 2 +- .../value-card-basic-config.component.html | 2 +- .../chart/flot-basic-config.component.html | 2 +- .../basic/common/data-key-row.component.html | 3 +- .../basic/common/data-key-row.component.scss | 30 +++++++- .../common/data-keys-panel.component.html | 3 +- .../common/data-keys-panel.component.scss | 40 ++++++++-- .../timewindow-config-panel.component.html | 11 +-- .../common/legend-config.component.html | 2 +- .../widget/lib/settings/widget-settings.scss | 3 + .../widget/widget-config.component.html | 22 +++--- .../widget/widget-config.component.scss | 35 +++++++-- .../components/time/timewindow.component.scss | 3 + .../components/time/timewindow.component.ts | 7 +- .../components/toggle-header.component.html | 8 +- .../components/toggle-header.component.scss | 3 - .../components/toggle-header.component.ts | 74 +++++++++++++++---- .../components/toggle-select.component.html | 1 + .../components/toggle-select.component.ts | 3 + ui-ngx/src/form.scss | 66 ++++++++++++----- ui-ngx/src/styles.scss | 29 +++++++- 34 files changed, 393 insertions(+), 120 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html index 7de7acf413..47f8634462 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/add-widget-dialog.component.html @@ -17,14 +17,16 @@ -->
-

widget.add

- : {{data.widgetInfo.widgetName}} -
- - {{ 'widget.basic-mode' | translate }} - {{ 'widget.advanced-mode' | translate }} - -
+
+

{{'widget.add' | translate}}: {{data.widgetInfo.widgetName}}

+
+ + {{ 'widget.basic-mode' | translate }} + {{ 'widget.advanced-mode' | translate }} + +
+
+ + + + @@ -360,7 +371,7 @@ [isReadOnly]="true" (closeDetails)="onEditWidgetClosed()">
- + {{ 'widget.basic-mode' | translate }} {{ 'widget.advanced-mode' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index cead69ab46..3996c1abaf 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -191,7 +191,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC } get hideToolbar(): boolean { - return (this.hideToolbarValue || this.hideToolbarSetting()) && !this.isEdit; + return ((this.hideToolbarValue || this.hideToolbarSetting()) && !this.isEdit) || (this.isEditingWidget || this.isAddingWidget); } @Input() diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-toolbar.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-toolbar.component.scss index 0d9ade9bf6..e43132c761 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-toolbar.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-toolbar.component.scss @@ -126,6 +126,7 @@ tb-dashboard-toolbar { @media #{$mat-lt-md} { height: $mobile-toolbar-height; max-height: $mobile-toolbar-height; + padding: 0 8px !important; } .close-action { @@ -150,8 +151,44 @@ tb-dashboard-toolbar { .tb-dashboard-action-panel { min-width: 0; height: $half-mobile-toolbar-height; + flex: 1 0 auto; + display: flex; + flex-direction: row-reverse; + place-content: center space-between; + align-items: center; + &.tb-left-panel { + flex: 1 1 auto; + } + + @media #{$mat-lt-md} { + padding-left: 12px; + } + + @media #{$mat-xs} { + gap: 3px; + padding-left: 0; + &.tb-left-panel { + padding-left: 12px; + } + } + + @media #{$mat-sm} { + gap: 6px; + } + + @media #{$mat-md} { + gap: 6px; + } + + @media #{$mat-gt-md} { + gap: 12px; + } @media #{$mat-gt-sm} { + place-content: center flex-start; + &.tb-left-panel { + place-content: center flex-end; + } height: 46px; } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html index a1c8ee6ade..86f069239c 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.html @@ -32,26 +32,38 @@ chevron_left {{ 'action.back' | translate }} -
-
- - -
+
+ +
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss index c31f1d5791..9c4e20a7a5 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/edit-widget.component.scss @@ -16,7 +16,7 @@ :host { .widget-preview-background { position: absolute; - top: 72px; + top: 68px; left: 0; right: 0; bottom: 0; diff --git a/ui-ngx/src/app/modules/home/components/details-panel.component.html b/ui-ngx/src/app/modules/home/components/details-panel.component.html index 15df7e99e5..748723197f 100644 --- a/ui-ngx/src/app/modules/home/components/details-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/details-panel.component.html @@ -21,7 +21,7 @@
- {{ headerTitle }} + {{ headerTitle }}
{{ headerSubtitle }} diff --git a/ui-ngx/src/app/modules/home/components/details-panel.component.scss b/ui-ngx/src/app/modules/home/components/details-panel.component.scss index 9002246841..451795a2d1 100644 --- a/ui-ngx/src/app/modules/home/components/details-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/details-panel.component.scss @@ -32,16 +32,14 @@ max-height: 120px; &.tb-details-title-header { min-width: 0; + padding: 0 16px 0 8px; } } .tb-details-title { width: inherit; margin: 20px 8px 0 0; - overflow: hidden; font-size: 1rem; font-weight: 400; - text-overflow: ellipsis; - white-space: nowrap; @media #{$mat-gt-sm} { font-size: 1.5rem; @@ -49,13 +47,16 @@ } .tb-details-subtitle { - width: inherit; margin: 10px 0; - overflow: hidden; font-size: 1rem; + opacity: .8; + } + + .tb-details-title-text, .tb-details-subtitle { + width: inherit; + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - opacity: .8; } tb-dashboard { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html index 18cd34609e..ffddc9df59 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html @@ -72,7 +72,7 @@
-
+
widget-config.show-card-buttons
{{ 'action.search' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-config.scss b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-config.scss index d29594fce3..0f88b8f1dc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-config.scss +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-config.scss @@ -13,8 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +@import '../../../../../../../scss/constants'; + :host { display: flex; flex-direction: column; gap: 16px; + @media #{$mat-xs} { + gap: 8px; + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html index c5501ae830..c68caab86e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html @@ -61,7 +61,7 @@
-
+
widget-config.show-card-buttons
{{ 'action.search' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html index 142f32cd4e..92bd2e44ab 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.html @@ -61,7 +61,7 @@
-
+
widget-config.show-card-buttons
{{ 'fullscreen.fullscreen' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html index bab6437485..49196fac3a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html @@ -61,7 +61,7 @@
-
+
widget-config.show-card-buttons
{{ 'action.search' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html index 51bb854826..788c997740 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html @@ -105,7 +105,7 @@
-
+
widget-config.show-card-buttons
{{ 'fullscreen.fullscreen' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html index 1439f74931..952b3f9031 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html @@ -61,7 +61,7 @@
-
+
widget-config.show-card-buttons
{{ 'fullscreen.fullscreen' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html index 22c4c2aace..62f34f3d28 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html @@ -158,7 +158,8 @@
-
-
+
legend.show-values
{{ 'legend.min-option' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.scss index 1971b02b6c..ed74372105 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.scss @@ -19,6 +19,9 @@ display: flex; flex-direction: column; gap: 16px; + @media #{$mat-xs} { + gap: 8px; + } .tb-widget-settings { .fields-group { 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 07f655c768..c9dd0732be 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 @@ -20,8 +20,10 @@ - - +
+ + +
@@ -48,18 +50,18 @@
-
+
{{ 'widget-config.display-icon' | translate }}
+ + + - - - @@ -247,7 +249,7 @@
widget-config.limits
-
+
widget-config.data-page-size
@@ -258,19 +260,19 @@
widget-config.data-settings
-
+
widget-config.units
-
+
widget-config.decimals
-
+
widget-config.no-data-display-message
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss index 91b3368ad0..701bfec099 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.scss @@ -20,16 +20,36 @@ .tb-widget-config { display: flex; flex-direction: column; - gap: 16px; + gap: 8px; .tb-widget-config-header { - padding: 24px 24px 8px; - height: 56px; + padding: 24px 24px 0; display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; + gap: 12px; + flex-direction: column-reverse; + align-items: flex-start; + @media #{$mat-gt-sm} { + gap: 0; + flex-direction: row; + align-items: center; + justify-content: space-between; + } + .tb-widget-config-header-components { + width: 100%; + flex: 1; + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + } } .tb-widget-config-content { + & > .mat-content { + padding-top: 8px; + @media #{$mat-xs} { + padding-left: 8px; + padding-right: 8px; + } + } flex: 1; overflow: auto; & > div { @@ -39,6 +59,9 @@ display: flex; flex-direction: column; gap: 16px; + @media #{$mat-xs} { + gap: 8px; + } } } .tb-basic-mode-directive-error { diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.scss b/ui-ngx/src/app/shared/components/time/timewindow.component.scss index 695362197d..af3feec6eb 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.scss +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.scss @@ -17,6 +17,9 @@ min-width: 48px; margin: 8px 0; max-width: 100%; + &.no-margin { + margin: 0; + } .mdc-button { max-width: 100%; } diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.ts b/ui-ngx/src/app/shared/components/time/timewindow.component.ts index f9b40daac1..ff39e54fc7 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.ts @@ -18,7 +18,7 @@ import { ChangeDetectorRef, Component, ElementRef, - forwardRef, + forwardRef, HostBinding, Injector, Input, StaticProvider, @@ -83,6 +83,11 @@ export class TimewindowComponent implements ControlValueAccessor { return this.historyOnlyValue; } + @HostBinding('class.no-margin') + @Input() + @coerceBoolean() + noMargin = false; + @Input() @coerceBoolean() forAllTimeEnabled = false; diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.html b/ui-ngx/src/app/shared/components/toggle-header.component.html index c2136558e3..7aa391b3b4 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.html +++ b/ui-ngx/src/app/shared/components/toggle-header.component.html @@ -16,13 +16,14 @@ --> -
+
+ class="tb-toggle-header-pagination-button" [class]="{'tb-mat-32': !isMdLg, 'tb-mat-24': isMdLg}"> chevron_right diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.scss b/ui-ngx/src/app/shared/components/toggle-header.component.scss index dd983f3de9..7a41032961 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.scss +++ b/ui-ngx/src/app/shared/components/toggle-header.component.scss @@ -178,9 +178,6 @@ line-height: 16px; letter-spacing: 0.25px; } - .mat-mdc-select-value { - color: rgba(0, 0, 0, 0.38); - } .mat-mdc-select-arrow-wrapper { height: 12px; padding-left: 6px; diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.ts b/ui-ngx/src/app/shared/components/toggle-header.component.ts index 6599a6fe35..a7bddfc7b4 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.ts +++ b/ui-ngx/src/app/shared/components/toggle-header.component.ts @@ -35,7 +35,7 @@ import { import { PageComponent } from '@shared/components/page.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { Subject, Subscription } from 'rxjs'; +import { BehaviorSubject, Subject, Subscription } from 'rxjs'; import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; import { coerceBoolean } from '@shared/decorators/coercion'; @@ -159,9 +159,20 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV @coerceBoolean() disablePagination = false; + @Input() + selectMediaBreakpoint = 'md-lg'; + @Input() @coerceBoolean() - useSelectOnMdLg = true; + set useSelectOnMdLg(value: boolean) { + if (value) { + this.selectMediaBreakpoint = 'md-lg'; + } else { + if (this.selectMediaBreakpoint === 'md-lg') { + this.selectMediaBreakpoint = ''; + } + } + } @Input() @coerceBoolean() @@ -174,7 +185,14 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV @coerceBoolean() disabled = false; - isMdLg: boolean; + get isMdLg(): boolean { + return !this.ignoreMdLgSize && this.isMdLgValue; + } + + private isMdLgValue: boolean; + private useSelectSubject = new BehaviorSubject(false); + + useSelect$ = this.useSelectSubject.asObservable(); private observeBreakpointSubscription: Subscription; @@ -186,11 +204,19 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV } ngOnInit() { - this.isMdLg = this.breakpointObserver.isMatched(MediaBreakpoints['md-lg']); + const mediaBreakpoints = [MediaBreakpoints['md-lg']]; + if (this.selectMediaBreakpoint && this.selectMediaBreakpoint !== 'md-lg') { + mediaBreakpoints.push(MediaBreakpoints[this.selectMediaBreakpoint]); + } this.observeBreakpointSubscription = this.breakpointObserver - .observe(MediaBreakpoints['md-lg']) + .observe(mediaBreakpoints) .subscribe((state: BreakpointState) => { - this.isMdLg = state.matches; + this.isMdLgValue = state.breakpoints[MediaBreakpoints['md-lg']]; + if (this.selectMediaBreakpoint) { + this.useSelectSubject.next(state.breakpoints[MediaBreakpoints[this.selectMediaBreakpoint]]); + } else { + this.useSelectSubject.next(false); + } this.cd.markForCheck(); } ); @@ -202,18 +228,21 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV } ngOnDestroy() { - if (this.toggleGroupResize$) { - this.toggleGroupResize$.disconnect(); - } + this.stopObservePagination(); super.ngOnDestroy(); } ngAfterViewInit() { - if (!this.disablePagination && !this.useSelectOnMdLg) { - this.toggleGroupResize$ = new ResizeObserver(() => { - this.updatePagination(); + if (!this.disablePagination) { + this.useSelect$.pipe(takeUntil(this._destroyed)).subscribe((useSelect) => { + if (useSelect) { + this.removePagination(); + } else { + setTimeout(() => { + this.startObservePagination(); + }, 0); + } }); - this.toggleGroupResize$.observe(this.toggleGroupContainer.nativeElement); } } @@ -243,6 +272,25 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV } } + private startObservePagination() { + this.toggleGroupResize$ = new ResizeObserver(() => { + this.updatePagination(); + }); + this.toggleGroupResize$.observe(this.toggleGroupContainer.nativeElement); + } + + private removePagination() { + this.stopObservePagination(); + this.showPaginationControls = false; + } + + private stopObservePagination() { + if (this.toggleGroupResize$) { + this.toggleGroupResize$.disconnect(); + this.toggleGroupResize$ = null; + } + } + private scrollHeader(direction: ScrollDirection) { const viewLength = this.toggleGroup.nativeElement.offsetWidth; // Move the scroll distance one-third the length of the tab list's viewport. diff --git a/ui-ngx/src/app/shared/components/toggle-select.component.html b/ui-ngx/src/app/shared/components/toggle-select.component.html index 819dc76ee4..c03e0cfcbf 100644 --- a/ui-ngx/src/app/shared/components/toggle-select.component.html +++ b/ui-ngx/src/app/shared/components/toggle-select.component.html @@ -21,6 +21,7 @@ [disabled]="disabled" [appearance]="appearance" [disablePagination]="disablePagination" + [selectMediaBreakpoint]="selectMediaBreakpoint" [options]="options" [value]="modelValue" (valueChange)="updateModel($event)"> diff --git a/ui-ngx/src/app/shared/components/toggle-select.component.ts b/ui-ngx/src/app/shared/components/toggle-select.component.ts index 3eee0cf841..c1541d1128 100644 --- a/ui-ngx/src/app/shared/components/toggle-select.component.ts +++ b/ui-ngx/src/app/shared/components/toggle-select.component.ts @@ -42,6 +42,9 @@ export class ToggleSelectComponent extends _ToggleBase implements ControlValueAc @coerceBoolean() disabled: boolean; + @Input() + selectMediaBreakpoint; + @Input() appearance: ToggleHeaderAppearance = 'stroked'; diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 4a4c018549..92feca1e8e 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -16,6 +16,15 @@ @import './scss/constants'; +@mixin form-row-column($breakpoint) { + @media #{$breakpoint} { + flex-direction: column; + align-items: stretch; + gap: 12px; + padding: 12px 12px 12px 16px; + } +} + .tb-default, .tb-dark { .tb-form-panel { box-shadow: 0 0 10px 6px rgba(11, 17, 51, 0.04); @@ -27,6 +36,10 @@ color: rgba(0, 0, 0, 0.87); letter-spacing: 0.15px; position: relative; + @media #{$mat-xs} { + padding: 12px; + gap: 8px; + } &.no-padding-bottom { padding-bottom: 0; } @@ -52,7 +65,6 @@ > .mat-expansion-panel { padding: 16px; .mat-expansion-panel-header { - height: 32px; .mat-slide { margin: 0; } @@ -66,6 +78,7 @@ overflow: visible; } > .mat-expansion-panel-header { + height: fit-content; user-select: none; font-weight: 500; font-size: 16px; @@ -98,6 +111,10 @@ flex-direction: column; gap: 16px; padding: 16px 0 0 !important; + @media #{$mat-xs} { + padding: 12px 0 0 !important; + gap: 8px; + } } } .tb-json-object-panel, .tb-css-content-panel { @@ -139,6 +156,14 @@ padding: 7px 7px 7px 16px; border: 1px solid rgba(0, 0, 0, 0.12); border-radius: 6px; + &.column { + &-xs { + @include form-row-column($mat-xs) + } + &-lt-md { + @include form-row-column($mat-lt-md) + } + } &.no-border { border: none; border-radius: 0; @@ -360,12 +385,14 @@ } .tb-form-table-row { - height: 38px; display: flex; flex-direction: row; - gap: 12px; - padding-left: 12px; - + gap: 8px; + padding-left: 8px; + @media #{$mat-gt-md} { + gap: 12px; + padding-left: 12px; + } &.tb-draggable { gap: 0; padding-left: 0; @@ -376,12 +403,7 @@ display: flex; flex-direction: row; button.mat-mdc-icon-button.mat-mdc-button-base { - padding: 7px; - width: 38px; - height: 38px; - .mat-icon { - color: rgba(0, 0, 0, 0.38); - } + color: rgba(0, 0, 0, 0.38); &.tb-hidden { visibility: hidden; } @@ -434,21 +456,18 @@ } } - button.mat-mdc-button-base.tb-box-button { + button.mat-mdc-button-base.tb-box-button, .tb-form-table-row-cell-buttons button.mat-mdc-icon-button.mat-mdc-button-base { width: 40px; min-width: 40px; height: 40px; - padding: 7px; + padding: 8px; + &.mat-mdc-outlined-button { + padding: 7px; + } .mat-mdc-button-touch-target { width: 40px; height: 40px; } - &:not(:disabled) { - color: rgba(0, 0, 0, 0.54); - } - &:disabled { - color: rgba(0, 0, 0, 0.12); - } > .mat-icon { width: 24px; height: 24px; @@ -456,4 +475,13 @@ margin: 0; } } + + button.mat-mdc-button-base.tb-box-button { + &:not(:disabled) { + color: rgba(0, 0, 0, 0.54); + } + &:disabled { + color: rgba(0, 0, 0, 0.12); + } + } } diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index 75fc0845cf..ec6060823d 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -625,9 +625,36 @@ mat-label { color: white; } } - .mat-mdc-select-value, .mat-mdc-select-arrow { + .mat-mdc-select-value, .mat-mdc-select-arrow, .mat-mdc-select-arrow:after { color: white; } + .mat-mdc-text-field-wrapper { + &.mdc-text-field--outlined { + &:not(.mdc-text-field--focused):not(.mdc-text-field--disabled):not(.mdc-text-field--invalid) { + &:not(:hover) { + .mdc-notched-outline { + .mdc-notched-outline__leading, .mdc-notched-outline__trailing { + border-color: white; + } + } + } + &:hover { + .mdc-notched-outline { + .mdc-notched-outline__leading, .mdc-notched-outline__trailing { + border-color: rgba(255, 255, 255, 0.87); + } + } + } + } + &:not(.mdc-text-field--disabled).mdc-text-field--focused { + .mdc-notched-outline { + .mdc-notched-outline__leading, .mdc-notched-outline__trailing { + border-color: rgba(255, 255, 255, 0.67); + } + } + } + } + } } .mat-toolbar.mat-mdc-table-toolbar { From 2056434bb70e582eeffaf1600dd334004044334a Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 2 Aug 2023 11:35:15 +0200 Subject: [PATCH 370/421] tests improvements --- .../state/DefaultDeviceStateServiceTest.java | 197 ++++++++++++++---- 1 file changed, 159 insertions(+), 38 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index 631a82f518..ca30f9e5ed 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -24,7 +24,6 @@ import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.server.cluster.TbClusterService; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceIdInfo; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; @@ -41,14 +40,13 @@ import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.sql.query.EntityQueryRepository; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.queue.discovery.PartitionService; -import org.thingsboard.server.service.partition.AbstractPartitionBasedService; +import org.thingsboard.server.queue.discovery.QueueKey; +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; -import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.UUID; import static org.hamcrest.CoreMatchers.is; @@ -78,13 +76,29 @@ public class DefaultDeviceStateServiceTest { @Mock EntityQueryRepository entityQueryRepository; + TenantId tenantId = new TenantId(UUID.fromString("00797a3b-7aeb-4b5b-b57a-c2a810d0f112")); DeviceId deviceId = DeviceId.fromString("00797a3b-7aeb-4b5b-b57a-c2a810d0f112"); + TopicPartitionInfo tpi; DefaultDeviceStateService service; + TelemetrySubscriptionService telemetrySubscriptionService; + @Before public void setUp() { service = spy(new DefaultDeviceStateService(deviceService, attributesService, tsService, clusterService, partitionService, entityQueryRepository, null, null, mock(NotificationRuleProcessor.class))); + telemetrySubscriptionService = Mockito.mock(TelemetrySubscriptionService.class); + ReflectionTestUtils.setField(service, "tsSubService", telemetrySubscriptionService); + ReflectionTestUtils.setField(service, "defaultStateCheckIntervalInSec", 60); + ReflectionTestUtils.setField(service, "defaultActivityStatsIntervalInSec", 60); + ReflectionTestUtils.setField(service, "initFetchPackSize", 10); + + tpi = TopicPartitionInfo.builder().myPartition(true).build(); + Mockito.when(partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId)).thenReturn(tpi); + Mockito.when(entityQueryRepository.findEntityDataByQueryInternal(Mockito.any())).thenReturn(new PageData<>()); + var deviceIdInfo = new DeviceIdInfo(tenantId.getId(), null, deviceId.getId()); + Mockito.when(deviceService.findDeviceIdInfos(Mockito.any())) + .thenReturn(new PageData<>(List.of(deviceIdInfo), 0, 1, false)); } @Test @@ -140,35 +154,62 @@ public class DefaultDeviceStateServiceTest { Assert.assertEquals(5000L, deviceStateData.getState().getInactivityTimeout()); } + private void initStateService(long timeout) throws InterruptedException { + service.stop(); + Mockito.reset(service, telemetrySubscriptionService); + ReflectionTestUtils.setField(service, "defaultInactivityTimeoutMs", timeout); + service.init(); + PartitionChangeEvent event = new PartitionChangeEvent(this, new QueueKey(ServiceType.TB_CORE), Collections.singleton(tpi)); + service.onApplicationEvent(event); + Thread.sleep(100); + } + @Test - public void givenIncreaseInactivityTimeoutAndThenStateIsActive() throws Exception { - TelemetrySubscriptionService telemetrySubscriptionService = Mockito.mock(TelemetrySubscriptionService.class); - ReflectionTestUtils.setField(service, "tsSubService", telemetrySubscriptionService); - ReflectionTestUtils.setField(service, "defaultStateCheckIntervalInSec", 60); - ReflectionTestUtils.setField(service, "defaultActivityStatsIntervalInSec", 60); - ReflectionTestUtils.setField(service, "defaultInactivityTimeoutMs", 1); - ReflectionTestUtils.setField(service, "initFetchPackSize", 10); + public void increaseInactivityForInactiveDeviceTest() throws Exception { + final long defaultTimeout = 1; + initStateService(defaultTimeout); + DeviceState deviceState = DeviceState.builder().build(); + DeviceStateData deviceStateData = DeviceStateData.builder() + .tenantId(tenantId) + .deviceId(deviceId) + .state(deviceState) + .metaData(new TbMsgMetaData()) + .build(); - Mockito.when(entityQueryRepository.findEntityDataByQueryInternal(Mockito.any())).thenReturn(new PageData<>()); + service.deviceStates.put(deviceId, deviceStateData); + service.getPartitionedEntities(tpi).add(deviceId); - service.init(); - var tenantId = new TenantId(UUID.randomUUID()); - var tpi = TopicPartitionInfo.builder().myPartition(true).build(); - Mockito.when(partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId)).thenReturn(tpi); + service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); + activityVerify(true); + Thread.sleep(defaultTimeout); + service.checkStates(); + activityVerify(false); - var deviceIdInfo = new DeviceIdInfo(tenantId.getId(), null, deviceId.getId()); + Mockito.reset(telemetrySubscriptionService); - Mockito.when(deviceService.findDeviceIdInfos(Mockito.any())) - .thenReturn(new PageData<>(List.of(deviceIdInfo), 0, 1, false)); + long increase = 100; + long newTimeout = System.currentTimeMillis() - deviceState.getLastActivityTime() + increase; + + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); + activityVerify(true); + Thread.sleep(increase); + service.checkStates(); + activityVerify(false); - Method method = AbstractPartitionBasedService.class.getDeclaredMethod("initStateFromDB", Set.class); - method.setAccessible(true); - method.invoke(service, Collections.singleton(tpi)); + Mockito.reset(telemetrySubscriptionService); - service.onAddedPartitions(Collections.singleton(tpi)); + service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); + activityVerify(true); + Thread.sleep(newTimeout + 5); + service.checkStates(); + activityVerify(false); + } + @Test + public void increaseInactivityForActiveDeviceTest() throws Exception { + final long defaultTimeout = 1000; + initStateService(defaultTimeout); DeviceState deviceState = DeviceState.builder().build(); - DeviceStateData deviceStateData = DeviceStateData.builder() .tenantId(tenantId) .deviceId(deviceId) @@ -177,44 +218,124 @@ public class DefaultDeviceStateServiceTest { .build(); service.deviceStates.put(deviceId, deviceStateData); - service.getPartitionedEntities(tpi).add(deviceId); service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); + activityVerify(true); - Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + Mockito.reset(telemetrySubscriptionService); - Thread.sleep(1); + long increase = 100; + long newTimeout = System.currentTimeMillis() - deviceState.getLastActivityTime() + increase; + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); + Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); + Thread.sleep(defaultTimeout + increase); service.checkStates(); - - Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(false), Mockito.any()); + activityVerify(false); Mockito.reset(telemetrySubscriptionService); - service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, System.currentTimeMillis() - deviceState.getLastActivityTime() + 1000); + service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); + activityVerify(true); + Thread.sleep(newTimeout); + service.checkStates(); + activityVerify(false); + } - Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + @Test + public void increaseSmallInactivityForInactiveDeviceTest() throws Exception { + final long defaultTimeout = 1; + initStateService(defaultTimeout); + DeviceState deviceState = DeviceState.builder().build(); + DeviceStateData deviceStateData = DeviceStateData.builder() + .tenantId(tenantId) + .deviceId(deviceId) + .state(deviceState) + .metaData(new TbMsgMetaData()) + .build(); - Thread.sleep(2000); + service.deviceStates.put(deviceId, deviceStateData); + service.getPartitionedEntities(tpi).add(deviceId); + service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); + activityVerify(true); + Thread.sleep(defaultTimeout); service.checkStates(); + activityVerify(false); - Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(false), Mockito.any()); + Mockito.reset(telemetrySubscriptionService); + long newTimeout = 1; + Thread.sleep(newTimeout); + Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); + } + + @Test + public void decreaseInactivityForActiveDeviceTest() throws Exception { + final long defaultTimeout = 1000; + initStateService(defaultTimeout); + DeviceState deviceState = DeviceState.builder().build(); + DeviceStateData deviceStateData = DeviceStateData.builder() + .tenantId(tenantId) + .deviceId(deviceId) + .state(deviceState) + .metaData(new TbMsgMetaData()) + .build(); + + service.deviceStates.put(deviceId, deviceStateData); + service.getPartitionedEntities(tpi).add(deviceId); + + service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); + activityVerify(true); + + Mockito.reset(telemetrySubscriptionService); + + Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); + + long newTimeout = 1; + + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); + activityVerify(false); Mockito.reset(telemetrySubscriptionService); - service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, 2000); + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, defaultTimeout); + activityVerify(true); + Thread.sleep(defaultTimeout); + service.checkStates(); + activityVerify(false); + } + + @Test + public void decreaseInactivityForInactiveDeviceTest() throws Exception { + final long defaultTimeout = 1000; + initStateService(defaultTimeout); + DeviceState deviceState = DeviceState.builder().build(); + DeviceStateData deviceStateData = DeviceStateData.builder() + .tenantId(tenantId) + .deviceId(deviceId) + .state(deviceState) + .metaData(new TbMsgMetaData()) + .build(); - Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + service.deviceStates.put(deviceId, deviceStateData); + service.getPartitionedEntities(tpi).add(deviceId); service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); + activityVerify(true); + Thread.sleep(defaultTimeout); + service.checkStates(); + activityVerify(false); + Mockito.reset(telemetrySubscriptionService); - Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(true), Mockito.any()); + long newTimeout = 1; - service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, 1); + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); + Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); + } - Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(false), Mockito.any()); + private void activityVerify(boolean isActive) { + Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(isActive), Mockito.any()); } } \ No newline at end of file From 12c8903ff559ed96ab741a0335e860cc3c62381f Mon Sep 17 00:00:00 2001 From: rusikv Date: Wed, 2 Aug 2023 12:48:19 +0300 Subject: [PATCH 371/421] Delete timeseries panel form is builded by FormBuilder and is now FormGroup, result of panel is now in result field --- .../attribute/attribute-table.component.html | 2 +- .../attribute/attribute-table.component.ts | 19 ++++---- .../delete-timeseries-panel.component.ts | 44 ++++++++++--------- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html index 788aeeaabc..10a5b03dba 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html @@ -85,7 +85,7 @@ 'attribute.selected-telemetry' : 'attribute.selected-attributes') | translate:{count: dataSource.selection.selected.length} }} - @@ -41,13 +41,13 @@ attribute.delete-timeseries.start-time - + attribute.delete-timeseries.ends-on - +
@@ -57,18 +57,18 @@
-
- - - -
- +
+ + + +
diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts index 04db1ee223..8adb9bcd5a 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts @@ -21,8 +21,8 @@ import { timeseriesDeleteStrategyTranslations } from '@shared/models/telemetry/telemetry.models'; import { MINUTE } from '@shared/models/time/time.models'; -import { AbstractControl, FormBuilder, FormGroup } from '@angular/forms'; -import { Subject, Subscription } from 'rxjs'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; export const DELETE_TIMESERIES_PANEL_DATA = new InjectionToken('DeleteTimeseriesPanelData'); @@ -47,10 +47,6 @@ export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { deleteTimeseriesFormGroup: FormGroup; - startDateTimeSubscription: Subscription; - - endDateTimeSubscription: Subscription; - result: DeleteTimeseriesPanelResult = null; strategiesTranslationsMap = timeseriesDeleteStrategyTranslations; @@ -76,14 +72,28 @@ export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { } this.deleteTimeseriesFormGroup = this.fb.group({ strategy: [TimeseriesDeleteStrategy.DELETE_ALL_DATA], - startDateTime: [new Date(today.getFullYear(), today.getMonth() - 1, today.getDate())], - endDateTime: [today], + startDateTime: [ + { value: new Date(today.getFullYear(), today.getMonth() - 1, today.getDate()), disabled: true }, + [Validators.required] + ], + endDateTime: [{ value: today, disabled: true }, [Validators.required]], rewriteLatest: [true] }) - this.startDateTimeSubscription = this.getStartDateTimeFormControl().valueChanges.pipe( + this.deleteTimeseriesFormGroup.get('strategy').valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(value => { + if (value === TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD) { + this.deleteTimeseriesFormGroup.get('startDateTime').enable({onlySelf: true, emitEvent: false}); + this.deleteTimeseriesFormGroup.get('endDateTime').enable({onlySelf: true, emitEvent: false}); + } else { + this.deleteTimeseriesFormGroup.get('startDateTime').disable({onlySelf: true, emitEvent: false}); + this.deleteTimeseriesFormGroup.get('endDateTime').disable({onlySelf: true, emitEvent: false}); + } + }) + this.deleteTimeseriesFormGroup.get('startDateTime').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe(value => this.onStartDateTimeChange(value)); - this.endDateTimeSubscription = this.getEndDateTimeFormControl().valueChanges.pipe( + this.deleteTimeseriesFormGroup.get('endDateTime').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe(value => this.onEndDateTimeChange(value)); } @@ -94,8 +104,12 @@ export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { } delete(): void { - this.result = this.deleteTimeseriesFormGroup.value; - this.overlayRef.dispose(); + if (this.deleteTimeseriesFormGroup.valid) { + this.result = this.deleteTimeseriesFormGroup.value; + this.overlayRef.dispose(); + } else { + this.deleteTimeseriesFormGroup.markAllAsTouched(); + } } cancel(): void { @@ -103,33 +117,22 @@ export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { } isPeriodStrategy(): boolean { - return this.getStrategyFormControl().value === TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD; + return this.deleteTimeseriesFormGroup.get('strategy').value === TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD; } isDeleteLatestStrategy(): boolean { - return this.getStrategyFormControl().value === TimeseriesDeleteStrategy.DELETE_LATEST_VALUE; - } - - getStrategyFormControl(): AbstractControl { - return this.deleteTimeseriesFormGroup.get('strategy'); - } - - getStartDateTimeFormControl(): AbstractControl { - return this.deleteTimeseriesFormGroup.get('startDateTime'); - } - - getEndDateTimeFormControl(): AbstractControl { - return this.deleteTimeseriesFormGroup.get('endDateTime'); + return this.deleteTimeseriesFormGroup.get('strategy').value === TimeseriesDeleteStrategy.DELETE_LATEST_VALUE; } onStartDateTimeChange(newStartDateTime: Date) { if (newStartDateTime) { const endDateTimeTs = this.deleteTimeseriesFormGroup.get('endDateTime').value.getTime(); - const startDateTimeControl = this.getStartDateTimeFormControl(); if (newStartDateTime.getTime() >= endDateTimeTs) { - startDateTimeControl.patchValue(new Date(endDateTimeTs - MINUTE), {onlySelf: true, emitEvent: false}); + this.deleteTimeseriesFormGroup.get('startDateTime') + .patchValue(new Date(endDateTimeTs - MINUTE), {onlySelf: true, emitEvent: false}); } else { - startDateTimeControl.patchValue(newStartDateTime, {onlySelf: true, emitEvent: false}); + this.deleteTimeseriesFormGroup.get('startDateTime') + .patchValue(newStartDateTime, {onlySelf: true, emitEvent: false}); } } } @@ -137,11 +140,12 @@ export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { onEndDateTimeChange(newEndDateTime: Date) { if (newEndDateTime) { const startDateTimeTs = this.deleteTimeseriesFormGroup.get('startDateTime').value.getTime(); - const endDateTimeControl = this.getEndDateTimeFormControl(); if (newEndDateTime.getTime() <= startDateTimeTs) { - endDateTimeControl.patchValue(new Date(startDateTimeTs + MINUTE), {onlySelf: true, emitEvent: false}); + this.deleteTimeseriesFormGroup.get('endDateTime') + .patchValue(new Date(startDateTimeTs + MINUTE), {onlySelf: true, emitEvent: false}); } else { - endDateTimeControl.patchValue(newEndDateTime, {onlySelf: true, emitEvent: false}); + this.deleteTimeseriesFormGroup.get('endDateTime') + .patchValue(newEndDateTime, {onlySelf: true, emitEvent: false}); } } } From 41b0949046ce2792b9f24dbc37520d9d43218193 Mon Sep 17 00:00:00 2001 From: rusikv Date: Wed, 2 Aug 2023 18:17:59 +0300 Subject: [PATCH 373/421] Change attribute dialog UntypedFormGroup to FormGroup, simplified if statement on add --- .../attribute/add-attribute-dialog.component.ts | 11 +++++------ .../attribute/attribute-table.component.html | 2 +- .../components/attribute/attribute-table.component.ts | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.ts b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.ts index 55746b7347..aadb96c142 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.ts @@ -19,7 +19,7 @@ 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 { FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms'; import { EntityId } from '@shared/models/id/entity-id'; import { Router } from '@angular/router'; import { DialogComponent } from '@app/shared/components/dialog.component'; @@ -41,7 +41,7 @@ export interface AddAttributeDialogData { export class AddAttributeDialogComponent extends DialogComponent implements OnInit, ErrorStateMatcher { - attributeFormGroup: UntypedFormGroup; + attributeFormGroup: FormGroup; submitted = false; @@ -53,7 +53,7 @@ export class AddAttributeDialogComponent extends DialogComponent, - public fb: UntypedFormBuilder) { + public fb: FormBuilder) { super(store, router, dialogRef); } @@ -66,7 +66,7 @@ export class AddAttributeDialogComponent extends DialogComponent
-
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss index e86f828111..a82f9c2f8b 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss @@ -45,8 +45,6 @@ } .preview { - width: 100%; - height: 100%; max-width: 100%; max-height: 100%; object-fit: contain; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html index 788c997740..356612564f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html @@ -45,7 +45,7 @@ {{ 'widgets.value-card.label' | translate }}
- +
- + @@ -75,10 +75,10 @@
widgets.value-card.value
- - + + -
widget-config.decimals-suffix
+
widget-config.decimals-suffix
@@ -87,11 +87,11 @@
-
+
{{ 'widgets.value-card.date' | translate }} -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html index 62f34f3d28..63f936195a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html @@ -28,7 +28,7 @@ (removed)="removeKey()">
-
+
{{ 'datakey.configuration' | translate }}
+
+ datakey.data-generation-func +
+ + +
datakey.aggregation @@ -80,72 +92,62 @@ {{ 'datakey.aggregation-type-hint-common' | translate }}
-
- datakey.delta-calculation - - - - - {{ 'datakey.enable-delta-calculation' | translate }} - - {{ 'datakey.enable-delta-calculation-hint' | translate }} - - - -
- - widgets.chart.time-for-comparison - - - {{ 'widgets.chart.time-for-comparison-previous-interval' | translate }} - - - {{ 'widgets.chart.time-for-comparison-days' | translate }} - - - {{ 'widgets.chart.time-for-comparison-weeks' | translate }} - - - {{ 'widgets.chart.time-for-comparison-months' | translate }} - - - {{ 'widgets.chart.time-for-comparison-years' | translate }} - - - {{ 'widgets.chart.time-for-comparison-custom-interval' | translate }} - - - - - widgets.chart.custom-interval-value - - - - datakey.delta-calculation-result - - - {{ comparisonResultTypeTranslations.get(comparisonResultTypes[comparisonResultType]) | translate }} - - - -
-
-
-
-
- datakey.data-generation-func -
- - -
+
+
datakey.delta-calculation
+ + + + + {{ 'datakey.enable-delta-calculation' | translate }} + + {{ 'datakey.enable-delta-calculation-hint' | translate }} + + + +
+ + widgets.chart.time-for-comparison + + + {{ 'widgets.chart.time-for-comparison-previous-interval' | translate }} + + + {{ 'widgets.chart.time-for-comparison-days' | translate }} + + + {{ 'widgets.chart.time-for-comparison-weeks' | translate }} + + + {{ 'widgets.chart.time-for-comparison-months' | translate }} + + + {{ 'widgets.chart.time-for-comparison-years' | translate }} + + + {{ 'widgets.chart.time-for-comparison-custom-interval' | translate }} + + + + + widgets.chart.custom-interval-value + + + + datakey.delta-calculation-result + + + {{ comparisonResultTypeTranslations.get(comparisonResultTypes[comparisonResultType]) | translate }} + + + +
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html index e024af20ee..3226ffed5e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.html @@ -47,7 +47,7 @@ drag_indicator
-
+
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss index 1664dafb7f..574d1df38e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss @@ -70,6 +70,9 @@ text-overflow: ellipsis; white-space: nowrap; } + &.tb-chip-icon { + min-width: 24px; + } .mat-icon.tb-datakey-icon { margin-right: 4px; margin-left: 4px; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.html b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.html index 2e4a984858..0ee6a7c508 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.html @@ -44,29 +44,27 @@ [cdkDropListDisabled]="dragDisabled" formArrayName="datasources"> -
-
+
+
{{$index + 1}}
-
-
- +
+
+ -
-
- - + + {{ 'widgets.table.use-cell-style-function' | translate }} @@ -86,8 +86,8 @@
- - + + {{ 'widgets.table.use-cell-content-function' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html index 4ec8f31be6..e304def2c8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html @@ -94,7 +94,7 @@ {{ 'widgets.table.display-pagination' | translate }} -
+
widgets.table.default-page-size
@@ -104,8 +104,8 @@
widgets.table.rows
- - + + {{ 'widgets.table.use-row-style-function' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html index 02d51ee325..faad357026 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html @@ -62,8 +62,8 @@
- - + + {{ 'widgets.table.use-cell-style-function' | translate }} @@ -86,8 +86,8 @@
- - + + {{ 'widgets.table.use-cell-content-function' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html index f8867b9f6a..c9c57d8843 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html @@ -41,7 +41,7 @@
widgets.table.columns
-
+
{{ 'widgets.table.display-entity-name' | translate }} @@ -49,7 +49,7 @@
-
+
{{ 'widgets.table.display-entity-label' | translate }} @@ -91,7 +91,7 @@ {{ 'widgets.table.display-pagination' | translate }} -
+
widgets.table.default-page-size
@@ -101,8 +101,8 @@
widgets.table.rows
- - + + {{ 'widgets.table.use-row-style-function' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html index 6c79eed622..165f4eb0f7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-key-settings.component.html @@ -50,8 +50,8 @@
- - + + {{ 'widgets.table.use-cell-style-function' | translate }} @@ -74,8 +74,8 @@
- - + + {{ 'widgets.table.use-cell-content-function' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html index 97cbe28ae9..fd34b66af6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-latest-key-settings.component.html @@ -59,8 +59,8 @@
- - + + {{ 'widgets.table.use-cell-style-function' | translate }} @@ -83,8 +83,8 @@
- - + + {{ 'widgets.table.use-cell-content-function' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html index 170d460f92..d70ae9964b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/timeseries-table-widget-settings.component.html @@ -59,7 +59,7 @@ {{ 'widgets.table.display-pagination' | translate }} -
+
widgets.table.default-page-size
@@ -78,8 +78,8 @@ {{ 'widgets.table.hide-empty-lines' | translate }} - - + + {{ 'widgets.table.use-row-style-function' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html index 423c727a8d..71a9b60118 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html @@ -44,8 +44,8 @@ {{ 'widgets.value-card.icon' | translate }} -
- +
+ @@ -67,11 +67,11 @@
-
+
{{ 'widgets.value-card.date' | translate }} -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html index 96ff4d8559..a424b61606 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html @@ -32,8 +32,8 @@
- - + + {{ 'widgets.chart.show-line' | translate }} @@ -65,8 +65,8 @@
- - + + {{ 'widgets.chart.show-points' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html index 6f08b5f3f7..be2ae39255 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.html @@ -17,7 +17,7 @@ -->
- +
{{ thresholdText() }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss index 150d516894..81f5d17bc6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-threshold.component.scss @@ -29,6 +29,9 @@ display: flex; flex-direction: row; align-items: stretch; + .mat-content { + overflow: hidden; + } .tb-threshold-header { flex: 1; display: flex; @@ -36,6 +39,7 @@ gap: 16px; align-items: center; padding-left: 16px; + overflow: hidden; .mat-divider-vertical { height: 100%; } @@ -47,6 +51,9 @@ font-weight: 400; line-height: 16px; letter-spacing: 0.15px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } .mat-expansion-indicator { margin-right: 22px; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html index 5dd7eaa2dc..4ea648c3b4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.html @@ -77,8 +77,8 @@
widget-config.legend
- - + + {{ 'widget-config.legend' | translate }} @@ -119,8 +119,8 @@
widgets.chart.ticks
- - + + {{ 'widgets.chart.ticks' | translate }} @@ -171,8 +171,8 @@
widgets.chart.ticks
- - + + {{ 'widgets.chart.ticks' | translate }} @@ -234,8 +234,8 @@
widgets.chart.tooltip
- - + + {{ 'widgets.chart.tooltip' | translate }} @@ -274,8 +274,8 @@
widgets.chart.comparison-settings
- - + + {{ 'widgets.chart.enable-comparison' | translate }} @@ -350,8 +350,8 @@
widgets.chart.custom-legend-settings
- - + + {{ 'widgets.chart.enable-custom-legend' | translate }} 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 ca5d4bc8b9..42c4472cca 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 @@ -20,7 +20,7 @@
widgets.background.background
- + {{ backgroundTypeTranslationsMap.get(type) | translate }} 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 51d2ddec1b..465d3383e2 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 @@ -94,7 +94,7 @@ export class BackgroundSettingsPanelComponent extends PageComponent implements O } applyColorSettings() { - const backgroundSettings = this.backgroundSettingsFormGroup.value; + const backgroundSettings = this.backgroundSettingsFormGroup.getRawValue(); this.backgroundSettingsApplied.emit(backgroundSettings); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html index eb2bbd6711..52bd5907bd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/image-cards-select.component.html @@ -17,7 +17,7 @@ -->
- +
{{ label }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html index 3cc771e94f..726aed776e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/value-source.component.html @@ -17,7 +17,7 @@ -->
- + {{ 'widgets.value-source.predefined-value' | translate }} @@ -32,7 +32,7 @@
-
+
widgets.value-source.source-entity-alias
-
+
widgets.value-source.source-entity-attribute
-
-
-
-
{{ (disabled ? 'dashboard.empty-image' : 'dashboard.no-image') | translate }}
- -
-
- -
-
-
-
-
- cloud_upload - image-input.drop-image-or - - +
+
+
{{ 'dashboard.empty-image' | translate }}
+
-
-
-
-
+
+
+ cloud_upload +
+ image-input.drag-and-drop +
+ image-input.or + + +
+
+
+
+ +
dashboard.maximum-upload-file-size
diff --git a/ui-ngx/src/app/shared/components/image-input.component.scss b/ui-ngx/src/app/shared/components/image-input.component.scss index a776bc8cd7..b7d05bef8d 100644 --- a/ui-ngx/src/app/shared/components/image-input.component.scss +++ b/ui-ngx/src/app/shared/components/image-input.component.scss @@ -15,9 +15,8 @@ */ @import "../../../scss/constants"; -$containerHeight: 120px !default; -$previewContainerWidth: 168px !default; -$previewSize: 96px !default; +$containerHeight: 96px !default; +$previewSize: 78px !default; :host { @@ -31,30 +30,39 @@ $previewSize: 96px !default; } .tb-image-select-container { - position: relative; width: 100%; height: $containerHeight; + display: flex; + gap: 12px; + align-items: center; } .image-container { - position: relative; - float: left; - height: $containerHeight; - padding: 12px; - margin-right: 8px; - background: rgba(0, 0, 0, 0.03); + background: #F3F6FA; border-radius: 4px; + border: 1px solid rgba(0, 0, 0, 0.05); + padding: 8px 12px 8px 8px; + display: flex; + align-items: center; + gap: 12px; + &.disabled { + padding: 8px; + } } - .image-content-container { - background: #FFFFFF; - border: 1px solid rgba(0, 0, 0, 0.2); - border-radius: 4px; - padding-left: 8px; + .tb-image-preview-container { + width: $previewSize; height: $previewSize; - &.no-padding { - padding-left: 0px; - } + border: 1px solid rgba(0, 0, 0, 0.12); + background: #fff; + display: flex; + align-items: center; + justify-content: center; + } + + .tb-image-preview-text { + font-size: 14px; + text-align: center; } .tb-image-preview { @@ -64,57 +72,18 @@ $previewSize: 96px !default; max-height: $previewSize - 2px; } - .tb-image-preview-container { - position: relative; - float: left; - width: $previewSize; - height: $previewSize; - margin-top: -1px; - margin-bottom: -1px; - border: 1px solid rgba(0, 0, 0, 0.54); - - div { - width: 100%; - font-size: 18px; - text-align: center; - } - - div, - .tb-image-preview { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } - } - - .tb-image-clear-container { - position: relative; - float: right; - height: $previewSize; - display: flex; - align-items: center; - &.full-height { - height: $containerHeight; - } - } - .file-input { display: none; } .tb-flow-drop { - position: relative; - height: $containerHeight; + height: 100%; + flex: 1; overflow: hidden; border: 2px dashed rgba(0, 0, 0, 0.2); border-radius: 4px; box-sizing: border-box; - &.float-left { - float: left; - } - .upload-label { width: 100%; height: 100%; @@ -123,11 +92,29 @@ $previewSize: 96px !default; flex-direction: row; justify-content: center; align-items: center; - font-size: 16px; - color: rgba(0, 0, 0, 0.54); - text-align: center; + gap: 8px; .mat-icon { - margin-right: 17px; + color: rgba(0,0,0,0.12); + } + .upload-text-area { + display: flex; + flex-direction: column; + align-items: center; + font-size: 16px; + line-height: 24px; + color: rgba(0, 0, 0, 0.54); + text-align: center; + .hide-xs { + @media #{$mat-xs} { + display: none; + } + } + } + .upload-button-area { + display: flex; + justify-content: center; + align-items: flex-start; + gap: 6px; } } } @@ -138,13 +125,14 @@ $previewSize: 96px !default; } :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; } } } diff --git a/ui-ngx/src/app/shared/components/image-input.component.ts b/ui-ngx/src/app/shared/components/image-input.component.ts index 026b64a413..f5b80aa1e0 100644 --- a/ui-ngx/src/app/shared/components/image-input.component.ts +++ b/ui-ngx/src/app/shared/components/image-input.component.ts @@ -65,9 +65,6 @@ export class ImageInputComponent extends PageComponent implements AfterViewInit, @Input() disabled: boolean; - @Input() - showClearButton = true; - @Input() showPreview = true; diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.scss b/ui-ngx/src/app/shared/components/toggle-header.component.scss index 7a41032961..ac24f7bf29 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.scss +++ b/ui-ngx/src/app/shared/components/toggle-header.component.scss @@ -29,10 +29,12 @@ display: block; } } - .tb-toggle-container { + .tb-toggle-container, .tb-toggle-header-select { display: inline-grid; grid-column: 2; overflow: hidden; + } + .tb-toggle-container { &.tb-disable-pagination { overflow: visible; } diff --git a/ui-ngx/src/app/shared/components/toggle-header.component.ts b/ui-ngx/src/app/shared/components/toggle-header.component.ts index a7bddfc7b4..5781f9fac9 100644 --- a/ui-ngx/src/app/shared/components/toggle-header.component.ts +++ b/ui-ngx/src/app/shared/components/toggle-header.component.ts @@ -16,7 +16,7 @@ import { AfterContentChecked, - AfterContentInit, + AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, Component, @@ -117,7 +117,8 @@ export abstract class _ToggleBase extends PageComponent implements AfterContentI templateUrl: './toggle-header.component.html', styleUrls: ['./toggle-header.component.scss'] }) -export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterViewInit, AfterContentInit, AfterContentChecked, OnDestroy { +export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterViewInit, AfterContentInit, + AfterContentChecked, AfterViewChecked, OnDestroy { @ViewChild('toggleGroup', {static: false}) toggleGroup: ElementRef; @@ -130,6 +131,7 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV @HostBinding('class.tb-toggle-header-pagination-controls-enabled') private showPaginationControls = false; + private _showPaginationControlsChanged = false; private toggleGroupResize$: ResizeObserver; @@ -254,6 +256,14 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV } } + ngAfterViewChecked() { + if (this._showPaginationControlsChanged) { + this.scrollToToggleOptionValue(); + this._showPaginationControlsChanged = false; + this.cd.markForCheck(); + } + } + trackByHeaderOption(index: number, option: ToggleHeaderOption){ return option.value; } @@ -301,10 +311,13 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV private scrollToToggleOptionValue() { if (this.buttonToggleGroup && this.buttonToggleGroup.selected) { const selectedToggleButton = this.buttonToggleGroup.selected as MatButtonToggle; + const index = this.options.findIndex(o => o.value === selectedToggleButton.value); + const isLast = index === this.options.length - 1; + const isFirst = index === 0; const viewLength = this.toggleGroupContainer.nativeElement.offsetWidth; const {offsetLeft, offsetWidth} = (selectedToggleButton._buttonElement.nativeElement.offsetParent as HTMLElement); - const labelBeforePos = offsetLeft; // this.toggleGroup.nativeElement.offsetWidth - offsetLeft; - const labelAfterPos = labelBeforePos + offsetWidth; + const labelBeforePos = isFirst ? 0 : offsetLeft; + const labelAfterPos = isLast ? this.toggleGroup.nativeElement.scrollWidth : labelBeforePos + offsetWidth; const beforeVisiblePos = this.scrollDistance; const afterVisiblePos = this.scrollDistance + viewLength; if (labelBeforePos < beforeVisiblePos) { @@ -331,9 +344,7 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV if (!isEnabled) { this.scrollDistance = 0; } else { - setTimeout(() => { - this.scrollToToggleOptionValue(); - }, 0); + this._showPaginationControlsChanged = true; } this.cd.markForCheck(); this.showPaginationControls = isEnabled; @@ -373,11 +384,13 @@ export class ToggleHeaderComponent extends _ToggleBase implements OnInit, AfterV } private updateToggleHeaderScrollPosition() { - const scrollDistance = this.scrollDistance; - const translateX = -scrollDistance; - this.toggleGroup.nativeElement.style.transform = `translateX(${Math.round(translateX)}px)`; - if (this.platform.TRIDENT || this.platform.EDGE) { - this.toggleGroupContainer.nativeElement.scrollLeft = 0; + if (this.toggleGroupContainer) { + const scrollDistance = this.scrollDistance; + const translateX = -scrollDistance; + this.toggleGroup.nativeElement.style.transform = `translateX(${Math.round(translateX)}px)`; + if (this.platform.TRIDENT || this.platform.EDGE) { + this.toggleGroupContainer.nativeElement.scrollLeft = 0; + } } } } diff --git a/ui-ngx/src/app/shared/components/unit-input.component.html b/ui-ngx/src/app/shared/components/unit-input.component.html index 0ae14b8ba9..c15b232444 100644 --- a/ui-ngx/src/app/shared/components/unit-input.component.html +++ b/ui-ngx/src/app/shared/components/unit-input.component.html @@ -15,7 +15,7 @@ limitations under the License. --> - + Date: Thu, 3 Aug 2023 20:20:17 +0300 Subject: [PATCH 380/421] reverted refactoring with "return" use in the if statement & added @Override where required in DefaultTbContext & reverted changes to TbAbstractExternalNode --- .../actors/ruleChain/DefaultTbContext.java | 71 ++++++++++++++----- .../rule/engine/api/TbContext.java | 4 +- .../external/TbAbstractExternalNode.java | 12 +++- .../engine/profile/TbDeviceProfileNode.java | 48 ++++++------- 4 files changed, 89 insertions(+), 46 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index dc03a97254..f5a0cedf08 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -371,10 +371,12 @@ class DefaultTbContext implements TbContext { return TbMsg.transformMsgOriginator(origMsg, originator); } + @Override public TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId) { return entityActionMsg(customer, customer.getId(), ruleNodeId, ENTITY_CREATED); } + @Override public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) { DeviceProfile deviceProfile = null; if (device.getDeviceProfileId() != null) { @@ -383,6 +385,7 @@ class DefaultTbContext implements TbContext { return entityActionMsg(device, device.getId(), ruleNodeId, ENTITY_CREATED, deviceProfile); } + @Override public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) { AssetProfile assetProfile = null; if (asset.getAssetProfileId() != null) { @@ -391,18 +394,33 @@ class DefaultTbContext implements TbContext { return entityActionMsg(asset, asset.getId(), ruleNodeId, ENTITY_CREATED, assetProfile); } + @Override + public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action) { + EntityId originator = alarm.getOriginator(); + HasRuleEngineProfile profile = getRuleEngineProfile(originator); + return entityActionMsg(alarm, originator, ruleNodeId, action, profile); + } + + @Override public TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, TbMsgType actionMsgType) { + EntityId originator = alarm.getOriginator(); + HasRuleEngineProfile profile = getRuleEngineProfile(originator); + return entityActionMsg(alarm, originator, ruleNodeId, actionMsgType, profile); + } + + private HasRuleEngineProfile getRuleEngineProfile(EntityId originator) { HasRuleEngineProfile profile = null; - if (EntityType.DEVICE.equals(alarm.getOriginator().getEntityType())) { - DeviceId deviceId = new DeviceId(alarm.getOriginator().getId()); + if (EntityType.DEVICE.equals(originator.getEntityType())) { + DeviceId deviceId = new DeviceId(originator.getId()); profile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId); - } else if (EntityType.ASSET.equals(alarm.getOriginator().getEntityType())) { - AssetId assetId = new AssetId(alarm.getOriginator().getId()); + } else if (EntityType.ASSET.equals(originator.getEntityType())) { + AssetId assetId = new AssetId(originator.getId()); profile = mainCtx.getAssetProfileCache().get(getTenantId(), assetId); } - return entityActionMsg(alarm, alarm.getOriginator(), ruleNodeId, actionMsgType, profile); + return profile; } + @Override public TbMsg attributesUpdatedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List attributes) { ObjectNode entityNode = JacksonUtil.newObjectNode(); if (attributes != null) { @@ -411,6 +429,7 @@ class DefaultTbContext implements TbContext { return attributesActionMsg(originator, ruleNodeId, scope, ATTRIBUTES_UPDATED, JacksonUtil.toString(entityNode)); } + @Override public TbMsg attributesDeletedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List keys) { ObjectNode entityNode = JacksonUtil.newObjectNode(); ArrayNode attrsArrayNode = entityNode.putArray("attributes"); @@ -423,14 +442,7 @@ class DefaultTbContext implements TbContext { private TbMsg attributesActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, TbMsgType actionMsgType, String msgData) { TbMsgMetaData tbMsgMetaData = getActionMetaData(ruleNodeId); tbMsgMetaData.putValue("scope", scope); - HasRuleEngineProfile profile = null; - if (EntityType.DEVICE.equals(originator.getEntityType())) { - DeviceId deviceId = new DeviceId(originator.getId()); - profile = mainCtx.getDeviceProfileCache().get(getTenantId(), deviceId); - } else if (EntityType.ASSET.equals(originator.getEntityType())) { - AssetId assetId = new AssetId(originator.getId()); - profile = mainCtx.getAssetProfileCache().get(getTenantId(), assetId); - } + HasRuleEngineProfile profile = getRuleEngineProfile(originator); return entityActionMsg(originator, tbMsgMetaData, msgData, actionMsgType, profile); } @@ -443,6 +455,26 @@ class DefaultTbContext implements TbContext { return entityActionMsg(entity, id, ruleNodeId, actionMsgType, null); } + @Deprecated(since = "3.5.2", forRemoval = true) + public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action, K profile) { + try { + return entityActionMsg(id, getActionMetaData(ruleNodeId), JacksonUtil.toString(JacksonUtil.valueToTree(entity)), action, profile); + } catch (IllegalArgumentException e) { + throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " " + action + " msg: " + e); + } + } + + @Deprecated(since = "3.5.2", forRemoval = true) + private TbMsg entityActionMsg(I id, TbMsgMetaData msgMetaData, String msgData, String action, K profile) { + String defaultQueueName = null; + RuleChainId defaultRuleChainId = null; + if (profile != null) { + defaultQueueName = profile.getDefaultQueueName(); + defaultRuleChainId = profile.getDefaultRuleChainId(); + } + return TbMsg.newMsg(defaultQueueName, action, id, msgMetaData, msgData, defaultRuleChainId, null); + } + public TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, TbMsgType actionMsgType, K profile) { try { return entityActionMsg(id, getActionMetaData(ruleNodeId), JacksonUtil.toString(JacksonUtil.valueToTree(entity)), actionMsgType, profile); @@ -878,10 +910,17 @@ class DefaultTbContext implements TbContext { } private static String getFailureMessage(Throwable th) { - if (th == null) { - return null; + String failureMessage; + if (th != null) { + if (!StringUtils.isEmpty(th.getMessage())) { + failureMessage = th.getMessage(); + } else { + failureMessage = th.getClass().getSimpleName(); + } + } else { + failureMessage = null; } - return StringUtils.isNotEmpty(th.getMessage()) ? th.getMessage() : th.getClass().getSimpleName(); + return failureMessage; } private class SimpleTbQueueCallback implements TbQueueCallback { diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index be35e74321..fa47faf8aa 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -225,7 +225,9 @@ public interface TbContext { TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId); - // TODO: Does this changes the message? + @Deprecated(since = "3.5.2", forRemoval = true) + TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, String action); + TbMsg alarmActionMsg(Alarm alarm, RuleNodeId ruleNodeId, TbMsgType actionMsgType); TbMsg attributesUpdatedActionMsg(EntityId originator, RuleNodeId ruleNodeId, String scope, List attributes); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java index d0c3e28ec1..1fb000d709 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/external/TbAbstractExternalNode.java @@ -38,9 +38,17 @@ public abstract class TbAbstractExternalNode implements TbNode { protected void tellFailure(TbContext ctx, TbMsg tbMsg, Throwable t) { if (forceAck) { - ctx.enqueueForTellFailure(tbMsg.copyWithNewCtx(), t); + if (t == null) { + ctx.enqueueForTellNext(tbMsg.copyWithNewCtx(), TbNodeConnectionType.FAILURE); + } else { + ctx.enqueueForTellFailure(tbMsg.copyWithNewCtx(), t); + } } else { - ctx.tellFailure(tbMsg, t); + if (t == null) { + ctx.tellNext(tbMsg, TbNodeConnectionType.FAILURE); + } else { + ctx.tellFailure(tbMsg, t); + } } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index 058a70fdea..0dccabff80 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -111,13 +111,9 @@ public class TbDeviceProfileNode implements TbNode { if (msg.checkType(TbMsgType.DEVICE_PROFILE_PERIODIC_SELF_MSG)) { scheduleAlarmHarvesting(ctx, msg); harvestAlarms(ctx, System.currentTimeMillis()); - return; - } - if (msg.checkType(TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG)) { + } else if (msg.checkType(TbMsgType.DEVICE_PROFILE_UPDATE_SELF_MSG)) { updateProfile(ctx, new DeviceProfileId(UUID.fromString(msg.getData()))); - return; - } - if (msg.checkType(TbMsgType.DEVICE_UPDATE_SELF_MSG)) { + } else if (msg.checkType(TbMsgType.DEVICE_UPDATE_SELF_MSG)) { JsonNode data = JacksonUtil.toJsonNode(msg.getData()); DeviceId deviceId = new DeviceId(UUID.fromString(data.get("deviceId").asText())); if (data.has("profileId")) { @@ -125,30 +121,28 @@ public class TbDeviceProfileNode implements TbNode { } else { removeDeviceState(deviceId); } - return; - } - if (EntityType.DEVICE.equals(originatorType)) { - DeviceId deviceId = new DeviceId(msg.getOriginator().getId()); - if (msg.checkType(TbMsgType.ENTITY_UPDATED)) { - invalidateDeviceProfileCache(deviceId, msg.getData()); - ctx.tellSuccess(msg); - return; - } - if (msg.checkType(TbMsgType.ENTITY_DELETED)) { - removeDeviceState(deviceId); - ctx.tellSuccess(msg); - return; - } - DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId, null, false); - if (deviceState == null) { - log.info("Device was not found! Most probably device [" + deviceId + "] has been removed from the database. Acknowledging msg."); - ctx.ack(msg); + } else { + if (EntityType.DEVICE.equals(originatorType)) { + DeviceId deviceId = new DeviceId(msg.getOriginator().getId()); + if (msg.checkType(TbMsgType.ENTITY_UPDATED)) { + invalidateDeviceProfileCache(deviceId, msg.getData()); + ctx.tellSuccess(msg); + } else if (msg.checkType(TbMsgType.ENTITY_DELETED)) { + removeDeviceState(deviceId); + ctx.tellSuccess(msg); + } else { + DeviceState deviceState = getOrCreateDeviceState(ctx, deviceId, null, false); + if (deviceState != null) { + deviceState.process(ctx, msg); + } else { + log.info("Device was not found! Most probably device [" + deviceId + "] has been removed from the database. Acknowledging msg."); + ctx.ack(msg); + } + } } else { - deviceState.process(ctx, msg); + ctx.tellSuccess(msg); } - return; } - ctx.tellSuccess(msg); } @Override From ad847ff40c9f07916190f9eebbee95206b18fc01 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 3 Aug 2023 20:22:58 +0300 Subject: [PATCH 381/421] changed checkType and checkTypeOneOf to isTypeOf and isTypeOneOf --- .../thingsboard/server/common/msg/TbMsg.java | 6 +++--- .../TbCopyAttributesToEntityViewNode.java | 6 +++--- .../rule/engine/action/TbMsgCountNode.java | 2 +- .../rule/engine/debug/TbMsgGeneratorNode.java | 2 +- .../deduplication/TbMsgDeduplicationNode.java | 2 +- .../rule/engine/delay/TbMsgDelayNode.java | 2 +- .../engine/edge/AbstractTbMsgPushNode.java | 14 +++++++------- .../rule/engine/mail/TbSendEmailNode.java | 2 +- .../engine/metadata/CalculateDeltaNode.java | 2 +- .../rule/engine/profile/DeviceState.java | 18 +++++++++--------- .../engine/profile/TbDeviceProfileNode.java | 10 +++++----- .../rule/engine/rpc/TbSendRPCRequestNode.java | 2 +- .../engine/telemetry/TbMsgAttributesNode.java | 2 +- .../engine/telemetry/TbMsgTimeseriesNode.java | 2 +- 14 files changed, 36 insertions(+), 36 deletions(-) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index bec094b804..a987a4a253 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -468,13 +468,13 @@ public final class TbMsg implements Serializable { return ts; } - public boolean checkType(TbMsgType tbMsgType) { + public boolean isTypeOf(TbMsgType tbMsgType) { return tbMsgType != null && tbMsgType.name().equals(this.type); } - public boolean checkTypeOneOf(TbMsgType... types) { + public boolean isTypeOneOf(TbMsgType... types) { for (TbMsgType type : types) { - if (checkType(type)) { + if (isTypeOf(type)) { return true; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index 8cd833ce66..c103dd4006 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -75,11 +75,11 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (msg.checkTypeOneOf(ATTRIBUTES_UPDATED, ATTRIBUTES_DELETED, + if (msg.isTypeOneOf(ATTRIBUTES_UPDATED, ATTRIBUTES_DELETED, ACTIVITY_EVENT, INACTIVITY_EVENT, POST_ATTRIBUTES_REQUEST)) { if (!msg.getMetaData().getData().isEmpty()) { long now = System.currentTimeMillis(); - String scope = msg.checkType(POST_ATTRIBUTES_REQUEST) ? + String scope = msg.isTypeOf(POST_ATTRIBUTES_REQUEST) ? DataConstants.CLIENT_SCOPE : msg.getMetaData().getValue(DataConstants.SCOPE); ListenableFuture> entityViewsFuture = @@ -91,7 +91,7 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { long startTime = entityView.getStartTimeMs(); long endTime = entityView.getEndTimeMs(); if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) { - if (msg.checkType(ATTRIBUTES_DELETED)) { + if (msg.isTypeOf(ATTRIBUTES_DELETED)) { List attributes = new ArrayList<>(); for (JsonElement element : JsonParser.parseString(msg.getData()).getAsJsonObject().get("attributes").getAsJsonArray()) { if (element.isJsonPrimitive()) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java index e43caf6bb8..021123a308 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java @@ -65,7 +65,7 @@ public class TbMsgCountNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (msg.checkType(TbMsgType.MSG_COUNT_SELF_MSG) && msg.getId().equals(nextTickId)) { + if (msg.isTypeOf(TbMsgType.MSG_COUNT_SELF_MSG) && msg.getId().equals(nextTickId)) { JsonObject telemetryJson = new JsonObject(); telemetryJson.addProperty(this.telemetryPrefix + "_" + ctx.getServiceId(), messagesProcessed.longValue()); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java index cd32a44ea0..b31c98bc0f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java @@ -107,7 +107,7 @@ public class TbMsgGeneratorNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { log.trace("onMsg, config {}, msg {}", config, msg); - if (initialized.get() && msg.checkType(TbMsgType.GENERATOR_NODE_SELF_MSG) && msg.getId().equals(nextTickId)) { + if (initialized.get() && msg.isTypeOf(TbMsgType.GENERATOR_NODE_SELF_MSG) && msg.getId().equals(nextTickId)) { TbStopWatch sw = TbStopWatch.create(); withCallback(generate(ctx, msg), m -> { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java index 1c0803770b..81bb3d6772 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/deduplication/TbMsgDeduplicationNode.java @@ -80,7 +80,7 @@ public class TbMsgDeduplicationNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { - if (msg.checkType(TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG)) { + if (msg.isTypeOf(TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG)) { processDeduplication(ctx, msg.getOriginator()); } else { processOnRegularMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java index d17415c1a6..5414cc2bbe 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java @@ -61,7 +61,7 @@ public class TbMsgDelayNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - if (msg.checkType(TbMsgType.DELAY_TIMEOUT_SELF_MSG)) { + if (msg.isTypeOf(TbMsgType.DELAY_TIMEOUT_SELF_MSG)) { TbMsg pendingMsg = pendingMsgs.remove(UUID.fromString(msg.getData())); if (pendingMsg != null) { ctx.enqueueForTellNext( diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java index 3472ea011b..7888922dc6 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/AbstractTbMsgPushNode.java @@ -82,7 +82,7 @@ public abstract class AbstractTbMsgPushNode Date: Fri, 4 Aug 2023 13:03:02 +0300 Subject: [PATCH 382/421] UI: Aligned phone input flags container by input field --- ui-ngx/src/app/shared/components/phone-input.component.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/shared/components/phone-input.component.scss b/ui-ngx/src/app/shared/components/phone-input.component.scss index eb8d27646f..1ba5eabf3a 100644 --- a/ui-ngx/src/app/shared/components/phone-input.component.scss +++ b/ui-ngx/src/app/shared/components/phone-input.component.scss @@ -24,7 +24,6 @@ .phone-input-container { display: flex; - align-items: center; .phone-input { width: 100%; @@ -32,10 +31,11 @@ } .flags-select-container { - display: inline-block; + display: flex; + align-items: center; position: relative; width: 50px; - height: 100%; + height: 56px; margin-right: 5px; } From a85f9fbabcf68da5319598174825c0d4d38fee97 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 4 Aug 2023 17:49:52 +0300 Subject: [PATCH 383/421] UI: Refactoring delete telemetry --- ui-ngx/src/app/core/http/attribute.service.ts | 12 +++- .../attribute/attribute-table.component.html | 2 +- .../attribute/attribute-table.component.ts | 65 +++++++++-------- .../delete-timeseries-panel.component.html | 72 +++++++++---------- .../delete-timeseries-panel.component.scss | 28 ++++++-- .../delete-timeseries-panel.component.ts | 25 ++++--- 6 files changed, 114 insertions(+), 90 deletions(-) diff --git a/ui-ngx/src/app/core/http/attribute.service.ts b/ui-ngx/src/app/core/http/attribute.service.ts index c810a0af22..9022a47eef 100644 --- a/ui-ngx/src/app/core/http/attribute.service.ts +++ b/ui-ngx/src/app/core/http/attribute.service.ts @@ -53,8 +53,16 @@ export class AttributeService { startTs?: number, endTs?: number, rewriteLatestIfDeleted = false, deleteLatest = true, config?: RequestConfig): Observable { const keys = timeseries.map(attribute => encodeURIComponent(attribute.key)).join(','); - let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/delete` + - `?keys=${keys}&deleteAllDataForKeys=${deleteAllDataForKeys}&rewriteLatestIfDeleted=${rewriteLatestIfDeleted}&deleteLatest=${deleteLatest}`; + let url = `/api/plugins/telemetry/${entityId.entityType}/${entityId.id}/timeseries/delete?keys=${keys}`; + if (isDefinedAndNotNull(deleteAllDataForKeys)) { + url += `&deleteAllDataForKeys=${deleteAllDataForKeys}`; + } + if (isDefinedAndNotNull(rewriteLatestIfDeleted)) { + url += `&rewriteLatestIfDeleted=${rewriteLatestIfDeleted}`; + } + if (isDefinedAndNotNull(deleteLatest)) { + url += `&deleteLatest=${deleteLatest}`; + } if (isDefinedAndNotNull(startTs)) { url += `&startTs=${startTs}`; } diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html index 10a5b03dba..d94f08e29f 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.html @@ -198,7 +198,7 @@ edit - diff --git a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts index add0a5c1e0..0da11767a2 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/attribute-table.component.ts @@ -38,7 +38,7 @@ import { TranslateService } from '@ngx-translate/core'; import { MatDialog } from '@angular/material/dialog'; import { DialogService } from '@core/services/dialog.service'; import { Direction, SortOrder } from '@shared/models/page/sort-order'; -import { fromEvent, merge, Observable } from 'rxjs'; +import { fromEvent, merge } from 'rxjs'; import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators'; import { EntityId } from '@shared/models/id/entity-id'; import { @@ -48,7 +48,8 @@ import { isClientSideTelemetryType, LatestTelemetry, TelemetryType, - telemetryTypeTranslations, TimeseriesDeleteStrategy, + telemetryTypeTranslations, + TimeseriesDeleteStrategy, toTelemetryType } from '@shared/models/telemetry/telemetry.models'; import { AttributeDatasource } from '@home/models/datasource/attribute-datasource'; @@ -88,7 +89,8 @@ import { hidePageSizePixelValue } from '@shared/models/constants'; import { ResizeObserver } from '@juggle/resize-observer'; import { DELETE_TIMESERIES_PANEL_DATA, - DeleteTimeseriesPanelComponent, DeleteTimeseriesPanelData + DeleteTimeseriesPanelComponent, + DeleteTimeseriesPanelData } from '@home/components/attribute/delete-timeseries-panel.component'; @@ -383,15 +385,19 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI }); } - deleteTimeseries($event: Event, attribute?: AttributeData) { + deleteTimeseries($event: Event, telemetry?: AttributeData) { if ($event) { $event.stopPropagation(); } - const isMultipleDeletion = isUndefinedOrNull(attribute) && this.dataSource.selection.selected.length > 1; + const isMultipleDeletion = isUndefinedOrNull(telemetry) && this.dataSource.selection.selected.length > 1; const target = $event.target || $event.srcElement || $event.currentTarget; - const config = new OverlayConfig(); - config.backdropClass = 'cdk-overlay-transparent-backdrop'; - config.hasBackdrop = true; + const config = new OverlayConfig({ + panelClass: 'tb-filter-panel', + backdropClass: 'cdk-overlay-transparent-backdrop', + hasBackdrop: true, + maxWidth: 488, + width: '100%' + }); const connectedPosition: ConnectedPosition = { originX: 'start', originY: 'top', @@ -400,8 +406,6 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI }; config.positionStrategy = this.overlay.position().flexibleConnectedTo(target as HTMLElement) .withPositions([connectedPosition]); - config.maxWidth = '488px'; - config.width = '100%'; const overlayRef = this.overlay.create(config); overlayRef.backdropClick().subscribe(() => { overlayRef.dispose(); @@ -411,7 +415,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI { provide: DELETE_TIMESERIES_PANEL_DATA, useValue: { - isMultipleDeletion: isMultipleDeletion + isMultipleDeletion } as DeleteTimeseriesPanelData }, { @@ -425,31 +429,34 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI componentRef.onDestroy(() => { if (componentRef.instance.result !== null) { const result = componentRef.instance.result; - const deleteTimeseries = attribute ? [attribute]: this.dataSource.selection.selected; + const deleteTimeseries = telemetry ? [telemetry]: this.dataSource.selection.selected; let deleteAllDataForKeys = false; let rewriteLatestIfDeleted = false; let startTs = null; let endTs = null; let deleteLatest = true; - if (result.strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA) { - deleteAllDataForKeys = true; - } - if (result.strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA_EXCEPT_LATEST_VALUE) { - deleteAllDataForKeys = true; - deleteLatest = false; - } - if (result.strategy === TimeseriesDeleteStrategy.DELETE_LATEST_VALUE) { - rewriteLatestIfDeleted = result.rewriteLatest; - startTs = deleteTimeseries[0].lastUpdateTs; - endTs = startTs + 1; - } - if (result.strategy === TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD) { - startTs = result.startDateTime.getTime(); - endTs = result.endDateTime.getTime(); - rewriteLatestIfDeleted = result.rewriteLatest; + switch (result.strategy) { + case TimeseriesDeleteStrategy.DELETE_ALL_DATA: + deleteAllDataForKeys = true; + break; + case TimeseriesDeleteStrategy.DELETE_ALL_DATA_EXCEPT_LATEST_VALUE: + deleteAllDataForKeys = true; + deleteLatest = false; + break; + case TimeseriesDeleteStrategy.DELETE_LATEST_VALUE: + rewriteLatestIfDeleted = result.rewriteLatest; + startTs = deleteTimeseries[0].lastUpdateTs; + endTs = startTs + 1; + break; + case TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD: + startTs = result.startDateTime.getTime(); + endTs = result.endDateTime.getTime(); + rewriteLatestIfDeleted = result.rewriteLatest; + break; } this.attributeService.deleteEntityTimeseries(this.entityIdValue, deleteTimeseries, deleteAllDataForKeys, - startTs, endTs, rewriteLatestIfDeleted, deleteLatest).subscribe(() => this.reloadAttributes()); + startTs, endTs, rewriteLatestIfDeleted, deleteLatest) + .subscribe(() => this.reloadAttributes()); } }); } diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html index aabac0bab4..5778fc6805 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.html @@ -16,47 +16,41 @@ --> - - -

{{ "attribute.delete-timeseries.delete-strategy" | translate }}

- - -
-
- - attribute.delete-timeseries.strategy - - - {{ strategiesTranslationsMap.get(strategy) | translate }} - - + +

{{ "attribute.delete-timeseries.delete-strategy" | translate }}

+ + +
+ + + attribute.delete-timeseries.strategy + + + {{ strategiesTranslationsMap.get(strategy) | translate }} + + + +
+ + attribute.delete-timeseries.start-time + + + + + + attribute.delete-timeseries.ends-on + + + -
-
- - attribute.delete-timeseries.start-time - - - - - - attribute.delete-timeseries.ends-on - - - - -
-
-
- - {{ "attribute.delete-timeseries.rewrite-latest-value" | translate }} - -
+ + {{ "attribute.delete-timeseries.rewrite-latest-value" | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss index d223b29b47..c9a0e527f7 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.scss @@ -13,16 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@import '../../../../../scss/constants'; :host { width: 100%; - background-color: #fff; - box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3), 0px 2px 6px 2px rgba(0, 0, 0, 0.15); - border-radius: 4px; -} -:host ::ng-deep{ - form .mat-toolbar { + .mat-toolbar { background: none; } + + .tb-form-settings { + flex-direction: column; + gap: 16px; + padding-top: 0; + } + + .tb-select-interval { + display: flex; + flex-direction: row; + gap: 16px; + @media #{$mat-xs} { + flex-direction: column; + gap: 0; + } + } + + .tb-slide-toggle { + margin-bottom: 8px; + } } diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts index 8adb9bcd5a..94c66b3734 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts @@ -51,34 +51,33 @@ export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { strategiesTranslationsMap = timeseriesDeleteStrategyTranslations; - multipleDeletionStrategies = [ + private multipleDeletionStrategies = new Set([ TimeseriesDeleteStrategy.DELETE_ALL_DATA, TimeseriesDeleteStrategy.DELETE_ALL_DATA_EXCEPT_LATEST_VALUE - ]; + ]); private destroy$ = new Subject(); - constructor(@Inject(DELETE_TIMESERIES_PANEL_DATA) public data: DeleteTimeseriesPanelData, - public overlayRef: OverlayRef, - public fb: FormBuilder) { } + constructor(@Inject(DELETE_TIMESERIES_PANEL_DATA) private data: DeleteTimeseriesPanelData, + private overlayRef: OverlayRef, + private fb: FormBuilder) { } ngOnInit(): void { const today = new Date(); if (this.data.isMultipleDeletion) { - this.strategiesTranslationsMap = new Map(Array.from(this.strategiesTranslationsMap.entries()) - .filter(([strategy]) => { - return this.multipleDeletionStrategies.includes(strategy); - })) + this.strategiesTranslationsMap = new Map(Array.from(this.strategiesTranslationsMap) + .filter(([strategy]) => this.multipleDeletionStrategies.has(strategy))) } this.deleteTimeseriesFormGroup = this.fb.group({ strategy: [TimeseriesDeleteStrategy.DELETE_ALL_DATA], startDateTime: [ { value: new Date(today.getFullYear(), today.getMonth() - 1, today.getDate()), disabled: true }, - [Validators.required] + Validators.required ], - endDateTime: [{ value: today, disabled: true }, [Validators.required]], + endDateTime: [{ value: today, disabled: true }, Validators.required], rewriteLatest: [true] }) + this.deleteTimeseriesFormGroup.get('strategy').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe(value => { @@ -124,7 +123,7 @@ export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { return this.deleteTimeseriesFormGroup.get('strategy').value === TimeseriesDeleteStrategy.DELETE_LATEST_VALUE; } - onStartDateTimeChange(newStartDateTime: Date) { + private onStartDateTimeChange(newStartDateTime: Date) { if (newStartDateTime) { const endDateTimeTs = this.deleteTimeseriesFormGroup.get('endDateTime').value.getTime(); if (newStartDateTime.getTime() >= endDateTimeTs) { @@ -137,7 +136,7 @@ export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { } } - onEndDateTimeChange(newEndDateTime: Date) { + private onEndDateTimeChange(newEndDateTime: Date) { if (newEndDateTime) { const startDateTimeTs = this.deleteTimeseriesFormGroup.get('startDateTime').value.getTime(); if (newEndDateTime.getTime() <= startDateTimeTs) { From fdceb86b319d33b02dc545a213b40ccd8fd4606f Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 4 Aug 2023 19:07:55 +0300 Subject: [PATCH 384/421] UI: Implement widget title font and color settings. --- .../src/app/core/services/dialog.service.ts | 5 +- .../alarms-table-basic-config.component.html | 22 ++++- .../alarms-table-basic-config.component.ts | 10 +++ .../basic/basic-widget-config.module.ts | 2 - ...entities-table-basic-config.component.html | 22 ++++- .../entities-table-basic-config.component.ts | 10 +++ .../simple-card-basic-config.component.ts | 2 +- ...meseries-table-basic-config.component.html | 22 ++++- ...timeseries-table-basic-config.component.ts | 10 +++ .../value-card-basic-config.component.ts | 2 +- .../chart/flot-basic-config.component.html | 22 ++++- .../chart/flot-basic-config.component.ts | 10 +++ .../config/widget-config-components.module.ts | 7 +- .../lib/cards/value-card-widget.component.ts | 2 +- .../lib/cards/value-card-widget.models.ts | 2 +- .../value-card-widget-settings.component.ts | 2 +- .../background-settings-panel.component.ts | 2 +- .../common/background-settings.component.ts | 2 +- .../common/color-settings-panel.component.ts | 2 +- .../common/color-settings.component.ts | 2 +- .../common/css-unit-select.component.html | 4 +- .../common/css-unit-select.component.ts | 7 +- .../common/date-format-select.component.ts | 2 +- .../date-format-settings-panel.component.ts | 2 +- .../common/font-settings-panel.component.html | 16 +++- .../common/font-settings-panel.component.ts | 43 +++++++--- .../common/font-settings.component.ts | 14 +++- .../common/widget-settings-common.module.ts | 84 +++++++++++++++++++ .../lib/settings/widget-settings.module.ts | 54 +----------- .../widget/widget-config.component.html | 20 ++++- .../widget/widget-config.component.ts | 8 ++ .../home/models/dashboard-component.models.ts | 13 +-- .../components/color-input.component.ts | 30 ++----- .../color-picker-panel.component.html | 8 ++ .../color-picker-panel.component.ts | 9 ++ .../dialog/color-picker-dialog.component.html | 1 + .../dialog/color-picker-dialog.component.ts | 3 + ui-ngx/src/app/shared/models/public-api.ts | 1 + .../models}/widget-settings.models.ts | 29 +++++-- ui-ngx/src/app/shared/models/widget.models.ts | 7 +- .../assets/locale/locale.constant-en_US.json | 3 +- ui-ngx/src/form.scss | 2 +- 42 files changed, 379 insertions(+), 141 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts rename ui-ngx/src/app/{modules/home/components/widget/config => shared/models}/widget-settings.models.ts (92%) diff --git a/ui-ngx/src/app/core/services/dialog.service.ts b/ui-ngx/src/app/core/services/dialog.service.ts index 2ca2d6d87e..6ba2687278 100644 --- a/ui-ngx/src/app/core/services/dialog.service.ts +++ b/ui-ngx/src/app/core/services/dialog.service.ts @@ -96,13 +96,14 @@ export class DialogService { return dialogRef.afterClosed(); } - colorPicker(color: string): Observable { + colorPicker(color: string, colorClearButton = false): Observable { return this.dialog.open(ColorPickerDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { - color + color, + colorClearButton }, autoFocus: false }).afterClosed(); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html index ffddc9df59..f46686e0c0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html @@ -50,13 +50,24 @@
widget-config.card-appearance
-
+
{{ 'widget-config.card-title' | translate }} - - - +
+ + + + + + + +
@@ -68,6 +79,7 @@ formControlName="titleIcon">
@@ -84,12 +96,14 @@
{{ 'widget-config.text-color' | translate }}
{{ 'widget-config.background-color' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts index 33abc0670c..c67a59ac20 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts @@ -61,6 +61,8 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent columns: [this.getColumns(configData.config.alarmSource), []], showTitle: [configData.config.showTitle, []], title: [configData.config.settings?.alarmsTitle, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], showTitleIcon: [configData.config.showTitleIcon, []], titleIcon: [configData.config.titleIcon, []], iconColor: [configData.config.iconColor, []], @@ -82,6 +84,8 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent this.widgetConfig.config.showTitle = config.showTitle; this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; this.widgetConfig.config.settings.alarmsTitle = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; this.widgetConfig.config.showTitleIcon = config.showTitleIcon; this.widgetConfig.config.titleIcon = config.titleIcon; this.widgetConfig.config.iconColor = config.iconColor; @@ -100,6 +104,8 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent const showTitleIcon: boolean = this.alarmsTableWidgetConfigForm.get('showTitleIcon').value; if (showTitle) { this.alarmsTableWidgetConfigForm.get('title').enable(); + this.alarmsTableWidgetConfigForm.get('titleFont').enable(); + this.alarmsTableWidgetConfigForm.get('titleColor').enable(); this.alarmsTableWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); if (showTitleIcon) { this.alarmsTableWidgetConfigForm.get('titleIcon').enable(); @@ -110,11 +116,15 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent } } else { this.alarmsTableWidgetConfigForm.get('title').disable(); + this.alarmsTableWidgetConfigForm.get('titleFont').disable(); + this.alarmsTableWidgetConfigForm.get('titleColor').disable(); this.alarmsTableWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); this.alarmsTableWidgetConfigForm.get('titleIcon').disable(); this.alarmsTableWidgetConfigForm.get('iconColor').disable(); } this.alarmsTableWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.alarmsTableWidgetConfigForm.get('titleFont').updateValueAndValidity({emitEvent}); + this.alarmsTableWidgetConfigForm.get('titleColor').updateValueAndValidity({emitEvent}); this.alarmsTableWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); this.alarmsTableWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); this.alarmsTableWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 3a3425975b..795d46984c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -34,7 +34,6 @@ import { TimeseriesTableBasicConfigComponent } from '@home/components/widget/config/basic/cards/timeseries-table-basic-config.component'; import { FlotBasicConfigComponent } from '@home/components/widget/config/basic/chart/flot-basic-config.component'; -import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widget-settings.module'; import { AlarmsTableBasicConfigComponent } from '@home/components/widget/config/basic/alarm/alarms-table-basic-config.component'; @@ -57,7 +56,6 @@ import { imports: [ CommonModule, SharedModule, - WidgetSettingsModule, WidgetConfigComponentsModule ], exports: [ diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html index c68caab86e..b4c2dbd616 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html @@ -39,13 +39,24 @@
widget-config.card-appearance
-
+
{{ 'widget-config.card-title' | translate }} - - - +
+ + + + + + + +
@@ -57,6 +68,7 @@ formControlName="titleIcon">
@@ -72,12 +84,14 @@
{{ 'widget-config.text-color' | translate }}
{{ 'widget-config.background-color' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts index 2061832918..f407293064 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts @@ -80,6 +80,8 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen columns: [this.getColumns(configData.config.datasources), []], showTitle: [configData.config.showTitle, []], title: [configData.config.settings?.entitiesTitle, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], showTitleIcon: [configData.config.showTitleIcon, []], titleIcon: [configData.config.titleIcon, []], iconColor: [configData.config.iconColor, []], @@ -100,6 +102,8 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen this.widgetConfig.config.showTitle = config.showTitle; this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; this.widgetConfig.config.settings.entitiesTitle = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; this.widgetConfig.config.showTitleIcon = config.showTitleIcon; this.widgetConfig.config.titleIcon = config.titleIcon; this.widgetConfig.config.iconColor = config.iconColor; @@ -118,6 +122,8 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen const showTitleIcon: boolean = this.entitiesTableWidgetConfigForm.get('showTitleIcon').value; if (showTitle) { this.entitiesTableWidgetConfigForm.get('title').enable(); + this.entitiesTableWidgetConfigForm.get('titleFont').enable(); + this.entitiesTableWidgetConfigForm.get('titleColor').enable(); this.entitiesTableWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); if (showTitleIcon) { this.entitiesTableWidgetConfigForm.get('titleIcon').enable(); @@ -128,11 +134,15 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen } } else { this.entitiesTableWidgetConfigForm.get('title').disable(); + this.entitiesTableWidgetConfigForm.get('titleFont').disable(); + this.entitiesTableWidgetConfigForm.get('titleColor').disable(); this.entitiesTableWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); this.entitiesTableWidgetConfigForm.get('titleIcon').disable(); this.entitiesTableWidgetConfigForm.get('iconColor').disable(); } this.entitiesTableWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.entitiesTableWidgetConfigForm.get('titleFont').updateValueAndValidity({emitEvent}); + this.entitiesTableWidgetConfigForm.get('titleColor').updateValueAndValidity({emitEvent}); this.entitiesTableWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); this.entitiesTableWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); this.entitiesTableWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts index 4238d6000c..283e39362a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts @@ -29,7 +29,7 @@ import { WidgetConfigComponent } from '@home/components/widget/widget-config.com import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; import { isUndefined } from '@core/utils'; -import { getLabel, setLabel } from '@home/components/widget/config/widget-settings.models'; +import { getLabel, setLabel } from '@shared/models/widget-settings.models'; @Component({ selector: 'tb-simple-card-basic-config', diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html index 49196fac3a..5952c206b6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html @@ -39,13 +39,24 @@
widget-config.card-appearance
-
+
{{ 'widget-config.card-title' | translate }} - - - +
+ + + + + + + +
@@ -57,6 +68,7 @@ formControlName="titleIcon">
@@ -72,12 +84,14 @@
{{ 'widget-config.text-color' | translate }}
{{ 'widget-config.background-color' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts index ac1b12167c..a8c4206fa7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts @@ -66,6 +66,8 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon columns: [this.getColumns(configData.config.datasources), []], showTitle: [configData.config.showTitle, []], title: [configData.config.title, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], showTitleIcon: [configData.config.showTitleIcon, []], titleIcon: [configData.config.titleIcon, []], iconColor: [configData.config.iconColor, []], @@ -85,6 +87,8 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon this.widgetConfig.config.actions = config.actions; this.widgetConfig.config.showTitle = config.showTitle; this.widgetConfig.config.title = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; this.widgetConfig.config.showTitleIcon = config.showTitleIcon; this.widgetConfig.config.titleIcon = config.titleIcon; this.widgetConfig.config.iconColor = config.iconColor; @@ -104,6 +108,8 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon const showTitleIcon: boolean = this.timeseriesTableWidgetConfigForm.get('showTitleIcon').value; if (showTitle) { this.timeseriesTableWidgetConfigForm.get('title').enable(); + this.timeseriesTableWidgetConfigForm.get('titleFont').enable(); + this.timeseriesTableWidgetConfigForm.get('titleColor').enable(); this.timeseriesTableWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); if (showTitleIcon) { this.timeseriesTableWidgetConfigForm.get('titleIcon').enable(); @@ -114,11 +120,15 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon } } else { this.timeseriesTableWidgetConfigForm.get('title').disable(); + this.timeseriesTableWidgetConfigForm.get('titleFont').disable(); + this.timeseriesTableWidgetConfigForm.get('titleColor').disable(); this.timeseriesTableWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); this.timeseriesTableWidgetConfigForm.get('titleIcon').disable(); this.timeseriesTableWidgetConfigForm.get('iconColor').disable(); } this.timeseriesTableWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.timeseriesTableWidgetConfigForm.get('titleFont').updateValueAndValidity({emitEvent}); + this.timeseriesTableWidgetConfigForm.get('titleColor').updateValueAndValidity({emitEvent}); this.timeseriesTableWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); this.timeseriesTableWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); this.timeseriesTableWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts index f00ec8e2e6..b535aaa7f8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts @@ -34,7 +34,7 @@ import { DateFormatSettings, getLabel, setLabel -} from '@home/components/widget/config/widget-settings.models'; +} from '@shared/models/widget-settings.models'; import { valueCardDefaultSettings, ValueCardLayout, diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html index 952b3f9031..0d607c230d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html @@ -39,13 +39,24 @@
widget-config.card-appearance
-
+
{{ 'widget-config.card-title' | translate }} - - - +
+ + + + + + + +
@@ -57,6 +68,7 @@ formControlName="titleIcon">
@@ -70,12 +82,14 @@
{{ 'widget-config.text-color' | translate }}
{{ 'widget-config.background-color' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts index 9d3dc4f1dd..c77d0ecb76 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts @@ -66,6 +66,8 @@ export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { series: [this.getSeries(configData.config.datasources), []], showTitle: [configData.config.showTitle, []], title: [configData.config.title, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], showTitleIcon: [configData.config.showTitleIcon, []], titleIcon: [configData.config.titleIcon, []], iconColor: [configData.config.iconColor, []], @@ -89,6 +91,8 @@ export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { this.widgetConfig.config.actions = config.actions; this.widgetConfig.config.showTitle = config.showTitle; this.widgetConfig.config.title = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; this.widgetConfig.config.showTitleIcon = config.showTitleIcon; this.widgetConfig.config.titleIcon = config.titleIcon; this.widgetConfig.config.iconColor = config.iconColor; @@ -114,6 +118,8 @@ export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { const showLegend: boolean = this.flotWidgetConfigForm.get('showLegend').value; if (showTitle) { this.flotWidgetConfigForm.get('title').enable(); + this.flotWidgetConfigForm.get('titleFont').enable(); + this.flotWidgetConfigForm.get('titleColor').enable(); this.flotWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); if (showTitleIcon) { this.flotWidgetConfigForm.get('titleIcon').enable(); @@ -124,6 +130,8 @@ export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { } } else { this.flotWidgetConfigForm.get('title').disable(); + this.flotWidgetConfigForm.get('titleFont').disable(); + this.flotWidgetConfigForm.get('titleColor').disable(); this.flotWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); this.flotWidgetConfigForm.get('titleIcon').disable(); this.flotWidgetConfigForm.get('iconColor').disable(); @@ -134,6 +142,8 @@ export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { this.flotWidgetConfigForm.get('legendConfig').disable(); } this.flotWidgetConfigForm.get('title').updateValueAndValidity({emitEvent}); + this.flotWidgetConfigForm.get('titleFont').updateValueAndValidity({emitEvent}); + this.flotWidgetConfigForm.get('titleColor').updateValueAndValidity({emitEvent}); this.flotWidgetConfigForm.get('showTitleIcon').updateValueAndValidity({emitEvent: false}); this.flotWidgetConfigForm.get('titleIcon').updateValueAndValidity({emitEvent}); this.flotWidgetConfigForm.get('iconColor').updateValueAndValidity({emitEvent}); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-config-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-config-components.module.ts index 3777973eff..392a829955 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-config-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-config-components.module.ts @@ -29,6 +29,7 @@ import { FilterSelectComponent } from '@home/components/filter/filter-select.com import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widget-settings.module'; import { WidgetSettingsComponent } from '@home/components/widget/config/widget-settings.component'; import { TimewindowConfigPanelComponent } from '@home/components/widget/config/timewindow-config-panel.component'; +import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings/common/widget-settings-common.module'; @NgModule({ declarations: @@ -48,7 +49,8 @@ import { TimewindowConfigPanelComponent } from '@home/components/widget/config/t imports: [ CommonModule, SharedModule, - WidgetSettingsModule + WidgetSettingsModule, + WidgetSettingsCommonModule ], exports: [ AlarmAssigneeSelectComponent, @@ -61,7 +63,8 @@ import { TimewindowConfigPanelComponent } from '@home/components/widget/config/t EntityAliasSelectComponent, FilterSelectComponent, TimewindowConfigPanelComponent, - WidgetSettingsComponent + WidgetSettingsComponent, + WidgetSettingsCommonModule ] }) export class WidgetConfigComponentsModule { } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts index f495581571..ac2cb62fee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts @@ -28,7 +28,7 @@ import { iconStyle, overlayStyle, textStyle -} from '@home/components/widget/config/widget-settings.models'; +} from '@shared/models/widget-settings.models'; import { valueCardDefaultSettings, ValueCardLayout, ValueCardWidgetSettings } from './value-card-widget.models'; import { WidgetComponent } from '@home/components/widget/widget.component'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts index 23d9a30329..549ba4abcd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts @@ -21,7 +21,7 @@ import { constantColor, cssUnit, DateFormatSettings, Font, lastUpdateAgoDateFormat -} from '@home/components/widget/config/widget-settings.models'; +} from '@shared/models/widget-settings.models'; export enum ValueCardLayout { square = 'square', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts index 6f76546ac1..ad50dde8d2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.ts @@ -30,7 +30,7 @@ import { DateFormatProcessor, DateFormatSettings, getLabel -} from '@home/components/widget/config/widget-settings.models'; +} from '@shared/models/widget-settings.models'; @Component({ selector: 'tb-value-card-widget-settings', 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 465d3383e2..ab94b95800 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 @@ -22,7 +22,7 @@ import { BackgroundSettings, BackgroundType, backgroundTypeTranslations, ComponentStyle -} from '@home/components/widget/config/widget-settings.models'; +} from '@shared/models/widget-settings.models'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { Store } from '@ngrx/store'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts index f8162575a3..62a2495942 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/background-settings.component.ts @@ -22,7 +22,7 @@ import { BackgroundType, ComponentStyle, overlayStyle -} from '@home/components/widget/config/widget-settings.models'; +} from '@shared/models/widget-settings.models'; import { MatButton } from '@angular/material/button'; import { TbPopoverService } from '@shared/components/popover.service'; import { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts index 2118bde6df..483674437d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings-panel.component.ts @@ -21,7 +21,7 @@ import { ColorSettings, ColorType, colorTypeTranslations -} from '@home/components/widget/config/widget-settings.models'; +} from '@shared/models/widget-settings.models'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { AbstractControl, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts index bffad41080..6d8ad1eefe 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts @@ -16,7 +16,7 @@ import { Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { ColorSettings, ColorType, ComponentStyle } from '@home/components/widget/config/widget-settings.models'; +import { ColorSettings, ColorType, ComponentStyle } from '@shared/models/widget-settings.models'; import { MatButton } from '@angular/material/button'; import { TbPopoverService } from '@shared/components/popover.service'; import { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html index eaca1b6d40..1c00141b1d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.html @@ -16,7 +16,9 @@ --> - + + + {{ cssUnit }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts index dc593e9564..3d2658dae1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts @@ -16,7 +16,8 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormControl } from '@angular/forms'; -import { cssUnit, cssUnits } from '@home/components/widget/config/widget-settings.models'; +import { cssUnit, cssUnits } from '@shared/models/widget-settings.models'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-css-unit-select', @@ -35,6 +36,10 @@ export class CssUnitSelectComponent implements OnInit, ControlValueAccessor { @Input() disabled: boolean; + @Input() + @coerceBoolean() + allowEmpty = false; + cssUnitsList = cssUnits; cssUnitFormControl: UntypedFormControl; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts index 413111ad1e..6393a92054 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts @@ -20,7 +20,7 @@ import { compareDateFormats, dateFormats, DateFormatSettings -} from '@home/components/widget/config/widget-settings.models'; +} from '@shared/models/widget-settings.models'; import { TranslateService } from '@ngx-translate/core'; import { DatePipe } from '@angular/common'; import { MatButton } from '@angular/material/button'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts index 47f54fd5d5..be120b80f6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.ts @@ -16,7 +16,7 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { PageComponent } from '@shared/components/page.component'; -import { DateFormatSettings } from '@home/components/widget/config/widget-settings.models'; +import { DateFormatSettings } from '@shared/models/widget-settings.models'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { UntypedFormControl, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html index 140c525ac2..36d488d766 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html @@ -51,7 +51,9 @@
widgets.widget-font.font-weight
- + + + {{ fontWeightTranslationsMap.has(weight) ? (fontWeightTranslationsMap.get(weight) | translate) : weight }} @@ -61,7 +63,9 @@
widgets.widget-font.font-style
- + + + {{ fontStyleTranslationsMap.get(style) | translate }} @@ -74,6 +78,14 @@
{{ previewText }}
+ +
diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts index 219ed0ec56..06d24f026b 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts @@ -23,6 +23,7 @@ import { DialogComponent } from '@shared/components/dialog.component'; export interface ColorPickerDialogData { color: string; + colorClearButton: boolean; } @Component({ @@ -33,6 +34,7 @@ export interface ColorPickerDialogData { export class ColorPickerDialogComponent extends DialogComponent { color: string; + colorClearButton: boolean; constructor(protected store: Store, protected router: Router, @@ -40,6 +42,7 @@ export class ColorPickerDialogComponent extends DialogComponent) { super(store, router, dialogRef); this.color = data.color; + this.colorClearButton = data.colorClearButton; } selectColor(color: string) { diff --git a/ui-ngx/src/app/shared/models/public-api.ts b/ui-ngx/src/app/shared/models/public-api.ts index aa93bece92..1b624259a9 100644 --- a/ui-ngx/src/app/shared/models/public-api.ts +++ b/ui-ngx/src/app/shared/models/public-api.ts @@ -54,6 +54,7 @@ export * from './settings.models'; export * from './tenant.model'; export * from './user.model'; export * from './user-settings.models'; +export * from './widget-settings.models'; export * from './widget.models'; export * from './widgets-bundle.model'; export * from './window-message.model'; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts b/ui-ngx/src/app/shared/models/widget-settings.models.ts similarity index 92% rename from ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts rename to ui-ngx/src/app/shared/models/widget-settings.models.ts index 0fa061de72..f7c1b6746e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-settings.models.ts +++ b/ui-ngx/src/app/shared/models/widget-settings.models.ts @@ -308,11 +308,30 @@ export const iconStyle = (size: number, sizeUnit: cssUnit): ComponentStyle => { }; }; -export const textStyle = (font: Font, lineHeight = '1.5', letterSpacing = '0.25px'): ComponentStyle => ({ - font: font.style + ' normal ' + font.weight + ' ' + (font.size+font.sizeUnit) + '/' + lineHeight + ' ' + font.family + - (font.family !== 'Roboto' ? ', Roboto' : ''), - letterSpacing -}); +export const textStyle = (font?: Font, lineHeight = '1.5', letterSpacing = '0.25px'): ComponentStyle => { + const style: ComponentStyle = { + lineHeight, + letterSpacing + }; + if (font?.style) { + style.fontStyle = font.style; + } + if (font?.weight) { + style.fontWeight = font.weight; + } + if (font?.size) { + style.fontSize = (font.size + (font.sizeUnit || 'px')); + } + if (font?.family) { + style.fontFamily = font.family + + (font.family !== 'Roboto' ? ', Roboto' : ''); + } + return style; +}; + +export const isFontSet = (font: Font): boolean => (!!font && !!font.style && !!font.weight && !!font.size && !!font.family); + +export const isFontPartiallySet = (font: Font): boolean => (!!font && (!!font.style || !!font.weight || !!font.size || !!font.family)); export const backgroundStyle = (background: BackgroundSettings): ComponentStyle => { if (background.type === BackgroundType.color) { diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index e0d9918540..c3b23048d1 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -40,6 +40,7 @@ import { Dashboard } from '@shared/models/dashboard.models'; import { IAliasController } from '@core/api/widget-api.models'; import { isEmptyStr } from '@core/utils'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { ComponentStyle, Font } from '@shared/models/widget-settings.models'; export enum widgetType { timeseries = 'timeseries', @@ -619,6 +620,8 @@ export enum WidgetConfigMode { export interface WidgetConfig { configMode?: WidgetConfigMode; title?: string; + titleFont?: Font; + titleColor?: string; titleIcon?: string; showTitle?: boolean; showTitleIcon?: boolean; @@ -639,9 +642,9 @@ export interface WidgetConfig { padding?: string; margin?: string; borderRadius?: string; - widgetStyle?: {[klass: string]: any}; + widgetStyle?: ComponentStyle; widgetCss?: string; - titleStyle?: {[klass: string]: any}; + titleStyle?: ComponentStyle; units?: string; decimals?: number; noDataDisplayMessage?: string; 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 7f0a271a04..026ebf857e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -74,7 +74,8 @@ "reset": "Reset", "show-more": "Show more", "dont-show-again": "Do not show again", - "see-documentation": "See documentation" + "see-documentation": "See documentation", + "clear": "Clear" }, "aggregation": { "aggregation": "Aggregation", diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 14711b85b4..bef8bf621e 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -21,7 +21,7 @@ flex-direction: column; align-items: stretch; gap: 12px; - padding: 12px 12px 12px 16px; + padding: 12px 7px 12px 16px; .mat-mdc-form-field, tb-unit-input { width: auto; &.medium-width { From 6bc9148f772e724f4ec322d9790665fa3d0c5050 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 7 Aug 2023 11:20:53 +0300 Subject: [PATCH 385/421] added optional nosxss validation for attribute/telemetry value --- .../DefaultTelemetrySubscriptionService.java | 6 ++++- .../src/main/resources/thingsboard.yml | 2 ++ .../controller/TelemetryControllerTest.java | 17 +++++++++++++ .../server/dao/attributes/AttributeUtils.java | 8 +++--- .../dao/attributes/BaseAttributesService.java | 8 ++++-- .../attributes/CachedAttributesService.java | 6 +++-- .../thingsboard/server/dao/util/KvUtils.java | 25 ++++++++++++------- 7 files changed, 54 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 3f5e52796a..df3a15e765 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -78,6 +79,9 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer private ExecutorService tsCallBackExecutor; + @Value("${sql.ts.value_no_xss_validation:false}") + private boolean valueNoXssValidation; + public DefaultTelemetrySubscriptionService(AttributesService attrService, TimeseriesService tsService, @Lazy TbEntityViewService tbEntityViewService, @@ -135,7 +139,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer checkInternalEntity(entityId); boolean sysTenant = TenantId.SYS_TENANT_ID.equals(tenantId) || tenantId == null; if (sysTenant || apiUsageStateService.getApiUsageState(tenantId).isDbStorageEnabled()) { - KvUtils.validate(ts); + KvUtils.validate(ts, valueNoXssValidation); if (saveLatest) { saveAndNotifyInternal(tenantId, entityId, ts, ttl, getCallback(tenantId, customerId, sysTenant, callback)); } else { diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index aa62a46d61..c8742921b0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -269,11 +269,13 @@ sql: batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:100}" stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}" batch_threads: "${SQL_ATTRIBUTES_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution + value_no_xss_validation: "${SQL_ATTRIBUTES_VALUE_NO_XSS_VALIDATION:false}" ts: batch_size: "${SQL_TS_BATCH_SIZE:10000}" batch_max_delay: "${SQL_TS_BATCH_MAX_DELAY_MS:100}" stats_print_interval_ms: "${SQL_TS_BATCH_STATS_PRINT_MS:10000}" batch_threads: "${SQL_TS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution + value_no_xss_validation: "${SQL_TS_VALUE_NO_XSS_VALIDATION:false}" ts_latest: batch_size: "${SQL_TS_LATEST_BATCH_SIZE:10000}" batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}" diff --git a/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java index 47cac1b549..fc6fc33b8f 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TelemetryControllerTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import org.junit.Test; +import org.springframework.test.context.TestPropertySource; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest; import org.thingsboard.server.common.data.security.DeviceCredentials; @@ -25,6 +26,10 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @DaoSqlTest +@TestPropertySource(properties = { + "sql.attributes.value_no_xss_validation=true", + "sql.ts.value_no_xss_validation=true" +}) public class TelemetryControllerTest extends AbstractControllerTest { @Test @@ -39,6 +44,18 @@ public class TelemetryControllerTest extends AbstractControllerTest { doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", invalidRequestBody, String.class, status().isBadRequest()); } + @Test + public void testValueConstraintValidator() throws Exception { + loginTenantAdmin(); + Device device = createDevice(); + String correctRequestBody = "{\"data\": \"value\"}"; + doPostAsync("/api/plugins/telemetry/" + device.getId() + "/SHARED_SCOPE", correctRequestBody, String.class, status().isOk()); + doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", correctRequestBody, String.class, status().isOk()); + String invalidRequestBody = "{\"data\": \"alert(document)\\\">\"}"; + doPostAsync("/api/plugins/telemetry/" + device.getId() + "/SHARED_SCOPE", invalidRequestBody, String.class, status().isBadRequest()); + doPostAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/timeseries/smth", invalidRequestBody, String.class, status().isBadRequest()); + } + private Device createDevice() throws Exception { String testToken = "TEST_TOKEN"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeUtils.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeUtils.java index d1abeda5b6..192d56334d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeUtils.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeUtils.java @@ -30,12 +30,12 @@ public class AttributeUtils { Validator.validateString(scope, "Incorrect scope " + scope); } - public static void validate(List kvEntries) { - kvEntries.forEach(AttributeUtils::validate); + public static void validate(List kvEntries, boolean valueNoXssValidation) { + kvEntries.forEach(tsKvEntry -> validate(tsKvEntry, valueNoXssValidation)); } - public static void validate(AttributeKvEntry kvEntry) { - KvUtils.validate(kvEntry); + public static void validate(AttributeKvEntry kvEntry, boolean valueNoXssValidation) { + KvUtils.validate(kvEntry, valueNoXssValidation); if (kvEntry.getDataType() == null) { throw new IncorrectParameterException("Incorrect kvEntry. Data type can't be null"); } else { diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java index 09414ac750..f855c116e2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.attributes; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Service; @@ -45,6 +46,9 @@ import static org.thingsboard.server.dao.attributes.AttributeUtils.validate; public class BaseAttributesService implements AttributesService { private final AttributesDao attributesDao; + @Value("${sql.attributes.value_no_xss_validation:false}") + private boolean valueNoXssValidation; + public BaseAttributesService(AttributesDao attributesDao) { this.attributesDao = attributesDao; } @@ -82,14 +86,14 @@ public class BaseAttributesService implements AttributesService { @Override public ListenableFuture save(TenantId tenantId, EntityId entityId, String scope, AttributeKvEntry attribute) { validate(entityId, scope); - AttributeUtils.validate(attribute); + AttributeUtils.validate(attribute, valueNoXssValidation); return attributesDao.save(tenantId, entityId, scope, attribute); } @Override public ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes) { validate(entityId, scope); - AttributeUtils.validate(attributes); + AttributeUtils.validate(attributes, valueNoXssValidation); List> saveFutures = attributes.stream().map(attribute -> attributesDao.save(tenantId, entityId, scope, attribute)).collect(Collectors.toList()); return Futures.allAsList(saveFutures); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java index b95ce39d9a..faff81670b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java @@ -69,6 +69,8 @@ public class CachedAttributesService implements AttributesService { @Value("${cache.type:caffeine}") private String cacheType; + @Value("${sql.attributes.value_no_xss_validation:false}") + private boolean valueNoXssValidation; public CachedAttributesService(AttributesDao attributesDao, StatsFactory statsFactory, @@ -212,7 +214,7 @@ public class CachedAttributesService implements AttributesService { @Override public ListenableFuture save(TenantId tenantId, EntityId entityId, String scope, AttributeKvEntry attribute) { validate(entityId, scope); - AttributeUtils.validate(attribute); + AttributeUtils.validate(attribute, valueNoXssValidation); ListenableFuture future = attributesDao.save(tenantId, entityId, scope, attribute); return Futures.transform(future, key -> evict(entityId, scope, attribute, key), cacheExecutor); } @@ -220,7 +222,7 @@ public class CachedAttributesService implements AttributesService { @Override public ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes) { validate(entityId, scope); - AttributeUtils.validate(attributes); + AttributeUtils.validate(attributes, valueNoXssValidation); List> futures = new ArrayList<>(attributes.size()); for (var attribute : attributes) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/KvUtils.java b/dao/src/main/java/org/thingsboard/server/dao/util/KvUtils.java index 788a19228b..e417a5a50a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/KvUtils.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/KvUtils.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.util; +import com.fasterxml.jackson.databind.JsonNode; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import org.thingsboard.server.common.data.kv.KvEntry; @@ -36,11 +37,11 @@ public class KvUtils { .maximumSize(100000).build(); } - public static void validate(List tsKvEntries) { - tsKvEntries.forEach(KvUtils::validate); + public static void validate(List tsKvEntries, boolean valueNoXssValidation) { + tsKvEntries.forEach(tsKvEntry -> validate(tsKvEntry, valueNoXssValidation)); } - public static void validate(KvEntry tsKvEntry) { + public static void validate(KvEntry tsKvEntry, boolean valueNoXssValidation) { if (tsKvEntry == null) { throw new IncorrectParameterException("Key value entry can't be null"); } @@ -55,14 +56,20 @@ public class KvUtils { throw new DataValidationException("Validation error: key length must be equal or less than 255"); } - if (validatedKeys.getIfPresent(key) != null) { - return; + if (validatedKeys.getIfPresent(key) == null) { + if (!NoXssValidator.isValid(key)) { + throw new DataValidationException("Validation error: key is malformed"); + } + validatedKeys.put(key, Boolean.TRUE); } - if (!NoXssValidator.isValid(key)) { - throw new DataValidationException("Validation error: key is malformed"); + if (valueNoXssValidation) { + Object value = tsKvEntry.getValue(); + if (value instanceof CharSequence || value instanceof JsonNode) { + if (!NoXssValidator.isValid(value.toString())) { + throw new DataValidationException("Validation error: value is malformed"); + } + } } - - validatedKeys.put(key, Boolean.TRUE); } } From b25fd961d4cdb48ed56b534da8ff451c0598bb33 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Mon, 7 Aug 2023 13:08:06 +0300 Subject: [PATCH 386/421] Fix getAvailableDeliveryMethods for customers --- .../thingsboard/server/controller/NotificationController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java index 5949028fea..04cf3d440b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -432,9 +432,8 @@ public class NotificationController extends BaseController { notes = "Returns the list of delivery methods that are properly configured and are allowed to be used for sending notifications." + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @GetMapping("/notification/deliveryMethods") - @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public Set getAvailableDeliveryMethods(@AuthenticationPrincipal SecurityUser user) throws ThingsboardException { - accessControlService.checkPermission(user, Resource.ADMIN_SETTINGS, Operation.READ); return notificationCenter.getAvailableDeliveryMethods(user.getTenantId()); } From 8faa1410b66cb2ef9d924b7a9e790881cb4c1d70 Mon Sep 17 00:00:00 2001 From: Andrii Landiak <50847617+AndriiLandiak@users.noreply.github.com> Date: Mon, 7 Aug 2023 13:21:02 +0300 Subject: [PATCH 387/421] Edge crud notification: implement event publisher strategy to process pubsub model for detecting changes in entities * Improve edge notification for entities' CRUD operations. Use service layer to notify instead of TbService * Improve queue service, delete unused class for edge event updates * Improve alarm delete and add handle fox delete dao event notification * Refactoring: provide notification for relations and alarms. Improve logic and bad edge event type using * Add entity type to SaveEvent to process correct message type to edge * Improve relation service publish event * Introduce EdgeEventSourcing service instead of saving edge events on controller/service layers. Part #2 * Improved stability of device edge test * Push credential updated event only in case update * Add tenantId to saveUser signature to send correct notification for listener * Fix tests to send correct notification msg to edge * Fix tests with correct action type * Add delete msg to edge for customer * Refactor ActionEntityEvent to use lombok builder * Remove unnecessary comments * Added edgeSynchronizationManager into BaseAlarmProcessor and BaseRelationProcessor * Fixed license header * Remove notification to edge from Version Control Service * Fixed alarm del processing - find related edges inside edge processor * Fix controller test for publish event to listener if entity was deleted * Added check for edge imitator messages during login as tenant admin * Refactoring: Added filtering of relation on EdgeEventSourcingListener * Refactored to be in sync with PE * Refactored edge test to be in sync with PE edge test changes * EdgeControllerTest - moved await block into separate method to reuse it * Fixed EdgeControllerTest * Fixed testAssignEdgeToCustomerFromDifferentTenant test * testSyncEdge - make stable * Refacroting - update utils method name to pop* in EdgeControllerTest * testSyncEdge - fixed order and nubmer of edge events * testGetEdgeEvents - check by pop items, and not by index to improve stability on slow machines * testGetEdgeEvents - added check that list is empty * Removed test debug output * EntityServiceTest - Fixed compilation error after merge * Improve service layer event publisher to process each notification and validate in listener * Improve BaseAlarmService to send notification to listener * Fix asset-device notification action to send delete to all edges * Delete unnecessary usage of sendMsgToEdge * Improve processEntityNotification to be in sync with changed needed for PE * Pull request review - minor refactoring * Fix tests after review-refactoring * Refactor tests to be in sync with PE * Fixed repeated update - added check for old_edge_event table existance before migration * DeviceEdgeProcessor - do edgeSynchronizationManager as soon as possible to avoid unnecessary downlinks * BaseEdgeProcessor - refactoring and remove duplicate methods. Introduce EdgeEventType.isAllEdgesRelated * Organize imports * Improve Edge test: add sync completed message to await * Minor refactoring for EdgeProcessor notification: asset and device * EdgeEventSourcingListener - updated logging to avoid null pointer exception * BaseAlarmService - added check for alarm to avoid NPE. EdgeEventSourcingListener - added try/catch blocks * EdgeEventSourcingListener - fixed error message log level --------- Co-authored-by: Volodymyr Babak --- .../main/data/upgrade/3.5.1/schema_update.sql | 29 +- .../server/actors/ActorSystemContext.java | 3 +- .../ruleChain/RuleEngineComponentActor.java | 2 +- .../config/RateLimitProcessingFilter.java | 4 +- .../server/controller/AuthController.java | 9 +- .../server/controller/BaseController.java | 22 -- .../server/controller/EdgeController.java | 22 +- .../controller/WidgetTypeController.java | 6 - .../controller/plugin/TbWebSocketHandler.java | 2 +- .../ThingsboardErrorResponseHandler.java | 1 - .../service/action/EntityActionService.java | 4 - .../edge/DefaultEdgeNotificationService.java | 66 ++-- .../edge/EdgeEventSourcingListener.java | 158 ++++++++++ .../edge/rpc/processor/BaseEdgeProcessor.java | 88 +++--- .../processor/alarm/AlarmEdgeProcessor.java | 49 +-- .../processor/alarm/BaseAlarmProcessor.java | 12 +- .../processor/asset/AssetEdgeProcessor.java | 7 - .../asset/AssetProfileEdgeProcessor.java | 8 - .../dashboard/DashboardEdgeProcessor.java | 7 - .../processor/device/BaseDeviceProcessor.java | 6 +- .../processor/device/DeviceEdgeProcessor.java | 9 +- .../device/DeviceProfileEdgeProcessor.java | 7 - .../entityview/EntityViewEdgeProcessor.java | 7 - .../ota/OtaPackageEdgeProcessor.java | 7 - .../processor/queue/QueueEdgeProcessor.java | 6 - .../relation/BaseRelationProcessor.java | 16 +- .../rule/RuleChainEdgeProcessor.java | 7 - .../rpc/processor/user/UserEdgeProcessor.java | 7 +- .../widget/WidgetBundleEdgeProcessor.java | 7 - .../widget/WidgetTypeEdgeProcessor.java | 6 - .../DefaultTbNotificationEntityService.java | 139 +-------- .../entitiy/TbNotificationEntityService.java | 50 +-- .../alarm/DefaultTbAlarmCommentService.java | 5 +- .../entitiy/alarm/DefaultTbAlarmService.java | 34 +- .../entitiy/asset/DefaultTbAssetService.java | 36 +-- .../profile/DefaultTbAssetProfileService.java | 11 +- .../customer/DefaultTbCustomerService.java | 15 +- .../dashboard/DefaultTbDashboardService.java | 49 ++- .../device/DefaultTbDeviceService.java | 32 +- .../DefaultTbDeviceProfileService.java | 11 +- .../entitiy/edge/DefaultTbEdgeService.java | 8 +- .../DefaultTbEntityRelationService.java | 21 +- .../DefaultTbEntityViewService.java | 67 ++-- .../ota/DefaultTbOtaPackageService.java | 19 +- .../entitiy/queue/DefaultTbQueueService.java | 5 - .../entitiy/user/DefaultUserService.java | 11 +- .../bundle/DefaultWidgetsBundleService.java | 11 +- .../DefaultSystemDataLoaderService.java | 2 +- .../service/mail/DefaultMailService.java | 1 - .../queue/DefaultTbClusterService.java | 8 - .../queue/DefaultTbCoreConsumerService.java | 4 +- .../rule/DefaultTbRuleChainService.java | 32 +- .../DefaultEntitiesExportImportService.java | 8 +- .../impl/AssetProfileImportService.java | 4 +- .../impl/BaseEntityImportService.java | 8 +- .../impl/DeviceProfileImportService.java | 4 +- .../impl/RuleChainImportService.java | 5 +- .../impl/WidgetsBundleImportService.java | 9 - .../DefaultEntitiesVersionControlService.java | 8 +- .../DefaultAlarmSubscriptionService.java | 4 +- .../server/utils/LwM2mObjectModelUtils.java | 2 - .../controller/AbstractNotifyEntityTest.java | 19 +- .../server/controller/AbstractWebTest.java | 18 +- .../controller/AlarmControllerTest.java | 29 +- .../controller/AssetControllerTest.java | 91 +++--- .../AssetProfileControllerTest.java | 4 +- .../controller/CustomerControllerTest.java | 12 +- .../controller/DashboardControllerTest.java | 37 ++- .../controller/DeviceControllerTest.java | 47 +-- .../DeviceProfileControllerTest.java | 4 +- .../server/controller/EdgeControllerTest.java | 294 ++++++++++++------ .../controller/EdgeEventControllerTest.java | 64 ++-- .../controller/EntityViewControllerTest.java | 32 +- .../controller/OtaPackageControllerTest.java | 2 +- .../controller/RuleChainControllerTest.java | 20 +- .../server/controller/UserControllerTest.java | 8 +- .../server/edge/AbstractEdgeTest.java | 109 +++---- .../server/edge/AssetEdgeTest.java | 5 +- .../server/edge/CustomerEdgeTest.java | 17 +- .../server/edge/DashboardEdgeTest.java | 4 +- .../server/edge/DeviceEdgeTest.java | 16 +- .../server/edge/EntityViewEdgeTest.java | 4 +- .../server/edge/RuleChainEdgeTest.java | 31 +- .../server/edge/TelemetryEdgeTest.java | 2 +- .../thingsboard/server/edge/UserEdgeTest.java | 60 ++-- .../server/edge/imitator/EdgeImitator.java | 13 +- .../provision/DeviceProvisionServiceTest.java | 2 - .../alarm/DefaultTbAlarmServiceTest.java | 17 +- .../DefaultTbAlarmCommentServiceTest.java | 5 +- .../server/cluster/TbClusterService.java | 2 - .../dao/edge/EdgeSynchronizationManager.java | 23 ++ .../server/dao/user/UserService.java | 2 +- .../common/data/edge/EdgeEventType.java | 47 +-- .../server/dao/alarm/BaseAlarmService.java | 45 ++- .../dao/asset/AssetProfileServiceImpl.java | 6 +- .../server/dao/asset/BaseAssetService.java | 11 + .../dao/customer/CustomerServiceImpl.java | 7 +- .../dao/dashboard/DashboardServiceImpl.java | 11 + .../device/DeviceCredentialsServiceImpl.java | 5 + .../dao/device/DeviceProfileServiceImpl.java | 5 + .../server/dao/device/DeviceServiceImpl.java | 12 +- .../DefaultEdgeSynchronizationManager.java | 34 ++ .../server/dao/edge/EdgeServiceImpl.java | 10 +- .../entity/AbstractCachedEntityService.java | 4 - .../dao/entity/AbstractEntityService.java | 7 +- .../dao/entityview/EntityViewServiceImpl.java | 13 +- .../dao/eventsourcing/ActionEntityEvent.java | 33 ++ .../dao/eventsourcing/DeleteEntityEvent.java | 31 ++ .../eventsourcing/RelationActionEvent.java | 28 ++ .../dao/eventsourcing/SaveEntityEvent.java | 30 ++ .../server/dao/ota/BaseOtaPackageService.java | 9 +- .../server/dao/queue/BaseQueueService.java | 8 +- .../dao/relation/BaseRelationService.java | 20 +- .../server/dao/rule/BaseRuleChainService.java | 18 +- .../server/dao/user/UserServiceImpl.java | 34 +- .../dao/widget/WidgetTypeServiceImpl.java | 13 +- .../dao/widget/WidgetsBundleServiceImpl.java | 12 +- .../dao/service/AlarmCommentServiceTest.java | 3 +- .../server/dao/service/AlarmServiceTest.java | 5 +- .../server/dao/service/EntityServiceTest.java | 2 +- .../server/dao/service/TenantServiceTest.java | 2 +- .../server/dao/service/UserServiceTest.java | 30 +- 122 files changed, 1524 insertions(+), 1171 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java create mode 100644 common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeSynchronizationManager.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/edge/DefaultEdgeSynchronizationManager.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/eventsourcing/ActionEntityEvent.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/eventsourcing/DeleteEntityEvent.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/eventsourcing/RelationActionEvent.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java diff --git a/application/src/main/data/upgrade/3.5.1/schema_update.sql b/application/src/main/data/upgrade/3.5.1/schema_update.sql index 281a7fcbfa..c8edf45cff 100644 --- a/application/src/main/data/upgrade/3.5.1/schema_update.sql +++ b/application/src/main/data/upgrade/3.5.1/schema_update.sql @@ -99,19 +99,22 @@ DECLARE p RECORD; partition_end_ts BIGINT; BEGIN - FOR p IN SELECT DISTINCT (created_time - created_time % partition_size_ms) AS partition_ts FROM old_edge_event - WHERE created_time >= start_time_ms AND created_time < end_time_ms - LOOP - partition_end_ts = p.partition_ts + partition_size_ms; - RAISE NOTICE '[edge_event] Partition to create : [%-%]', p.partition_ts, partition_end_ts; - EXECUTE format('CREATE TABLE IF NOT EXISTS edge_event_%s PARTITION OF edge_event ' || - 'FOR VALUES FROM ( %s ) TO ( %s )', p.partition_ts, p.partition_ts, partition_end_ts); - END LOOP; - - INSERT INTO edge_event (id, created_time, edge_id, edge_event_type, edge_event_uid, entity_id, edge_event_action, body, tenant_id, ts) - SELECT id, created_time, edge_id, edge_event_type, edge_event_uid, entity_id, edge_event_action, body, tenant_id, ts - FROM old_edge_event - WHERE created_time >= start_time_ms AND created_time < end_time_ms; + IF (SELECT exists(SELECT FROM pg_tables WHERE tablename = 'old_edge_event')) THEN + FOR p IN SELECT DISTINCT (created_time - created_time % partition_size_ms) AS partition_ts FROM old_edge_event + WHERE created_time >= start_time_ms AND created_time < end_time_ms + LOOP + partition_end_ts = p.partition_ts + partition_size_ms; + RAISE NOTICE '[edge_event] Partition to create : [%-%]', p.partition_ts, partition_end_ts; + EXECUTE format('CREATE TABLE IF NOT EXISTS edge_event_%s PARTITION OF edge_event ' || + 'FOR VALUES FROM ( %s ) TO ( %s )', p.partition_ts, p.partition_ts, partition_end_ts); + END LOOP; + INSERT INTO edge_event (id, created_time, edge_id, edge_event_type, edge_event_uid, entity_id, edge_event_action, body, tenant_id, ts) + SELECT id, created_time, edge_id, edge_event_type, edge_event_uid, entity_id, edge_event_action, body, tenant_id, ts + FROM old_edge_event + WHERE created_time >= start_time_ms AND created_time < end_time_ms; + ELSE + RAISE NOTICE 'Table old_edge_event does not exists, skipping migration'; + END IF; END; $$; -- EDGE EVENTS MIGRATION END diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index fc822ce226..f82db6ebe7 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -48,6 +48,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.tools.TbRateLimits; @@ -90,7 +91,6 @@ import org.thingsboard.server.dao.widget.WidgetsBundleService; import org.thingsboard.server.queue.discovery.DiscoveryService; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; -import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.component.ComponentDiscoveryService; @@ -115,7 +115,6 @@ import org.thingsboard.server.service.transport.TbCoreToTransportService; import javax.annotation.Nullable; import javax.annotation.PostConstruct; -import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.concurrent.ConcurrentHashMap; diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java index 42a78b7965..dc7529200e 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleEngineComponentActor.java @@ -22,9 +22,9 @@ import org.thingsboard.server.actors.shared.ComponentMsgProcessor; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventTrigger; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.msg.TbActorStopReason; -import org.thingsboard.server.common.data.notification.rule.trigger.RuleEngineComponentLifecycleEventTrigger; public abstract class RuleEngineComponentActor> extends ComponentActor { diff --git a/application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java b/application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java index 2ecc8590b8..66c1c9081d 100644 --- a/application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java +++ b/application/src/main/java/org/thingsboard/server/config/RateLimitProcessingFilter.java @@ -24,10 +24,10 @@ import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.exception.TenantProfileNotFoundException; -import org.thingsboard.server.common.msg.tools.TbRateLimitsException; -import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; import org.thingsboard.server.common.data.limit.LimitedApi; +import org.thingsboard.server.common.msg.tools.TbRateLimitsException; import org.thingsboard.server.dao.util.limits.RateLimitService; +import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; import org.thingsboard.server.service.security.model.SecurityUser; import javax.servlet.FilterChain; diff --git a/application/src/main/java/org/thingsboard/server/controller/AuthController.java b/application/src/main/java/org/thingsboard/server/controller/AuthController.java index 4512334d61..ac024093c6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AuthController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AuthController.java @@ -38,19 +38,18 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent; import org.thingsboard.server.common.data.security.event.UserSessionInvalidationEvent; import org.thingsboard.server.common.data.security.model.JwtPair; import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; -import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; +import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.auth.rest.RestAuthenticationDetails; import org.thingsboard.server.service.security.model.ActivateUserRequest; import org.thingsboard.server.service.security.model.ChangePasswordRequest; @@ -123,8 +122,6 @@ public class AuthController extends BaseController { userCredentials.setPassword(passwordEncoder.encode(newPassword)); userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials); - sendEntityNotificationMsg(getTenantId(), userCredentials.getUserId(), EdgeEventActionType.CREDENTIALS_UPDATED); - eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(securityUser.getId())); ObjectNode response = JacksonUtil.newObjectNode(); response.put("token", tokenFactory.createAccessJwtToken(securityUser).getToken()); @@ -259,8 +256,6 @@ public class AuthController extends BaseController { } } - sendEntityNotificationMsg(user.getTenantId(), user.getId(), EdgeEventActionType.CREDENTIALS_UPDATED); - return tokenFactory.createTokenPair(securityUser); } diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 68a987a0bc..0af55d7c00 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -60,8 +60,6 @@ import org.thingsboard.server.common.data.asset.AssetInfo; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; -import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.edge.EdgeInfo; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; @@ -142,8 +140,6 @@ import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.action.EntityActionService; import org.thingsboard.server.service.component.ComponentDiscoveryService; -import org.thingsboard.server.service.edge.instructions.EdgeInstallService; -import org.thingsboard.server.service.edge.rpc.EdgeRpcService; import org.thingsboard.server.service.entitiy.TbNotificationEntityService; import org.thingsboard.server.service.entitiy.user.TbUserSettingsService; import org.thingsboard.server.service.ota.OtaPackageStateService; @@ -301,12 +297,6 @@ public abstract class BaseController { @Autowired(required = false) protected EdgeService edgeService; - @Autowired(required = false) - protected EdgeRpcService edgeRpcService; - - @Autowired(required = false) - protected EdgeInstallService edgeInstallService; - @Autowired protected TbNotificationEntityService notificationEntityService; @@ -824,18 +814,6 @@ public abstract class BaseController { } } - protected void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action) { - sendNotificationMsgToEdge(tenantId, null, entityId, null, null, action); - } - - protected void sendEntityAssignToEdgeNotificationMsg(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) { - sendNotificationMsgToEdge(tenantId, edgeId, entityId, null, null, action); - } - - private void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) { - tbClusterService.sendNotificationMsgToEdge(tenantId, edgeId, entityId, body, type, action); - } - protected void processDashboardIdFromAdditionalInfo(ObjectNode additionalInfo, String requiredFields) throws ThingsboardException { String dashboardId = additionalInfo.has(requiredFields) ? additionalInfo.get(requiredFields).asText() : null; if (dashboardId != null && !dashboardId.equals("null")) { diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java index 9a021643cc..a50f9c7658 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -59,6 +59,8 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.EdgeBulkImportService; +import org.thingsboard.server.service.edge.instructions.EdgeInstallService; +import org.thingsboard.server.service.edge.rpc.EdgeRpcService; import org.thingsboard.server.service.entitiy.edge.TbEdgeService; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; @@ -67,6 +69,7 @@ import org.thingsboard.server.service.security.permission.Resource; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @@ -94,8 +97,11 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI @RequestMapping("/api") @RequiredArgsConstructor public class EdgeController extends BaseController { + private final EdgeBulkImportService edgeBulkImportService; private final TbEdgeService tbEdgeService; + private final Optional edgeRpcServiceOpt; + private final Optional edgeInstallServiceOpt; public static final String EDGE_ID = "edgeId"; public static final String EDGE_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the edge is owned by the same tenant. " + @@ -497,13 +503,13 @@ public class EdgeController extends BaseController { @PathVariable("edgeId") String strEdgeId) throws ThingsboardException { checkParameter("edgeId", strEdgeId); final DeferredResult response = new DeferredResult<>(); - if (isEdgesEnabled()) { + if (isEdgesEnabled() && edgeRpcServiceOpt.isPresent()) { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); edgeId = checkNotNull(edgeId); SecurityUser user = getCurrentUser(); TenantId tenantId = user.getTenantId(); ToEdgeSyncRequest request = new ToEdgeSyncRequest(UUID.randomUUID(), tenantId, edgeId); - edgeRpcService.processSyncRequest(request, fromEdgeSyncResponse -> reply(response, fromEdgeSyncResponse)); + edgeRpcServiceOpt.get().processSyncRequest(request, fromEdgeSyncResponse -> reply(response, fromEdgeSyncResponse)); } else { throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL); } @@ -557,9 +563,13 @@ public class EdgeController extends BaseController { @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("edgeId") String strEdgeId, HttpServletRequest request) throws ThingsboardException { - EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); - edgeId = checkNotNull(edgeId); - Edge edge = checkEdgeId(edgeId, Operation.READ); - return checkNotNull(edgeInstallService.getDockerInstallInstructions(getTenantId(), edge, request)); + if (isEdgesEnabled() && edgeInstallServiceOpt.isPresent()) { + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); + edgeId = checkNotNull(edgeId); + Edge edge = checkEdgeId(edgeId, Operation.READ); + return checkNotNull(edgeInstallServiceOpt.get().getDockerInstallInstructions(getTenantId(), edge, request)); + } else { + throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL); + } } } diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java index d1ecd0441a..9a727523d7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -28,7 +28,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; @@ -107,9 +106,6 @@ public class WidgetTypeController extends AutoCommitController { } } - sendEntityNotificationMsg(getTenantId(), savedWidgetTypeDetails.getId(), - widgetTypeDetails.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); - return checkNotNull(savedWidgetTypeDetails); } @@ -133,8 +129,6 @@ public class WidgetTypeController extends AutoCommitController { autoCommit(currentUser, widgetsBundle.getId()); } } - - sendEntityNotificationMsg(getTenantId(), widgetTypeId, EdgeEventActionType.DELETED); } @ApiOperation(value = "Get all Widget types for specified Bundle (getBundleWidgetTypes)", diff --git a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java index 8a68dc21cb..e1f20be0e4 100644 --- a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java +++ b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java @@ -33,10 +33,10 @@ import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.config.WebSocketConfiguration; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.model.SecurityUser; diff --git a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java index ed641c2d4f..0cd581b2e5 100644 --- a/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java +++ b/application/src/main/java/org/thingsboard/server/exception/ThingsboardErrorResponseHandler.java @@ -16,7 +16,6 @@ package org.thingsboard.server.exception; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; diff --git a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java index 6c855a89c9..99884b013d 100644 --- a/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java +++ b/application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java @@ -237,10 +237,6 @@ public class EntityActionService { auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo); } - public void sendEntityNotificationMsgToEdge(TenantId tenantId, EntityId entityId, EdgeEventActionType action) { - tbClusterService.sendNotificationMsgToEdge(tenantId, null, entityId, null, null, action); - } - private T extractParameter(Class clazz, int index, Object... additionalInfo) { T result = null; if (additionalInfo != null && additionalInfo.length > index) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java index 110760acbc..1f38f83492 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.edge; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; @@ -23,22 +22,18 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.checkerframework.checker.nullness.qual.Nullable; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; -import org.thingsboard.server.cluster.TbClusterService; -import org.thingsboard.server.common.data.EdgeUtils; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.edge.EdgeEvent; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventType; -import org.thingsboard.server.common.data.id.EdgeId; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.queue.TbCallback; -import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeService; +import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.alarm.AlarmEdgeProcessor; @@ -74,12 +69,6 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { @Autowired private EdgeService edgeService; - @Autowired - private EdgeEventService edgeEventService; - - @Autowired - private TbClusterService clusterService; - @Autowired private EdgeProcessor edgeProcessor; @@ -128,6 +117,9 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { @Autowired private RelationEdgeProcessor relationProcessor; + @Autowired + protected ApplicationEventPublisher eventPublisher; + private ExecutorService dbCallBackExecutor; @PostConstruct @@ -143,32 +135,16 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { } @Override - public Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws Exception { + public Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) { edge.setRootRuleChainId(ruleChainId); Edge savedEdge = edgeService.saveEdge(edge); ObjectNode isRootBody = JacksonUtil.newObjectNode(); isRootBody.put(EDGE_IS_ROOT_BODY_KEY, Boolean.TRUE); - saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, EdgeEventActionType.UPDATED, ruleChainId, isRootBody).get(); + eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).edgeId(edge.getId()).entityId(ruleChainId) + .body(JacksonUtil.toString(isRootBody)).actionType(ActionType.UPDATED).build()); return savedEdge; } - private ListenableFuture saveEdgeEvent(TenantId tenantId, - EdgeId edgeId, - EdgeEventType type, - EdgeEventActionType action, - EntityId entityId, - JsonNode body) { - log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]", - tenantId, edgeId, type, action, entityId, body); - - EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body); - - return Futures.transform(edgeEventService.saveAsync(edgeEvent), unused -> { - clusterService.onEdgeEventUpdate(tenantId, edgeId); - return null; - }, dbCallBackExecutor); - } - @Override public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { log.debug("Pushing notification to edge {}", edgeNotificationMsg); @@ -181,43 +157,43 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { future = edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg); break; case ASSET: - future = assetProcessor.processAssetNotification(tenantId, edgeNotificationMsg); + future = assetProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case DEVICE: - future = deviceProcessor.processDeviceNotification(tenantId, edgeNotificationMsg); + future = deviceProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case ENTITY_VIEW: - future = entityViewProcessor.processEntityViewNotification(tenantId, edgeNotificationMsg); + future = entityViewProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case DASHBOARD: - future = dashboardProcessor.processDashboardNotification(tenantId, edgeNotificationMsg); + future = dashboardProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case RULE_CHAIN: - future = ruleChainProcessor.processRuleChainNotification(tenantId, edgeNotificationMsg); + future = ruleChainProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case USER: - future = userProcessor.processUserNotification(tenantId, edgeNotificationMsg); + future = userProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case CUSTOMER: future = customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg); break; case DEVICE_PROFILE: - future = deviceProfileProcessor.processDeviceProfileNotification(tenantId, edgeNotificationMsg); + future = deviceProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case ASSET_PROFILE: - future = assetProfileProcessor.processAssetProfileNotification(tenantId, edgeNotificationMsg); + future = assetProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case OTA_PACKAGE: - future = otaPackageProcessor.processOtaPackageNotification(tenantId, edgeNotificationMsg); + future = otaPackageProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case WIDGETS_BUNDLE: - future = widgetBundleProcessor.processWidgetsBundleNotification(tenantId, edgeNotificationMsg); + future = widgetBundleProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case WIDGET_TYPE: - future = widgetTypeProcessor.processWidgetTypeNotification(tenantId, edgeNotificationMsg); + future = widgetTypeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case QUEUE: - future = queueProcessor.processQueueNotification(tenantId, edgeNotificationMsg); + future = queueProcessor.processEntityNotification(tenantId, edgeNotificationMsg); break; case ALARM: future = alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java new file mode 100644 index 0000000000..43b05094a4 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java @@ -0,0 +1,158 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.edge; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionalEventListener; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.OtaPackageInfo; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; +import org.thingsboard.server.common.data.edge.EdgeEventActionType; +import org.thingsboard.server.common.data.edge.EdgeEventType; +import org.thingsboard.server.common.data.relation.EntityRelation; +import org.thingsboard.server.common.data.relation.RelationTypeGroup; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.dao.edge.EdgeSynchronizationManager; +import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.eventsourcing.RelationActionEvent; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; + +import javax.annotation.PostConstruct; + +import static org.thingsboard.server.service.entitiy.DefaultTbNotificationEntityService.edgeTypeByActionType; + + +/** + * This event listener does not support async event processing because relay on ThreadLocal + * Another possible approach is to implement a special annotation and a bunch of classes similar to TransactionalApplicationListener + * This class is the simplest approach to maintain edge synchronization within the single class. + *

+ * For async event publishers, you have to decide whether publish event on creating async task in the same thread where dao method called + * @Autowired + * EdgeEventSynchronizationManager edgeSynchronizationManager + * ... + * //some async write action make future + * if (!edgeSynchronizationManager.isSync()) { + * future.addCallback(eventPublisher.publishEvent(...)) + * } + * */ +@Component +@RequiredArgsConstructor +@Slf4j +public class EdgeEventSourcingListener { + + private final TbClusterService tbClusterService; + private final EdgeSynchronizationManager edgeSynchronizationManager; + + @PostConstruct + public void init() { + log.info("EdgeEventSourcingListener initiated"); + } + + @TransactionalEventListener(fallbackExecution = true) + public void handleEvent(SaveEntityEvent event) { + if (edgeSynchronizationManager.isSync()) { + return; + } + try { + if (!isValidEdgeEventEntity(event.getEntity())) { + return; + } + log.trace("[{}] SaveEntityEvent called: {}", event.getTenantId(), event); + EdgeEventActionType action = Boolean.TRUE.equals(event.getAdded()) ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED; + tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), null, event.getEntityId(), + null, null, action); + } catch (Exception e) { + log.error("[{}] failed to process SaveEntityEvent: {}", event.getTenantId(), event); + } + } + + @TransactionalEventListener(fallbackExecution = true) + public void handleEvent(DeleteEntityEvent event) { + if (edgeSynchronizationManager.isSync()) { + return; + } + try { + log.trace("[{}] DeleteEntityEvent called: {}", event.getTenantId(), event); + tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), event.getEdgeId(), event.getEntityId(), + JacksonUtil.toString(event.getEntity()), null, EdgeEventActionType.DELETED); + } catch (Exception e) { + log.error("[{}] failed to process DeleteEntityEvent: {}", event.getTenantId(), event); + } + } + + @TransactionalEventListener(fallbackExecution = true) + public void handleEvent(ActionEntityEvent event) { + if (edgeSynchronizationManager.isSync()) { + return; + } + try { + log.trace("[{}] ActionEntityEvent called: {}", event.getTenantId(), event); + tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), event.getEdgeId(), event.getEntityId(), + event.getBody(), null, edgeTypeByActionType(event.getActionType())); + } catch (Exception e) { + log.error("[{}] failed to process ActionEntityEvent: {}", event.getTenantId(), event); + } + } + + @TransactionalEventListener(fallbackExecution = true) + public void handleEvent(RelationActionEvent event) { + if (edgeSynchronizationManager.isSync()) { + return; + } + try { + EntityRelation relation = event.getRelation(); + if (relation == null) { + log.trace("[{}] skipping RelationActionEvent event in case relation is null: {}", event.getTenantId(), event); + return; + } + if (!RelationTypeGroup.COMMON.equals(relation.getTypeGroup())) { + log.trace("[{}] skipping RelationActionEvent event in case NOT COMMON relation type group: {}", event.getTenantId(), event); + return; + } + log.trace("[{}] RelationActionEvent called: {}", event.getTenantId(), event); + tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), null, null, + JacksonUtil.toString(relation), EdgeEventType.RELATION, edgeTypeByActionType(event.getActionType())); + } catch (Exception e) { + log.error("[{}] failed to process RelationActionEvent: {}", event.getTenantId(), event); + } + } + + private boolean isValidEdgeEventEntity(Object entity) { + if (entity instanceof OtaPackageInfo) { + OtaPackageInfo otaPackageInfo = (OtaPackageInfo) entity; + return otaPackageInfo.hasUrl() || otaPackageInfo.isHasData(); + } else if (entity instanceof RuleChain) { + RuleChain ruleChain = (RuleChain) entity; + return RuleChainType.EDGE.equals(ruleChain.getType()); + } else if (entity instanceof User) { + User user = (User) entity; + return !Authority.SYS_ADMIN.equals(user.getAuthority()); + } else if (entity instanceof AlarmApiCallResult) { + AlarmApiCallResult alarmApiCallResult = (AlarmApiCallResult) entity; + return alarmApiCallResult.isModified(); + } + // Default: If the entity doesn't match any of the conditions, consider it as valid. + return true; + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java index ac7c791338..56f4f06fa3 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EdgeUtils; @@ -55,6 +56,7 @@ import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeService; +import org.thingsboard.server.dao.edge.EdgeSynchronizationManager; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.queue.QueueService; @@ -249,15 +251,18 @@ public abstract class BaseEdgeProcessor { @Autowired protected QueueMsgConstructor queueMsgConstructor; + @Autowired + protected EdgeSynchronizationManager edgeSynchronizationManager; + @Autowired protected DbCallbackExecutorService dbCallbackExecutorService; protected ListenableFuture saveEdgeEvent(TenantId tenantId, - EdgeId edgeId, - EdgeEventType type, - EdgeEventActionType action, - EntityId entityId, - JsonNode body) { + EdgeId edgeId, + EdgeEventType type, + EdgeEventActionType action, + EntityId entityId, + JsonNode body) { log.debug("Pushing event to edge queue. tenantId [{}], edgeId [{}], type[{}], " + "action [{}], entityId [{}], body [{}]", tenantId, edgeId, type, action, entityId, body); @@ -288,7 +293,7 @@ public abstract class BaseEdgeProcessor { return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); } - protected List> processActionForAllEdgesByTenantId(TenantId tenantId, + private List> processActionForAllEdgesByTenantId(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId, @@ -340,36 +345,46 @@ public abstract class BaseEdgeProcessor { } } - protected ListenableFuture processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); + public ListenableFuture processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); - EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, - new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); - EdgeId edgeId = safeGetEdgeId(edgeNotificationMsg); - switch (actionType) { - case ADDED: - case UPDATED: - case CREDENTIALS_UPDATED: - case ASSIGNED_TO_CUSTOMER: - case UNASSIGNED_FROM_CUSTOMER: - case DELETED: - if (edgeId != null) { - return saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); - } else { - return pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType); - } - case ASSIGNED_TO_EDGE: - case UNASSIGNED_FROM_EDGE: - ListenableFuture future = saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); - return Futures.transformAsync(future, unused -> { - if (type.equals(EdgeEventType.RULE_CHAIN)) { - return updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId); + EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); + EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); + if (type.isAllEdgesRelated()) { + return processEntityNotificationForAllEdges(tenantId, type, actionType, entityId); + } else { + JsonNode body = JacksonUtil.toJsonNode(edgeNotificationMsg.getBody()); + EdgeId edgeId = safeGetEdgeId(edgeNotificationMsg); + switch (actionType) { + case UPDATED: + case CREDENTIALS_UPDATED: + case ASSIGNED_TO_CUSTOMER: + case UNASSIGNED_FROM_CUSTOMER: + if (edgeId != null) { + return saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, body); } else { - return Futures.immediateFuture(null); + return processNotificationToRelatedEdges(tenantId, entityId, type, actionType); } - }, dbCallbackExecutorService); - default: - return Futures.immediateFuture(null); + case DELETED: + EdgeEventActionType deleted = EdgeEventActionType.DELETED; + if (edgeId != null) { + return saveEdgeEvent(tenantId, edgeId, type, deleted, entityId, body); + } else { + return Futures.transform(Futures.allAsList(processActionForAllEdgesByTenantId(tenantId, type, deleted, entityId, body)), + voids -> null, dbCallbackExecutorService); + } + case ASSIGNED_TO_EDGE: + case UNASSIGNED_FROM_EDGE: + ListenableFuture future = saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, body); + return Futures.transformAsync(future, unused -> { + if (type.equals(EdgeEventType.RULE_CHAIN)) { + return updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId); + } else { + return Futures.immediateFuture(null); + } + }, dbCallbackExecutorService); + default: + return Futures.immediateFuture(null); + } } } @@ -381,7 +396,7 @@ public abstract class BaseEdgeProcessor { } } - private ListenableFuture pushNotificationToAllRelatedEdges(TenantId tenantId, EntityId entityId, EdgeEventType type, EdgeEventActionType actionType) { + private ListenableFuture processNotificationToRelatedEdges(TenantId tenantId, EntityId entityId, EdgeEventType type, EdgeEventActionType actionType) { PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); PageData pageData; List> futures = new ArrayList<>(); @@ -432,10 +447,7 @@ public abstract class BaseEdgeProcessor { return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); } - protected ListenableFuture processEntityNotificationForAllEdges(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); - EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); - EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); + private ListenableFuture processEntityNotificationForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) { switch (actionType) { case ADDED: case UPDATED: diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java index 189d69e68d..0b86352c02 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/AlarmEdgeProcessor.java @@ -16,6 +16,7 @@ package org.thingsboard.server.service.edge.rpc.processor.alarm; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; @@ -28,6 +29,7 @@ import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -62,9 +64,9 @@ public class AlarmEdgeProcessor extends BaseAlarmProcessor { AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); switch (actionType) { case DELETED: - EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB())); Alarm deletedAlarm = JacksonUtil.OBJECT_MAPPER.readValue(edgeNotificationMsg.getBody(), Alarm.class); - return saveEdgeEvent(tenantId, edgeId, EdgeEventType.ALARM, actionType, alarmId, JacksonUtil.OBJECT_MAPPER.valueToTree(deletedAlarm)); + List> delFutures = pushEventToAllRelatedEdges(tenantId, deletedAlarm.getOriginator(), alarmId, actionType, JacksonUtil.OBJECT_MAPPER.valueToTree(deletedAlarm)); + return Futures.transform(Futures.allAsList(delFutures), voids -> null, dbCallbackExecutorService); default: ListenableFuture alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId); return Futures.transformAsync(alarmFuture, alarm -> { @@ -75,28 +77,33 @@ public class AlarmEdgeProcessor extends BaseAlarmProcessor { if (type == null) { return Futures.immediateFuture(null); } - PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); - PageData pageData; - List> futures = new ArrayList<>(); - do { - pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator(), pageLink); - if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { - for (EdgeId relatedEdgeId : pageData.getData()) { - futures.add(saveEdgeEvent(tenantId, - relatedEdgeId, - EdgeEventType.ALARM, - EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()), - alarmId, - null)); - } - if (pageData.hasNext()) { - pageLink = pageLink.nextPageLink(); - } - } - } while (pageData != null && pageData.hasNext()); + List> futures = pushEventToAllRelatedEdges(tenantId, alarm.getOriginator(), alarmId, actionType, null); return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService); }, dbCallbackExecutorService); } } + private List> pushEventToAllRelatedEdges(TenantId tenantId, EntityId originatorId, AlarmId alarmId, EdgeEventActionType actionType, JsonNode body) { + PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); + PageData pageData; + List> futures = new ArrayList<>(); + do { + pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, originatorId, pageLink); + if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { + for (EdgeId relatedEdgeId : pageData.getData()) { + futures.add(saveEdgeEvent(tenantId, + relatedEdgeId, + EdgeEventType.ALARM, + actionType, + alarmId, + body)); + } + if (pageData.hasNext()) { + pageLink = pageLink.nextPageLink(); + } + } + } while (pageData != null && pageData.hasNext()); + return futures; + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java index be64f475a2..fbe141ab32 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/alarm/BaseAlarmProcessor.java @@ -49,6 +49,7 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor { return Futures.immediateFuture(null); } try { + edgeSynchronizationManager.getSync().set(true); switch (alarmUpdateMsg.getMsgType()) { case ENTITY_CREATED_RPC_MESSAGE: case ENTITY_UPDATED_RPC_MESSAGE: @@ -72,26 +73,26 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor { } else { alarmService.updateAlarm(AlarmUpdateRequest.fromAlarm(alarm)); } - return Futures.immediateFuture(null); + break; case ALARM_ACK_RPC_MESSAGE: Alarm alarmToAck = alarmService.findAlarmById(tenantId, alarmId); if (alarmToAck != null) { alarmService.acknowledgeAlarm(tenantId, alarmId, alarmUpdateMsg.getAckTs()); } - return Futures.immediateFuture(null); + break; case ALARM_CLEAR_RPC_MESSAGE: Alarm alarmToClear = alarmService.findAlarmById(tenantId, alarmId); if (alarmToClear != null) { alarmService.clearAlarm(tenantId, alarmId, alarmUpdateMsg.getClearTs(), JacksonUtil.OBJECT_MAPPER.readTree(alarmUpdateMsg.getDetails())); } - return Futures.immediateFuture(null); + break; case ENTITY_DELETED_RPC_MESSAGE: Alarm alarmToDelete = alarmService.findAlarmById(tenantId, alarmId); if (alarmToDelete != null) { alarmService.delAlarm(tenantId, alarmId); } - return Futures.immediateFuture(null); + break; case UNRECOGNIZED: default: return handleUnsupportedMsgType(alarmUpdateMsg.getMsgType()); @@ -99,7 +100,10 @@ public abstract class BaseAlarmProcessor extends BaseEdgeProcessor { } catch (Exception e) { log.error("[{}] Failed to process alarm update msg [{}]", tenantId, alarmUpdateMsg, e); return Futures.immediateFailedFuture(e); + } finally { + edgeSynchronizationManager.getSync().remove(); } + return Futures.immediateFuture(null); } private EntityId getAlarmOriginator(TenantId tenantId, String entityName, EntityType entityType) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java index 2fb7320219..d7824a7467 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetEdgeProcessor.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.edge.rpc.processor.asset; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EdgeUtils; @@ -23,11 +22,9 @@ import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.AssetId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -72,8 +69,4 @@ public class AssetEdgeProcessor extends BaseEdgeProcessor { } return downlinkMsg; } - - public ListenableFuture processAssetNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotification(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java index 51c42e5764..ec0e0b9761 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/asset/AssetProfileEdgeProcessor.java @@ -15,18 +15,15 @@ */ package org.thingsboard.server.service.edge.rpc.processor.asset; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.AssetProfileId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -63,9 +60,4 @@ public class AssetProfileEdgeProcessor extends BaseEdgeProcessor { } return downlinkMsg; } - - public ListenableFuture processAssetProfileNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); - } - } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java index 9651609bd3..14f566db0a 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/dashboard/DashboardEdgeProcessor.java @@ -15,18 +15,15 @@ */ package org.thingsboard.server.service.edge.rpc.processor.dashboard; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.DashboardId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -67,8 +64,4 @@ public class DashboardEdgeProcessor extends BaseEdgeProcessor { } return downlinkMsg; } - - public ListenableFuture processDashboardNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotification(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java index 742acdbcda..1421cf32c0 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/BaseDeviceProcessor.java @@ -97,7 +97,7 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor { deviceCredentials.setCredentialsId(StringUtils.randomAlphanumeric(20)); deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials); } - tbClusterService.onDeviceUpdated(savedDevice, created ? null : device, false); + tbClusterService.onDeviceUpdated(savedDevice, created ? null : device); } finally { deviceCreationLock.unlock(); } @@ -113,6 +113,8 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor { log.debug("Updating device credentials for device [{}]. New device credentials Id [{}], value [{}]", device.getName(), deviceCredentialsUpdateMsg.getCredentialsId(), deviceCredentialsUpdateMsg.getCredentialsValue()); try { + edgeSynchronizationManager.getSync().set(true); + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, device.getId()); deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceCredentialsUpdateMsg.getCredentialsType())); deviceCredentials.setCredentialsId(deviceCredentialsUpdateMsg.getCredentialsId()); @@ -123,6 +125,8 @@ public abstract class BaseDeviceProcessor extends BaseEdgeProcessor { log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]", device.getName(), deviceCredentialsUpdateMsg, e); throw new RuntimeException(e); + } finally { + edgeSynchronizationManager.getSync().remove(); } } else { log.warn("Can't find device by id [{}], deviceCredentialsUpdateMsg [{}]", deviceId, deviceCredentialsUpdateMsg); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java index 67194cb618..d083c5b16f 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceEdgeProcessor.java @@ -54,7 +54,6 @@ import org.thingsboard.server.gen.edge.v1.DeviceRpcCallMsg; import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.TbQueueCallback; import org.thingsboard.server.queue.TbQueueMsgMetadata; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -71,6 +70,8 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { log.trace("[{}] executing processDeviceMsgFromEdge [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName()); DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB())); try { + edgeSynchronizationManager.getSync().set(true); + switch (deviceUpdateMsg.getMsgType()) { case ENTITY_CREATED_RPC_MESSAGE: case ENTITY_UPDATED_RPC_MESSAGE: @@ -93,6 +94,8 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { } else { return Futures.immediateFailedFuture(e); } + } finally { + edgeSynchronizationManager.getSync().remove(); } } @@ -308,8 +311,4 @@ public class DeviceEdgeProcessor extends BaseDeviceProcessor { .addDeviceCredentialsRequestMsg(deviceCredentialsRequestMsg); return builder.build(); } - - public ListenableFuture processDeviceNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotification(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java index 5ddfecfdb1..c888ec2925 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/device/DeviceProfileEdgeProcessor.java @@ -15,18 +15,15 @@ */ package org.thingsboard.server.service.edge.rpc.processor.device; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.DeviceProfileId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -63,8 +60,4 @@ public class DeviceProfileEdgeProcessor extends BaseEdgeProcessor { } return downlinkMsg; } - - public ListenableFuture processDeviceProfileNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java index 29965fcc69..0964a434ba 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/entityview/EntityViewEdgeProcessor.java @@ -15,18 +15,15 @@ */ package org.thingsboard.server.service.edge.rpc.processor.entityview; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.EntityViewId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -67,8 +64,4 @@ public class EntityViewEdgeProcessor extends BaseEdgeProcessor { } return downlinkMsg; } - - public ListenableFuture processEntityViewNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotification(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java index 8206e0f1b0..fae6399e3a 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/ota/OtaPackageEdgeProcessor.java @@ -15,18 +15,15 @@ */ package org.thingsboard.server.service.edge.rpc.processor.ota; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.OtaPackageId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.OtaPackageUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -63,8 +60,4 @@ public class OtaPackageEdgeProcessor extends BaseEdgeProcessor { } return downlinkMsg; } - - public ListenableFuture processOtaPackageNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java index cbacaf9276..8562582940 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/queue/QueueEdgeProcessor.java @@ -15,18 +15,15 @@ */ package org.thingsboard.server.service.edge.rpc.processor.queue; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.QueueId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -64,7 +61,4 @@ public class QueueEdgeProcessor extends BaseEdgeProcessor { return downlinkMsg; } - public ListenableFuture processQueueNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java index df683bbbe2..9038cc9c33 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/relation/BaseRelationProcessor.java @@ -34,8 +34,9 @@ import java.util.UUID; public abstract class BaseRelationProcessor extends BaseEdgeProcessor { public ListenableFuture processRelationMsg(TenantId tenantId, RelationUpdateMsg relationUpdateMsg) { - log.trace("[{}] processRelationFromEdge [{}]", tenantId, relationUpdateMsg); + log.trace("[{}] processRelationMsg [{}]", tenantId, relationUpdateMsg); try { + edgeSynchronizationManager.getSync().set(true); EntityRelation entityRelation = new EntityRelation(); UUID fromUUID = new UUID(relationUpdateMsg.getFromIdMSB(), relationUpdateMsg.getFromIdLSB()); @@ -55,15 +56,15 @@ public abstract class BaseRelationProcessor extends BaseEdgeProcessor { case ENTITY_UPDATED_RPC_MESSAGE: if (isEntityExists(tenantId, entityRelation.getTo()) && isEntityExists(tenantId, entityRelation.getFrom())) { - return Futures.transform(relationService.saveRelationAsync(tenantId, entityRelation), - (result) -> null, dbCallbackExecutorService); + relationService.saveRelation(tenantId, entityRelation); + break; } else { log.warn("Skipping relating update msg because from/to entity doesn't exists on edge, {}", relationUpdateMsg); - return Futures.immediateFuture(null); + break; } case ENTITY_DELETED_RPC_MESSAGE: - return Futures.transform(relationService.deleteRelationAsync(tenantId, entityRelation), - (result) -> null, dbCallbackExecutorService); + relationService.deleteRelation(tenantId, entityRelation); + break; case UNRECOGNIZED: default: return handleUnsupportedMsgType(relationUpdateMsg.getMsgType()); @@ -71,6 +72,9 @@ public abstract class BaseRelationProcessor extends BaseEdgeProcessor { } catch (Exception e) { log.error("[{}] Failed to process relation update msg [{}]", tenantId, relationUpdateMsg, e); return Futures.immediateFailedFuture(e); + } finally { + edgeSynchronizationManager.getSync().remove(); } + return Futures.immediateFuture(null); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java index 69d4f7ef64..ba6fc1ef97 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/rule/RuleChainEdgeProcessor.java @@ -15,13 +15,11 @@ */ package org.thingsboard.server.service.edge.rpc.processor.rule; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.id.RuleChainId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; @@ -29,7 +27,6 @@ import org.thingsboard.server.gen.edge.v1.EdgeVersion; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -93,8 +90,4 @@ public class RuleChainEdgeProcessor extends BaseEdgeProcessor { } return downlinkMsg; } - - public ListenableFuture processRuleChainNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotification(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java index 9070686fd6..de40fdb1a3 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/user/UserEdgeProcessor.java @@ -15,19 +15,16 @@ */ package org.thingsboard.server.service.edge.rpc.processor.user; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.edge.EdgeEvent; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UserCredentialsUpdateMsg; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -67,11 +64,9 @@ public class UserEdgeProcessor extends BaseEdgeProcessor { .addUserCredentialsUpdateMsg(userCredentialsUpdateMsg) .build(); } + break; } return downlinkMsg; } - public ListenableFuture processUserNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java index a429816a31..d50e752fdf 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetBundleEdgeProcessor.java @@ -15,18 +15,15 @@ */ package org.thingsboard.server.service.edge.rpc.processor.widget; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.EdgeEvent; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.WidgetsBundleUpdateMsg; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -63,8 +60,4 @@ public class WidgetBundleEdgeProcessor extends BaseEdgeProcessor { } return downlinkMsg; } - - public ListenableFuture processWidgetsBundleNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java index 3caad57081..5171724439 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/widget/WidgetTypeEdgeProcessor.java @@ -15,18 +15,15 @@ */ package org.thingsboard.server.service.edge.rpc.processor.widget; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.EdgeEvent; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.gen.edge.v1.DownlinkMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; @@ -64,7 +61,4 @@ public class WidgetTypeEdgeProcessor extends BaseEdgeProcessor { return downlinkMsg; } - public ListenableFuture processWidgetTypeNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { - return processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java index 68b9cdecbb..f2465c9398 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java @@ -22,28 +22,20 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; -import org.thingsboard.server.common.data.alarm.Alarm; -import org.thingsboard.server.common.data.alarm.AlarmComment; -import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEventActionType; -import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.relation.EntityRelation; -import org.thingsboard.server.common.data.rule.RuleChain; -import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; @@ -51,8 +43,6 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.service.action.EntityActionService; import org.thingsboard.server.service.gateway_device.GatewayNotificationsService; -import java.util.List; - @Slf4j @Service @RequiredArgsConstructor @@ -98,54 +88,6 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } } - @Override - public void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, - CustomerId customerId, ActionType actionType, - List relatedEdgeIds, - User user, Object... additionalInfo) { - logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); - sendDeleteNotificationMsg(tenantId, entityId, relatedEdgeIds, null); - } - - @Override - public void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, CustomerId customerId, - List relatedEdgeIds, User user, String body, Object... additionalInfo) { - logEntityAction(tenantId, originatorId, alarm, customerId, ActionType.DELETED, user, additionalInfo); - sendAlarmDeleteNotificationMsg(tenantId, alarm, relatedEdgeIds, body); - } - - @Override - public void notifyDeleteRuleChain(TenantId tenantId, RuleChain ruleChain, List relatedEdgeIds, User user) { - RuleChainId ruleChainId = ruleChain.getId(); - logEntityAction(tenantId, ruleChainId, ruleChain, null, ActionType.DELETED, user, null, ruleChainId.toString()); - if (RuleChainType.EDGE.equals(ruleChain.getType())) { - sendDeleteNotificationMsg(tenantId, ruleChainId, relatedEdgeIds, null); - } - } - - @Override - public void notifySendMsgToEdgeService(TenantId tenantId, I entityId, EdgeEventActionType edgeEventActionType) { - sendEntityNotificationMsg(tenantId, entityId, edgeEventActionType); - } - - @Override - public void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId, - CustomerId customerId, E entity, - ActionType actionType, - User user, Object... additionalInfo) { - logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); - sendEntityNotificationMsg(tenantId, entityId, edgeTypeByActionType(actionType), JacksonUtil.toString(customerId)); - } - - @Override - public void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId, - CustomerId customerId, EdgeId edgeId, - E entity, ActionType actionType, - User user, Object... additionalInfo) { - logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); - sendEntityAssignToEdgeNotificationMsg(tenantId, edgeId, entityId, edgeTypeByActionType(actionType)); - } - @Override public void notifyCreateOrUpdateTenant(Tenant tenant, ComponentLifecycleEvent event) { tbClusterService.onTenantChange(tenant, null); @@ -168,18 +110,16 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS @Override public void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, - List relatedEdgeIds, User user, Object... additionalInfo) { + User user, Object... additionalInfo) { gatewayNotificationsService.onDeviceDeleted(device); tbClusterService.onDeviceDeleted(device, null); - - notifyDeleteEntity(tenantId, deviceId, device, customerId, ActionType.DELETED, relatedEdgeIds, user, additionalInfo); + logEntityAction(tenantId, deviceId, device, customerId, ActionType.DELETED, user, additionalInfo); } @Override public void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, DeviceCredentials deviceCredentials, User user) { tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(tenantId, deviceCredentials.getDeviceId(), deviceCredentials), null); - sendEntityNotificationMsg(tenantId, deviceId, EdgeEventActionType.CREDENTIALS_UPDATED); logEntityAction(tenantId, deviceId, device, customerId, ActionType.CREDENTIALS_UPDATED, user, deviceCredentials); } @@ -190,16 +130,6 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS pushAssignedFromNotification(tenant, newTenantId, device); } - @Override - public void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity, - CustomerId customerId, ActionType actionType, - User user, Object... additionalInfo) { - logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); - if (actionType == ActionType.UPDATED) { - sendEntityNotificationMsg(tenantId, entityId, EdgeEventActionType.UPDATED); - } - } - @Override public void notifyCreateOrUpdateOrDeleteEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType, User user, Object... additionalInfo) { @@ -222,65 +152,10 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS } @Override - public void notifyCreateOrUpdateAlarm(AlarmInfo alarm, ActionType actionType, User user, Object... additionalInfo) { - logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), actionType, user, additionalInfo); - sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType(actionType)); - } - - @Override - public void notifyAlarmComment(Alarm alarm, AlarmComment alarmComment, ActionType actionType, User user) { - logEntityAction(alarm.getTenantId(), alarm.getId(), alarm, alarm.getCustomerId(), actionType, user, alarmComment); - } - - @Override - public void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId, - I entityId, E entity, User user, - ActionType actionType, boolean sendNotifyMsgToEdge, Exception e, - Object... additionalInfo) { - logEntityAction(tenantId, entityId, entity, customerId, actionType, user, e, additionalInfo); - if (sendNotifyMsgToEdge) { - sendEntityNotificationMsg(tenantId, entityId, edgeTypeByActionType(actionType)); - } - } - - @Override - public void notifyRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user, - ActionType actionType, Object... additionalInfo) { - logEntityAction(tenantId, relation.getFrom(), null, customerId, actionType, user, additionalInfo); - logEntityAction(tenantId, relation.getTo(), null, customerId, actionType, user, additionalInfo); - if (!EntityType.EDGE.equals(relation.getFrom().getEntityType()) && !EntityType.EDGE.equals(relation.getTo().getEntityType())) { - sendNotificationMsgToEdge(tenantId, null, null, JacksonUtil.toString(relation), - EdgeEventType.RELATION, edgeTypeByActionType(actionType)); - } - } - - private void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action) { - sendEntityNotificationMsg(tenantId, entityId, action, null); - } - - private void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action, String body) { - sendNotificationMsgToEdge(tenantId, null, entityId, body, null, action); - } - - private void sendAlarmDeleteNotificationMsg(TenantId tenantId, Alarm alarm, List edgeIds, String body) { - sendDeleteNotificationMsg(tenantId, alarm.getId(), edgeIds, body); - } - - private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List edgeIds, String body) { - if (edgeIds != null && !edgeIds.isEmpty()) { - for (EdgeId edgeId : edgeIds) { - sendNotificationMsgToEdge(tenantId, edgeId, entityId, body, null, EdgeEventActionType.DELETED); - } - } - } - - private void sendEntityAssignToEdgeNotificationMsg(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) { - sendNotificationMsgToEdge(tenantId, edgeId, entityId, null, null, action); - } - - private void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, - EdgeEventType type, EdgeEventActionType action) { - tbClusterService.sendNotificationMsgToEdge(tenantId, edgeId, entityId, body, type, action); + public void logEntityRelationAction(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user, + ActionType actionType, Exception e, Object... additionalInfo) { + logEntityAction(tenantId, relation.getFrom(), null, customerId, actionType, user, e, additionalInfo); + logEntityAction(tenantId, relation.getTo(), null, customerId, actionType, user, e, additionalInfo); } private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) { @@ -327,6 +202,8 @@ public class DefaultTbNotificationEntityService implements TbNotificationEntityS return EdgeEventActionType.ASSIGNED_TO_EDGE; case UNASSIGNED_FROM_EDGE: return EdgeEventActionType.UNASSIGNED_FROM_EDGE; + case CREDENTIALS_UPDATED: + return EdgeEventActionType.CREDENTIALS_UPDATED; default: return null; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java index c5f8f85831..d14b2c6293 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java @@ -19,12 +19,8 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; -import org.thingsboard.server.common.data.alarm.Alarm; -import org.thingsboard.server.common.data.alarm.AlarmComment; -import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EdgeId; @@ -32,11 +28,8 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.relation.EntityRelation; -import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.security.DeviceCredentials; -import java.util.List; - public interface TbNotificationEntityService { void logEntityAction(TenantId tenantId, I entityId, ActionType actionType, User user, @@ -55,33 +48,6 @@ public interface TbNotificationEntityService { ActionType actionType, User user, Exception e, Object... additionalInfo); - void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity, - CustomerId customerId, ActionType actionType, - User user, Object... additionalInfo); - - void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, - CustomerId customerId, ActionType actionType, - List relatedEdgeIds, - User user, Object... additionalInfo); - - void notifyDeleteAlarm(TenantId tenantId, Alarm alarm, EntityId originatorId, CustomerId customerId, - List relatedEdgeIds, User user, String body, Object... additionalInfo); - - void notifyDeleteRuleChain(TenantId tenantId, RuleChain ruleChain, - List relatedEdgeIds, User user); - - void notifySendMsgToEdgeService(TenantId tenantId, I entityId, EdgeEventActionType edgeEventActionType); - - void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId, - CustomerId customerId, E entity, - ActionType actionType, - User user, Object... additionalInfo); - - void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId, - CustomerId customerId, EdgeId edgeId, - E entity, ActionType actionType, - User user, Object... additionalInfo); - void notifyCreateOrUpdateTenant(Tenant tenant, ComponentLifecycleEvent event); void notifyDeleteTenant(Tenant tenant); @@ -90,7 +56,7 @@ public interface TbNotificationEntityService { Device oldDevice, ActionType actionType, User user, Object... additionalInfo); void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, - List relatedEdgeIds, User user, Object... additionalInfo); + User user, Object... additionalInfo); void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, DeviceCredentials deviceCredentials, User user); @@ -101,16 +67,6 @@ public interface TbNotificationEntityService { void notifyCreateOrUpdateOrDeleteEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType, User user, Object... additionalInfo); - void notifyCreateOrUpdateAlarm(AlarmInfo alarm, ActionType actionType, User user, Object... additionalInfo); - - void notifyAlarmComment(Alarm alarm, AlarmComment alarmComment, ActionType actionType, User user); - - - void notifyCreateOrUpdateOrDelete(TenantId tenantId, CustomerId customerId, - I entityId, E entity, User user, - ActionType actionType, boolean sendNotifyMsgToEdge, - Exception e, Object... additionalInfo); - - void notifyRelation(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user, - ActionType actionType, Object... additionalInfo); + void logEntityRelationAction(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user, + ActionType actionType, Exception e, Object... additionalInfo); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java index 6dfc81c747..282d11ab2a 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmCommentService.java @@ -45,7 +45,8 @@ public class DefaultTbAlarmCommentService extends AbstractTbEntityService implem } try { AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.createOrUpdateAlarmComment(alarm.getTenantId(), alarmComment)); - notificationEntityService.notifyAlarmComment(alarm, savedAlarmComment, actionType, user); + notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getId(), alarm, alarm.getCustomerId(), actionType, user, savedAlarmComment); + return savedAlarmComment; } catch (Exception e) { notificationEntityService.logEntityAction(alarm.getTenantId(), emptyId(EntityType.ALARM), alarm, actionType, user, e, alarmComment); @@ -62,7 +63,7 @@ public class DefaultTbAlarmCommentService extends AbstractTbEntityService implem String.format("User %s deleted his comment", (user.getFirstName() == null || user.getLastName() == null) ? user.getName() : user.getFirstName() + " " + user.getLastName()))); AlarmComment savedAlarmComment = checkNotNull(alarmCommentService.saveAlarmComment(alarm.getTenantId(), alarmComment)); - notificationEntityService.notifyAlarmComment(alarm, savedAlarmComment, ActionType.DELETED_COMMENT, user); + notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getId(), alarm, alarm.getCustomerId(), ActionType.DELETED_COMMENT, user, savedAlarmComment); } else { throw new ThingsboardException("System comment could not be deleted", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java index 07c66e359a..e776c040c0 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java @@ -67,10 +67,6 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb if (!result.isSuccessful()) { throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND); } - actionType = result.isCreated() ? ActionType.ADDED : ActionType.UPDATED; - if (result.isModified()) { - notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), actionType, user); - } AlarmInfo resultAlarm = result.getAlarm(); if (alarm.isAcknowledged() && !resultAlarm.isAcknowledged()) { resultAlarm = ack(resultAlarm, alarm.getAckTs(), user); @@ -85,6 +81,10 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } else if (newAssignee == null && curAssignee != null) { resultAlarm = unassign(alarm, alarm.getAssignTs(), user); } + if (result.isModified()) { + notificationEntityService.logEntityAction(tenantId, alarm.getOriginator(), resultAlarm, + resultAlarm.getCustomerId(), actionType, user); + } return new Alarm(resultAlarm); } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ALARM), alarm, actionType, user, e); @@ -103,6 +103,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb if (!result.isSuccessful()) { throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND); } + AlarmInfo alarmInfo = result.getAlarm(); if (result.isModified()) { AlarmComment alarmComment = AlarmComment.builder() .alarmId(alarm.getId()) @@ -117,11 +118,12 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } catch (ThingsboardException e) { log.error("Failed to save alarm comment", e); } - notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_ACK, user); + notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, + alarmInfo.getCustomerId(), ActionType.ALARM_ACK, user); } else { throw new ThingsboardException("Alarm was already acknowledged!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } - return result.getAlarm(); + return alarmInfo; } @Override @@ -135,6 +137,7 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb if (!result.isSuccessful()) { throw new ThingsboardException(ThingsboardErrorCode.ITEM_NOT_FOUND); } + AlarmInfo alarmInfo = result.getAlarm(); if (result.isCleared()) { AlarmComment alarmComment = AlarmComment.builder() .alarmId(alarm.getId()) @@ -149,11 +152,12 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } catch (ThingsboardException e) { log.error("Failed to save alarm comment", e); } - notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_CLEAR, user); + notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, + alarmInfo.getCustomerId(), ActionType.ALARM_CLEAR, user); } else { throw new ThingsboardException("Alarm was already cleared!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } - return result.getAlarm(); + return alarmInfo; } @Override @@ -180,7 +184,8 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } catch (ThingsboardException e) { log.error("Failed to save alarm comment", e); } - notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_ASSIGNED, user); + notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, + alarmInfo.getCustomerId(), ActionType.ALARM_ASSIGNED, user); } else { throw new ThingsboardException("Alarm was already assigned to this user!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } @@ -208,7 +213,8 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } catch (ThingsboardException e) { log.error("Failed to save alarm comment", e); } - notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user); + notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarmInfo, + alarmInfo.getCustomerId(), ActionType.ALARM_UNASSIGNED, user); } else { throw new ThingsboardException("Alarm was already unassigned!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } @@ -239,7 +245,8 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb } catch (ThingsboardException e) { log.error("Failed to save alarm comment", e); } - notificationEntityService.notifyCreateOrUpdateAlarm(result.getAlarm(), ActionType.ALARM_UNASSIGNED, user); + notificationEntityService.logEntityAction(alarm.getTenantId(), alarm.getOriginator(), result.getAlarm(), + alarm.getCustomerId(), ActionType.ALARM_UNASSIGNED, user); } } @@ -251,9 +258,8 @@ public class DefaultTbAlarmService extends AbstractTbEntityService implements Tb @Override public Boolean delete(Alarm alarm, User user) { TenantId tenantId = alarm.getTenantId(); - List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, alarm.getOriginator()); - notificationEntityService.notifyDeleteAlarm(tenantId, alarm, alarm.getOriginator(), alarm.getCustomerId(), - relatedEdgeIds, user, JacksonUtil.toString(alarm)); + notificationEntityService.logEntityAction(tenantId, alarm.getOriginator(), alarm, alarm.getCustomerId(), + ActionType.DELETED, user); return alarmSubscriptionService.deleteAlarm(tenantId, alarm.getId()); } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java index ab57ecd050..6510ecfb7f 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java @@ -36,8 +36,6 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import org.thingsboard.server.service.profile.TbAssetProfileCache; -import java.util.List; - import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; @Service @@ -62,8 +60,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb } Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); autoCommit(user, savedAsset.getId()); - notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedAsset.getId(), savedAsset, - asset.getCustomerId(), actionType, user); + notificationEntityService.logEntityAction(tenantId, savedAsset.getId(), savedAsset, asset.getCustomerId(), + actionType, user); tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedAsset.getId(), asset.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); return savedAsset; @@ -75,17 +73,16 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb @Override public ListenableFuture delete(Asset asset, User user) { + ActionType actionType = ActionType.DELETED; TenantId tenantId = asset.getTenantId(); AssetId assetId = asset.getId(); try { - List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, assetId); assetService.deleteAsset(tenantId, assetId); - notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), - ActionType.DELETED, relatedEdgeIds, user, assetId.toString()); + notificationEntityService.logEntityAction(tenantId, assetId, asset, asset.getCustomerId(), actionType, user, assetId.toString()); tbClusterService.broadcastEntityStateChangeEvent(tenantId, assetId, ComponentLifecycleEvent.DELETED); return removeAlarmsByEntityId(tenantId, assetId); } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), ActionType.DELETED, user, e, + notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType, user, e, assetId.toString()); throw e; } @@ -97,8 +94,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb CustomerId customerId = customer.getId(); try { Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, customerId)); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset, - actionType, user, assetId.toString(), customerId.toString(), customer.getName()); + notificationEntityService.logEntityAction(tenantId, assetId, savedAsset, customerId, actionType, user, + assetId.toString(), customerId.toString(), customer.getName()); return savedAsset; } catch (Exception e) { @@ -114,8 +111,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb try { Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(tenantId, assetId)); CustomerId customerId = customer.getId(); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset, - actionType, user, assetId.toString(), customerId.toString(), customer.getName()); + notificationEntityService.logEntityAction(tenantId, assetId, savedAsset, customerId, actionType, user, + assetId.toString(), customerId.toString(), customer.getName()); return savedAsset; } catch (Exception e) { @@ -130,8 +127,9 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb try { Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId); Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, publicCustomer.getId())); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, savedAsset.getCustomerId(), savedAsset, - actionType, user, assetId.toString(), publicCustomer.getId().toString(), publicCustomer.getName()); + CustomerId customerId = publicCustomer.getId(); + notificationEntityService.logEntityAction(tenantId, assetId, savedAsset, customerId, actionType, user, + assetId.toString(), customerId.toString(), publicCustomer.getName()); return savedAsset; } catch (Exception e) { @@ -146,9 +144,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb EdgeId edgeId = edge.getId(); try { Asset savedAsset = checkNotNull(assetService.assignAssetToEdge(tenantId, assetId, edgeId)); - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, savedAsset.getCustomerId(), - edgeId, savedAsset, actionType, user, assetId.toString(), edgeId.toString(), edge.getName()); - + notificationEntityService.logEntityAction(tenantId, assetId, savedAsset, savedAsset.getCustomerId(), + actionType, user, assetId.toString(), edgeId.toString(), edge.getName()); return savedAsset; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), actionType, @@ -164,9 +161,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb EdgeId edgeId = edge.getId(); try { Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(tenantId, assetId, edgeId)); - - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, asset.getCustomerId(), - edgeId, asset, actionType, user, assetId.toString(), edgeId.toString(), edge.getName()); + notificationEntityService.logEntityAction(tenantId, assetId, asset, asset.getCustomerId(), + actionType, user, assetId.toString(), edgeId.toString(), edge.getName()); return savedAsset; } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java index b662994451..00b181a52a 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/profile/DefaultTbAssetProfileService.java @@ -59,8 +59,8 @@ public class DefaultTbAssetProfileService extends AbstractTbEntityService implem tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedAssetProfile.getId(), actionType.equals(ActionType.ADDED) ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedAssetProfile.getId(), - savedAssetProfile, user, actionType, true, null); + notificationEntityService.logEntityAction(tenantId, savedAssetProfile.getId(), savedAssetProfile, + null, actionType, user); return savedAssetProfile; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET_PROFILE), assetProfile, actionType, user, e); @@ -70,16 +70,17 @@ public class DefaultTbAssetProfileService extends AbstractTbEntityService implem @Override public void delete(AssetProfile assetProfile, User user) { + ActionType actionType = ActionType.DELETED; AssetProfileId assetProfileId = assetProfile.getId(); TenantId tenantId = assetProfile.getTenantId(); try { assetProfileService.deleteAssetProfile(tenantId, assetProfileId); tbClusterService.broadcastEntityStateChangeEvent(tenantId, assetProfileId, ComponentLifecycleEvent.DELETED); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, assetProfileId, assetProfile, - user, ActionType.DELETED, true, null, assetProfileId.toString()); + notificationEntityService.logEntityAction(tenantId, assetProfileId, assetProfile, null, + actionType, user, assetProfileId.toString()); } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET_PROFILE), ActionType.DELETED, + notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET_PROFILE), actionType, user, e, assetProfileId.toString()); throw e; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java index b71cfd222e..96611bb3b5 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/customer/DefaultTbCustomerService.java @@ -22,13 +22,10 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; -import java.util.List; - @Service @AllArgsConstructor public class DefaultTbCustomerService extends AbstractTbEntityService implements TbCustomerService { @@ -40,7 +37,7 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements try { Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer)); autoCommit(user, savedCustomer.getId()); - notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedCustomer.getId(), savedCustomer, null, actionType, user); + notificationEntityService.logEntityAction(tenantId, savedCustomer.getId(), savedCustomer, null, actionType, user); return savedCustomer; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), customer, actionType, user, e); @@ -50,17 +47,17 @@ public class DefaultTbCustomerService extends AbstractTbEntityService implements @Override public void delete(Customer customer, User user) { + ActionType actionType = ActionType.DELETED; TenantId tenantId = customer.getTenantId(); CustomerId customerId = customer.getId(); try { - List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, customer.getId()); customerService.deleteCustomer(tenantId, customerId); - notificationEntityService.notifyDeleteEntity(tenantId, customer.getId(), customer, customerId, - ActionType.DELETED, relatedEdgeIds, user, customerId.toString()); + notificationEntityService.logEntityAction(tenantId, customer.getId(), customer, customerId, actionType, + user, customerId.toString()); tbClusterService.broadcastEntityStateChangeEvent(tenantId, customer.getId(), ComponentLifecycleEvent.DELETED); } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), ActionType.DELETED, - user, e, customerId.toString()); + notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.CUSTOMER), actionType, user, + e, customerId.toString()); throw e; } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java index fa5b967bd0..70918486a3 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/dashboard/DefaultTbDashboardService.java @@ -34,7 +34,6 @@ import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; import java.util.HashSet; -import java.util.List; import java.util.Set; @Service @@ -51,8 +50,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement try { Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard)); autoCommit(user, savedDashboard.getId()); - notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedDashboard.getId(), savedDashboard, - null, actionType, user); + notificationEntityService.logEntityAction(tenantId, savedDashboard.getId(), savedDashboard, null, + actionType, user); return savedDashboard; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), dashboard, actionType, user, e); @@ -62,15 +61,14 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement @Override public void delete(Dashboard dashboard, User user) { + ActionType actionType = ActionType.DELETED; DashboardId dashboardId = dashboard.getId(); TenantId tenantId = dashboard.getTenantId(); try { - List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, dashboardId); dashboardService.deleteDashboard(tenantId, dashboardId); - notificationEntityService.notifyDeleteEntity(tenantId, dashboardId, dashboard, null, - ActionType.DELETED, relatedEdgeIds, user, dashboardId.toString()); + notificationEntityService.logEntityAction(tenantId, dashboardId, dashboard, null, actionType, user, dashboardId.toString()); } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), ActionType.DELETED, user, e, dashboardId.toString()); + notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString()); throw e; } } @@ -83,8 +81,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement DashboardId dashboardId = dashboard.getId(); try { Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId)); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard, - actionType, user, dashboardId.toString(), customerId.toString(), customer.getName()); + notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, customerId, actionType, + user, dashboardId.toString(), customerId.toString(), customer.getName()); return savedDashboard; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, @@ -101,9 +99,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement try { Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId); Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, publicCustomer.getId())); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, publicCustomer.getId(), savedDashboard, - actionType, user, dashboardId.toString(), - publicCustomer.getId().toString(), publicCustomer.getName()); + notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, publicCustomer.getId(), + actionType, user, dashboardId.toString(), publicCustomer.getId().toString(), publicCustomer.getName()); return savedDashboard; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString()); @@ -119,9 +116,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement try { Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId); Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, publicCustomer.getId())); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, publicCustomer.getId(), dashboard, - actionType, user, dashboardId.toString(), - publicCustomer.getId().toString(), publicCustomer.getName()); + notificationEntityService.logEntityAction(tenantId, dashboardId, dashboard, publicCustomer.getId(), actionType, + user, dashboardId.toString(), publicCustomer.getId().toString(), publicCustomer.getName()); return savedDashboard; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, dashboardId.toString()); @@ -159,15 +155,15 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement for (CustomerId customerId : addedCustomerIds) { savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId)); ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard, + notificationEntityService.logEntityAction(tenantId, savedDashboard.getId(), savedDashboard, customerId, actionType, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle()); } actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; for (CustomerId customerId : removedCustomerIds) { ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customerId)); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, savedDashboard.getId(), customerId, savedDashboard, - ActionType.UNASSIGNED_FROM_CUSTOMER, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle()); + notificationEntityService.logEntityAction(tenantId, savedDashboard.getId(), savedDashboard, customerId, + actionType, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle()); } return savedDashboard; } @@ -196,7 +192,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement for (CustomerId customerId : addedCustomerIds) { savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(tenantId, dashboardId, customerId)); ShortCustomerInfo customerInfo = savedDashboard.getAssignedCustomerInfo(customerId); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard, + notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, customerId, actionType, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle()); } return savedDashboard; @@ -226,7 +222,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement for (CustomerId customerId : removedCustomerIds) { ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customerId)); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customerId, savedDashboard, + notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, customerId, actionType, user, dashboardId.toString(), customerId.toString(), customerInfo.getTitle()); } return savedDashboard; @@ -243,9 +239,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement EdgeId edgeId = edge.getId(); try { Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(tenantId, dashboardId, edgeId)); - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, null, - edgeId, savedDashboard, actionType, user, dashboardId.toString(), - edgeId.toString(), edge.getName()); + notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, null, actionType, + user, dashboardId.toString(), edgeId.toString(), edge.getName()); return savedDashboard; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), @@ -262,10 +257,8 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement EdgeId edgeId = edge.getId(); try { Dashboard savedDevice = checkNotNull(dashboardService.unassignDashboardFromEdge(tenantId, dashboardId, edgeId)); - - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, dashboardId, null, - edgeId, dashboard, actionType, user, dashboardId.toString(), - edgeId.toString(), edge.getName()); + notificationEntityService.logEntityAction(tenantId, dashboardId, dashboard, null, actionType, + user, dashboardId.toString(), edgeId.toString(), edge.getName()); return savedDevice; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DASHBOARD), actionType, user, e, @@ -281,7 +274,7 @@ public class DefaultTbDashboardService extends AbstractTbEntityService implement DashboardId dashboardId = dashboard.getId(); try { Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromCustomer(tenantId, dashboardId, customer.getId())); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, dashboardId, customer.getId(), savedDashboard, + notificationEntityService.logEntityAction(tenantId, dashboardId, savedDashboard, customer.getId(), actionType, user, dashboardId.toString(), customer.getId().toString(), customer.getName()); return savedDashboard; } catch (Exception e) { diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java index 2ab8de9438..544a199498 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java @@ -44,8 +44,6 @@ import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.AbstractTbEntityService; -import java.util.List; - @AllArgsConstructor @TbCoreComponent @Service @@ -97,10 +95,9 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T TenantId tenantId = device.getTenantId(); DeviceId deviceId = device.getId(); try { - List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, deviceId); deviceService.deleteDevice(tenantId, deviceId); notificationEntityService.notifyDeleteDevice(tenantId, deviceId, device.getCustomerId(), device, - relatedEdgeIds, user, deviceId.toString()); + user, deviceId.toString()); return removeAlarmsByEntityId(tenantId, deviceId); } catch (Exception e) { @@ -116,8 +113,8 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T CustomerId customerId = customer.getId(); try { Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, customerId)); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice, - actionType, user, deviceId.toString(), customerId.toString(), customer.getName()); + notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, customerId, actionType, user, + deviceId.toString(), customerId.toString(), customer.getName()); return savedDevice; } catch (Exception e) { @@ -136,8 +133,8 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T Device savedDevice = checkNotNull(deviceService.unassignDeviceFromCustomer(tenantId, deviceId)); CustomerId customerId = customer.getId(); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice, - actionType, user, deviceId.toString(), customerId.toString(), customer.getName()); + notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, customerId, actionType, user, + deviceId.toString(), customerId.toString(), customer.getName()); return savedDevice; } catch (Exception e) { @@ -154,9 +151,8 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T try { Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, publicCustomer.getId())); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, savedDevice.getCustomerId(), savedDevice, - actionType, user, deviceId.toString(), - publicCustomer.getId().toString(), publicCustomer.getName()); + notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, savedDevice.getCustomerId(), + actionType, user, deviceId.toString(), publicCustomer.getId().toString(), publicCustomer.getName()); return savedDevice; } catch (Exception e) { @@ -252,30 +248,32 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T EdgeId edgeId = edge.getId(); try { Device savedDevice = checkNotNull(deviceService.assignDeviceToEdge(tenantId, deviceId, edgeId)); - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, savedDevice.getCustomerId(), - edgeId, savedDevice, actionType, user, deviceId.toString(), edgeId.toString(), edge.getName()); + notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, savedDevice.getCustomerId(), + actionType, user, deviceId.toString(), edgeId.toString(), edge.getName()); + return savedDevice; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), - ActionType.ASSIGNED_TO_EDGE, user, e, deviceId.toString(), edgeId.toString()); + actionType, user, e, deviceId.toString(), edgeId.toString()); throw e; } } @Override public Device unassignDeviceFromEdge(Device device, Edge edge, User user) throws ThingsboardException { + ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE; TenantId tenantId = device.getTenantId(); DeviceId deviceId = device.getId(); EdgeId edgeId = edge.getId(); try { Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(tenantId, deviceId, edgeId)); + notificationEntityService.logEntityAction(tenantId, deviceId, savedDevice, savedDevice.getCustomerId(), + actionType, user, deviceId.toString(), edgeId.toString(), edge.getName()); - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, device.getCustomerId(), - edgeId, device, ActionType.UNASSIGNED_FROM_EDGE, user, deviceId.toString(), edgeId.toString(), edge.getName()); return savedDevice; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), - ActionType.UNASSIGNED_FROM_EDGE, user, e, deviceId.toString(), edgeId.toString()); + actionType, user, e, deviceId.toString(), edgeId.toString()); throw e; } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java index faa6a69983..70ee722493 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/device/profile/DefaultTbDeviceProfileService.java @@ -67,8 +67,8 @@ public class DefaultTbDeviceProfileService extends AbstractTbEntityService imple otaPackageStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedDeviceProfile.getId(), - savedDeviceProfile, user, actionType, true, null); + notificationEntityService.logEntityAction(tenantId, savedDeviceProfile.getId(), savedDeviceProfile, + null, actionType, user); return savedDeviceProfile; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), deviceProfile, actionType, user, e); @@ -78,6 +78,7 @@ public class DefaultTbDeviceProfileService extends AbstractTbEntityService imple @Override public void delete(DeviceProfile deviceProfile, User user) { + ActionType actionType = ActionType.DELETED; DeviceProfileId deviceProfileId = deviceProfile.getId(); TenantId tenantId = deviceProfile.getTenantId(); try { @@ -85,10 +86,10 @@ public class DefaultTbDeviceProfileService extends AbstractTbEntityService imple tbClusterService.onDeviceProfileDelete(deviceProfile, null); tbClusterService.broadcastEntityStateChangeEvent(tenantId, deviceProfileId, ComponentLifecycleEvent.DELETED); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, deviceProfileId, deviceProfile, - user, ActionType.DELETED, true, null, deviceProfileId.toString()); + notificationEntityService.logEntityAction(tenantId, deviceProfileId, deviceProfile, null, + actionType, user, deviceProfileId.toString()); } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), ActionType.DELETED, + notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE_PROFILE), actionType, user, e, deviceProfileId.toString()); throw e; } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java index c51ae3352e..adc20c21d0 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java @@ -89,8 +89,8 @@ public class DefaultTbEdgeService extends AbstractTbEntityService implements TbE CustomerId customerId = customer.getId(); try { Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId)); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, edgeId, customerId, savedEdge, - actionType, user, edgeId.toString(), customerId.toString(), customer.getName()); + notificationEntityService.logEntityAction(tenantId, edgeId, savedEdge, customerId, actionType, + user, edgeId.toString(), customerId.toString(), customer.getName()); return savedEdge; } catch (Exception e) { @@ -108,8 +108,8 @@ public class DefaultTbEdgeService extends AbstractTbEntityService implements TbE CustomerId customerId = customer.getId(); try { Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(tenantId, edgeId)); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, edgeId, customerId, savedEdge, - actionType, user, edgeId.toString(), customerId.toString(), customer.getName()); + notificationEntityService.logEntityAction(tenantId, edgeId, savedEdge, customerId, actionType, + user, edgeId.toString(), customerId.toString(), customer.getName()); return savedEdge; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.EDGE), diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java index cf1733490d..904d98653e 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entity/relation/DefaultTbEntityRelationService.java @@ -40,33 +40,30 @@ public class DefaultTbEntityRelationService extends AbstractTbEntityService impl @Override public void save(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user) throws ThingsboardException { + ActionType actionType = ActionType.RELATION_ADD_OR_UPDATE; try { relationService.saveRelation(tenantId, relation); - notificationEntityService.notifyRelation(tenantId, customerId, - relation, user, ActionType.RELATION_ADD_OR_UPDATE, relation); + notificationEntityService.logEntityRelationAction(tenantId, customerId, + relation, user, actionType, null, relation); } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId, - ActionType.RELATION_ADD_OR_UPDATE, user, e, relation); - notificationEntityService.logEntityAction(tenantId, relation.getTo(), null, customerId, - ActionType.RELATION_ADD_OR_UPDATE, user, e, relation); + notificationEntityService.logEntityRelationAction(tenantId, customerId, + relation, user, actionType, e, relation); throw e; } } @Override public void delete(TenantId tenantId, CustomerId customerId, EntityRelation relation, User user) throws ThingsboardException { + ActionType actionType = ActionType.RELATION_DELETED; try { boolean found = relationService.deleteRelation(tenantId, relation.getFrom(), relation.getTo(), relation.getType(), relation.getTypeGroup()); if (!found) { throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); } - notificationEntityService.notifyRelation(tenantId, customerId, - relation, user, ActionType.RELATION_DELETED, relation); + notificationEntityService.logEntityRelationAction(tenantId, customerId, relation, user, actionType, null, relation); } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, relation.getFrom(), null, customerId, - ActionType.RELATION_DELETED, user, e, relation); - notificationEntityService.logEntityAction(tenantId, relation.getTo(), null, customerId, - ActionType.RELATION_DELETED, user, e, relation); + notificationEntityService.logEntityRelationAction(tenantId, customerId, + relation, user, actionType, e, relation); throw e; } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java index 48e6c4b634..f587e19ef2 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/entityview/DefaultTbEntityViewService.java @@ -81,7 +81,7 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); this.updateEntityViewAttributes(tenantId, savedEntityView, existingEntityView, user); autoCommit(user, savedEntityView.getId()); - notificationEntityService.notifyCreateOrUpdateEntity(savedEntityView.getTenantId(), savedEntityView.getId(), savedEntityView, + notificationEntityService.logEntityAction(savedEntityView.getTenantId(), savedEntityView.getId(), savedEntityView, null, actionType, user); localCache.computeIfAbsent(savedEntityView.getTenantId(), (k) -> new ConcurrentReferenceHashMap<>()).clear(); tbClusterService.broadcastEntityStateChangeEvent(savedEntityView.getTenantId(), savedEntityView.getId(), @@ -129,10 +129,9 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen TenantId tenantId = entityView.getTenantId(); EntityViewId entityViewId = entityView.getId(); try { - List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, entityViewId); entityViewService.deleteEntityView(tenantId, entityViewId); - notificationEntityService.notifyDeleteEntity(tenantId, entityViewId, entityView, entityView.getCustomerId(), ActionType.DELETED, - relatedEdgeIds, user, entityViewId.toString()); + notificationEntityService.logEntityAction(tenantId, entityViewId, entityView, entityView.getCustomerId(), + ActionType.DELETED, user, entityViewId.toString()); localCache.computeIfAbsent(tenantId, (k) -> new ConcurrentReferenceHashMap<>()).clear(); tbClusterService.broadcastEntityStateChangeEvent(tenantId, entityViewId, ComponentLifecycleEvent.DELETED); @@ -145,15 +144,31 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen @Override public EntityView assignEntityViewToCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException { + ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; CustomerId customerId = customer.getId(); try { EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId, entityViewId, customerId)); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customerId, savedEntityView, - ActionType.ASSIGNED_TO_CUSTOMER, user, entityViewId.toString(), customerId.toString(), customer.getName()); + notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, savedEntityView.getCustomerId(), + actionType, user, entityViewId.toString(), customerId.toString(), customer.getName()); + return savedEntityView; + } catch (Exception e) { + notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW), + actionType, user, e, entityViewId.toString(), customerId.toString()); + throw e; + } + } + + @Override + public EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException { + ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; + try { + EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(tenantId, entityViewId)); + notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, customer.getId(), + actionType, user, savedEntityView.getId().toString(), customer.getId().toString(), customer.getName()); return savedEntityView; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW), - ActionType.ASSIGNED_TO_CUSTOMER, user, e, entityViewId.toString(), customerId.toString()); + actionType, user, e, entityViewId.toString()); throw e; } } @@ -165,9 +180,8 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen try { EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(tenantId, entityViewId, publicCustomer.getId())); - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, savedEntityView.getCustomerId(), savedEntityView, - actionType, user, savedEntityView.getId().toString(), - publicCustomer.getId().toString(), publicCustomer.getName()); + notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, savedEntityView.getCustomerId(), + actionType, user, savedEntityView.getId().toString(), publicCustomer.getId().toString(), publicCustomer.getName()); return savedEntityView; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW), @@ -178,16 +192,16 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen @Override public EntityView assignEntityViewToEdge(TenantId tenantId, CustomerId customerId, EntityViewId entityViewId, Edge edge, User user) throws ThingsboardException { + ActionType actionType = ActionType.ASSIGNED_TO_EDGE; EdgeId edgeId = edge.getId(); try { EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToEdge(tenantId, entityViewId, edgeId)); - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, entityViewId, customerId, - edgeId, savedEntityView, ActionType.ASSIGNED_TO_EDGE, user, savedEntityView.getEntityId().toString(), - edgeId.toString(), edge.getName()); + notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, customerId, actionType, + user, savedEntityView.getEntityId().toString(), edgeId.toString(), edge.getName()); return savedEntityView; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW), - ActionType.ASSIGNED_TO_EDGE, user, e, entityViewId.toString(), edgeId.toString()); + actionType, user, e, entityViewId.toString(), edgeId.toString()); throw e; } } @@ -195,34 +209,17 @@ public class DefaultTbEntityViewService extends AbstractTbEntityService implemen @Override public EntityView unassignEntityViewFromEdge(TenantId tenantId, CustomerId customerId, EntityView entityView, Edge edge, User user) throws ThingsboardException { + ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE; EntityViewId entityViewId = entityView.getId(); EdgeId edgeId = edge.getId(); try { EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(tenantId, entityViewId, edgeId)); - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, entityViewId, customerId, - edgeId, entityView, ActionType.UNASSIGNED_FROM_EDGE, user, entityViewId.toString(), - edgeId.toString(), edge.getName()); + notificationEntityService.logEntityAction(tenantId, entityViewId, savedEntityView, customerId, actionType, + user, entityViewId.toString(), edgeId.toString(), edge.getName()); return savedEntityView; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW), - ActionType.UNASSIGNED_FROM_EDGE, user, e, entityViewId.toString(), edgeId.toString()); - throw e; - } - } - - @Override - public EntityView unassignEntityViewFromCustomer(TenantId tenantId, EntityViewId entityViewId, Customer customer, User user) throws ThingsboardException { - ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; - try { - EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(tenantId, entityViewId)); - - notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, entityViewId, customer.getId(), savedEntityView, - actionType, user, savedEntityView.getId().toString(), customer.getId().toString(), customer.getName()); - - return savedEntityView; - } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ENTITY_VIEW), - actionType, user, e, entityViewId.toString()); + actionType, user, e, entityViewId.toString(), edgeId.toString()); throw e; } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java index 4d3c61e615..3cc444caf5 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/ota/DefaultTbOtaPackageService.java @@ -50,9 +50,8 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen try { OtaPackageInfo savedOtaPackageInfo = otaPackageService.saveOtaPackageInfo(new OtaPackageInfo(saveOtaPackageInfoRequest), saveOtaPackageInfoRequest.isUsesUrl()); - boolean sendMsgToEdge = savedOtaPackageInfo.hasUrl() || savedOtaPackageInfo.isHasData(); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedOtaPackageInfo.getId(), - savedOtaPackageInfo, user, actionType, sendMsgToEdge, null); + notificationEntityService.logEntityAction(tenantId, savedOtaPackageInfo.getId(), savedOtaPackageInfo, + null, actionType, user); return savedOtaPackageInfo; } catch (Exception e) { @@ -65,6 +64,7 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen @Override public OtaPackageInfo saveOtaPackageData(OtaPackageInfo otaPackageInfo, String checksum, ChecksumAlgorithm checksumAlgorithm, byte[] data, String filename, String contentType, User user) throws ThingsboardException { + ActionType actionType = ActionType.UPDATED; TenantId tenantId = otaPackageInfo.getTenantId(); OtaPackageId otaPackageId = otaPackageInfo.getId(); try { @@ -87,27 +87,26 @@ public class DefaultTbOtaPackageService extends AbstractTbEntityService implemen otaPackage.setData(ByteBuffer.wrap(data)); otaPackage.setDataSize((long) data.length); OtaPackageInfo savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedOtaPackage.getId(), - savedOtaPackage, user, ActionType.UPDATED, true, null); + notificationEntityService.logEntityAction(tenantId, savedOtaPackage.getId(), savedOtaPackage, null, actionType, user); return savedOtaPackage; } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE), ActionType.UPDATED, - user, e, otaPackageId.toString()); + notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE), actionType, user, e, otaPackageId.toString()); throw e; } } @Override public void delete(OtaPackageInfo otaPackageInfo, User user) throws ThingsboardException { + ActionType actionType = ActionType.DELETED; TenantId tenantId = otaPackageInfo.getTenantId(); OtaPackageId otaPackageId = otaPackageInfo.getId(); try { otaPackageService.deleteOtaPackage(tenantId, otaPackageId); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, otaPackageId, otaPackageInfo, - user, ActionType.DELETED, true, null, otaPackageInfo.getId().toString()); + notificationEntityService.logEntityAction(tenantId, otaPackageId, otaPackageInfo, null, + actionType, user, otaPackageInfo.getId().toString()); } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.OTA_PACKAGE), - ActionType.DELETED, user, e, otaPackageId.toString()); + actionType, user, e, otaPackageId.toString()); throw e; } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java index 63e11aeb7a..40d294d238 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java @@ -20,7 +20,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.TenantProfile; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.queue.Queue; @@ -71,8 +70,6 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb onQueueUpdated(savedQueue, oldQueue); } - notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), savedQueue.getId(), create ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); - return savedQueue; } @@ -145,8 +142,6 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb } } }, DELETE_DELAY, TimeUnit.SECONDS); - - notificationEntityService.notifySendMsgToEdgeService(queue.getTenantId(), queue.getId(), EdgeEventActionType.DELETED); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java index d9f11dacb5..58bd40d070 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/user/DefaultUserService.java @@ -54,7 +54,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse ActionType actionType = tbUser.getId() == null ? ActionType.ADDED : ActionType.UPDATED; try { boolean sendEmail = tbUser.getId() == null && sendActivationMail; - User savedUser = checkNotNull(userService.saveUser(tbUser)); + User savedUser = checkNotNull(userService.saveUser(tenantId, tbUser)); if (sendEmail) { UserCredentials userCredentials = userService.findUserCredentialsByUserId(tenantId, savedUser.getId()); String baseUrl = systemSecurityService.getBaseUrl(tenantId, customerId, request); @@ -68,8 +68,7 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse throw e; } } - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, savedUser.getId(), - savedUser, user, actionType, true, null); + notificationEntityService.logEntityAction(tenantId, savedUser.getId(), savedUser, customerId, actionType, user); return savedUser; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER), tbUser, actionType, user, e); @@ -79,16 +78,16 @@ public class DefaultUserService extends AbstractTbEntityService implements TbUse @Override public void delete(TenantId tenantId, CustomerId customerId, User tbUser, User user) throws ThingsboardException { + ActionType actionType = ActionType.DELETED; UserId userId = tbUser.getId(); try { tbAlarmService.unassignUserAlarms(tbUser.getTenantId(), tbUser, System.currentTimeMillis()); userService.deleteUser(tenantId, userId); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, customerId, userId, tbUser, - user, ActionType.DELETED, true, null, customerId.toString()); + notificationEntityService.logEntityAction(tenantId, userId, tbUser, customerId, actionType, user, customerId.toString()); } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.USER), - ActionType.DELETED, user, e, userId.toString()); + actionType, user, e, userId.toString()); throw e; } } diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java index 7cc150b746..efc20cd422 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java @@ -40,8 +40,8 @@ public class DefaultWidgetsBundleService extends AbstractTbEntityService impleme try { WidgetsBundle savedWidgetsBundle = checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle)); autoCommit(user, savedWidgetsBundle.getId()); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedWidgetsBundle.getId(), - savedWidgetsBundle, user, actionType, true, null); + notificationEntityService.logEntityAction(tenantId, savedWidgetsBundle.getId(), savedWidgetsBundle, + null, actionType, user); return savedWidgetsBundle; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGETS_BUNDLE), widgetsBundle, actionType, user, e); @@ -51,14 +51,13 @@ public class DefaultWidgetsBundleService extends AbstractTbEntityService impleme @Override public void delete(WidgetsBundle widgetsBundle, User user) { + ActionType actionType = ActionType.DELETED; TenantId tenantId = widgetsBundle.getTenantId(); try { widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getTenantId(), widgetsBundle.getId()); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, widgetsBundle.getId(), widgetsBundle, - user, ActionType.DELETED, true, null); + notificationEntityService.logEntityAction(tenantId, widgetsBundle.getId(), widgetsBundle, null, actionType, user); } catch (Exception e) { - notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGETS_BUNDLE), - ActionType.DELETED, user, e, widgetsBundle.getId()); + notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGETS_BUNDLE), actionType, user, e, widgetsBundle.getId()); throw e; } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 1087990c4e..acadd35577 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -525,7 +525,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { user.setEmail(email); user.setTenantId(tenantId); user.setCustomerId(customerId); - user = userService.saveUser(user); + user = userService.saveUser(tenantId, user); UserCredentials userCredentials = userService.findUserCredentialsByUserId(TenantId.SYS_TENANT_ID, user.getId()); userCredentials.setPassword(passwordEncoder.encode(password)); userCredentials.setEnabled(true); diff --git a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java index 1c6af41360..246fa4a0fa 100644 --- a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java +++ b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java @@ -16,7 +16,6 @@ package org.thingsboard.server.service.mail; import com.fasterxml.jackson.databind.JsonNode; - import freemarker.template.Configuration; import freemarker.template.Template; import lombok.extern.slf4j.Slf4j; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index 63eaab23f2..53ef38d96a 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -458,11 +458,6 @@ public class DefaultTbClusterService implements TbClusterService { @Override public void onDeviceUpdated(Device device, Device old) { - onDeviceUpdated(device, old, true); - } - - @Override - public void onDeviceUpdated(Device device, Device old, boolean notifyEdge) { var created = old == null; broadcastEntityChangeToTransport(device.getTenantId(), device.getId(), device, null); if (old != null) { @@ -477,9 +472,6 @@ public class DefaultTbClusterService implements TbClusterService { broadcastEntityStateChangeEvent(device.getTenantId(), device.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); sendDeviceStateServiceEvent(device.getTenantId(), device.getId(), created, !created, false); otaPackageStateService.update(device, old); - if (!created && notifyEdge) { - sendNotificationMsgToEdge(device.getTenantId(), null, device.getId(), null, null, EdgeEventActionType.UPDATED); - } } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index dc24d6df33..fef22acf40 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -32,10 +32,11 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.NotificationRequestId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; import org.thingsboard.server.common.data.rpc.RpcError; import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.TbActorMsg; -import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTrigger; +import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; @@ -63,7 +64,6 @@ import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; -import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.queue.provider.TbCoreQueueFactory; import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.DataDecodingEncodingService; diff --git a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java index 5756101ee1..884c614231 100644 --- a/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java +++ b/application/src/main/java/org/thingsboard/server/service/rule/DefaultTbRuleChainService.java @@ -29,7 +29,6 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.RuleChainId; @@ -185,9 +184,7 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedRuleChain.getId(), actionType.equals(ActionType.ADDED) ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); } - boolean sendMsgToEdge = RuleChainType.EDGE.equals(savedRuleChain.getType()) && actionType.equals(ActionType.UPDATED); - notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedRuleChain.getId(), - savedRuleChain, user, actionType, sendMsgToEdge, null); + notificationEntityService.logEntityAction(tenantId, savedRuleChain.getId(), savedRuleChain, null, actionType, user); return savedRuleChain; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.RULE_CHAIN), ruleChain, actionType, user, e); @@ -204,11 +201,6 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement Set referencingRuleChainIds = referencingRuleNodes.stream().map(RuleNode::getRuleChainId).collect(Collectors.toSet()); - List relatedEdgeIds = null; - if (RuleChainType.EDGE.equals(ruleChain.getType())) { - relatedEdgeIds = edgeService.findAllRelatedEdgeIds(tenantId, ruleChainId); - } - ruleChainService.deleteRuleChainById(tenantId, ruleChainId); referencingRuleChainIds.remove(ruleChain.getId()); @@ -220,7 +212,7 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement tbClusterService.broadcastEntityStateChangeEvent(tenantId, ruleChain.getId(), ComponentLifecycleEvent.DELETED); } - notificationEntityService.notifyDeleteRuleChain(tenantId, ruleChain, relatedEdgeIds, user); + notificationEntityService.logEntityAction(tenantId, ruleChainId, ruleChain, null, ActionType.DELETED, user, ruleChainId.toString()); } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.RULE_CHAIN), ActionType.DELETED, user, e, ruleChainId.toString()); @@ -310,14 +302,8 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement notificationEntityService.logEntityAction(tenantId, ruleChainId, ruleChain, ActionType.UPDATED, user, ruleChainMetaData); - if (RuleChainType.EDGE.equals(ruleChain.getType())) { - notificationEntityService.notifySendMsgToEdgeService(tenantId, ruleChain.getId(), EdgeEventActionType.UPDATED); - } - for (RuleChain updatedRuleChain : updatedRuleChains) { - if (RuleChainType.EDGE.equals(ruleChain.getType())) { - notificationEntityService.notifySendMsgToEdgeService(tenantId, updatedRuleChain.getId(), EdgeEventActionType.UPDATED); - } else { + if (RuleChainType.CORE.equals(ruleChain.getType())) { RuleChainMetaData updatedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, updatedRuleChain.getId())); notificationEntityService.logEntityAction(tenantId, updatedRuleChain.getId(), updatedRuleChain, ActionType.UPDATED, user, updatedRuleChainMetaData); @@ -333,34 +319,34 @@ public class DefaultTbRuleChainService extends AbstractTbEntityService implement @Override public RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChain ruleChain, Edge edge, User user) throws ThingsboardException { + ActionType actionType = ActionType.ASSIGNED_TO_EDGE; RuleChainId ruleChainId = ruleChain.getId(); EdgeId edgeId = edge.getId(); try { RuleChain savedRuleChain = checkNotNull(ruleChainService.assignRuleChainToEdge(tenantId, ruleChainId, edgeId)); - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, ruleChainId, - null, edgeId, savedRuleChain, ActionType.ASSIGNED_TO_EDGE, + notificationEntityService.logEntityAction(tenantId, ruleChainId, savedRuleChain, null, actionType, user, ruleChainId.toString(), edgeId.toString(), edge.getName()); return savedRuleChain; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.RULE_CHAIN), - ActionType.ASSIGNED_TO_EDGE, user, e, ruleChainId.toString(), edgeId.toString()); + actionType, user, e, ruleChainId.toString(), edgeId.toString()); throw e; } } @Override public RuleChain unassignRuleChainFromEdge(TenantId tenantId, RuleChain ruleChain, Edge edge, User user) throws ThingsboardException { + ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE; RuleChainId ruleChainId = ruleChain.getId(); EdgeId edgeId = edge.getId(); try { RuleChain savedRuleChain = checkNotNull(ruleChainService.unassignRuleChainFromEdge(tenantId, ruleChainId, edgeId, false)); - notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, ruleChainId, - null, edgeId, savedRuleChain, ActionType.UNASSIGNED_FROM_EDGE, + notificationEntityService.logEntityAction(tenantId, ruleChainId, savedRuleChain, null, actionType, user, ruleChainId.toString(), edgeId.toString(), edge.getName()); return savedRuleChain; } catch (Exception e) { notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.RULE_CHAIN), - ActionType.UNASSIGNED_FROM_EDGE, user, e, ruleChainId, edgeId); + actionType, user, e, ruleChainId, edgeId); throw e; } } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java index 3b37b0fe26..dcb6764201 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/DefaultEntitiesExportImportService.java @@ -25,15 +25,15 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.common.data.sync.ie.EntityImportResult; import org.thingsboard.server.common.data.util.ThrowingRunnable; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.relation.RelationService; -import org.thingsboard.server.queue.util.TbCoreComponent; -import org.thingsboard.server.common.data.limit.LimitedApi; import org.thingsboard.server.dao.util.limits.RateLimitService; +import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.entitiy.TbNotificationEntityService; import org.thingsboard.server.service.sync.ie.exporting.EntityExportService; import org.thingsboard.server.service.sync.ie.exporting.impl.BaseEntityExportService; @@ -119,8 +119,8 @@ public class DefaultEntitiesExportImportService implements EntitiesExportImportS relationService.saveRelations(ctx.getTenantId(), new ArrayList<>(ctx.getRelations())); for (EntityRelation relation : ctx.getRelations()) { - entityNotificationService.notifyRelation(ctx.getTenantId(), null, - relation, ctx.getUser(), ActionType.RELATION_ADD_OR_UPDATE, relation); + entityNotificationService.logEntityRelationAction(ctx.getTenantId(), null, + relation, ctx.getUser(), ActionType.RELATION_ADD_OR_UPDATE, null, relation); } } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java index 7f0af64ed7..3255c418c5 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/AssetProfileImportService.java @@ -58,8 +58,8 @@ public class AssetProfileImportService extends BaseEntityImportService { - entityNotificationService.notifyRelation(tenantId, null, - existingRelation, ctx.getUser(), ActionType.RELATION_DELETED, existingRelation); + entityNotificationService.logEntityRelationAction(tenantId, null, + existingRelation, ctx.getUser(), ActionType.RELATION_DELETED, null, existingRelation); }); } else if (Objects.equal(relation.getAdditionalInfo(), existingRelation.getAdditionalInfo())) { relationsMap.remove(relation); @@ -266,8 +266,8 @@ public abstract class BaseEntityImportService taskCache; @@ -432,12 +429,11 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont return exportableEntitiesService.findEntitiesByTenantId(ctx.getTenantId(), entityType, pageLink); }, 100, entity -> { if (ctx.getImportedEntities().get(entityType) == null || !ctx.getImportedEntities().get(entityType).contains(entity.getId())) { - List relatedEdgeIds = edgeService.findAllRelatedEdgeIds(ctx.getTenantId(), entity.getId()); exportableEntitiesService.removeById(ctx.getTenantId(), entity.getId()); ctx.addEventCallback(() -> { - entityNotificationService.notifyDeleteEntity(ctx.getTenantId(), entity.getId(), - entity, null, ActionType.DELETED, relatedEdgeIds, ctx.getUser()); + entityNotificationService.logEntityAction(ctx.getTenantId(), entity.getId(), entity, null, + ActionType.DELETED, ctx.getUser()); }); ctx.registerDeleted(entityType); } diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java index 1603d33bfd..b2b9d992e6 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java @@ -44,15 +44,15 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; +import org.thingsboard.server.common.data.notification.rule.trigger.AlarmTrigger; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; -import org.thingsboard.server.common.data.notification.rule.trigger.AlarmTrigger; +import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.stats.TbApiUsageReportClient; import org.thingsboard.server.dao.alarm.AlarmOperationResult; import org.thingsboard.server.dao.alarm.AlarmService; -import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService; import org.thingsboard.server.service.subscription.TbSubscriptionUtils; diff --git a/application/src/main/java/org/thingsboard/server/utils/LwM2mObjectModelUtils.java b/application/src/main/java/org/thingsboard/server/utils/LwM2mObjectModelUtils.java index 4a07444bbb..0deb2f6bb7 100644 --- a/application/src/main/java/org/thingsboard/server/utils/LwM2mObjectModelUtils.java +++ b/application/src/main/java/org/thingsboard/server/utils/LwM2mObjectModelUtils.java @@ -16,8 +16,6 @@ package org.thingsboard.server.utils; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.model.DDFFileParser; -import org.eclipse.leshan.core.model.DefaultDDFFileValidator; import org.eclipse.leshan.core.model.InvalidDDFFileException; import org.eclipse.leshan.core.model.ObjectModel; import org.thingsboard.server.common.data.ResourceType; diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java index d5eabdff2a..71c244890d 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java @@ -74,6 +74,17 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { Mockito.reset(tbClusterService, auditLogService); } + protected void testNotifyAssignUnassignEntityAllOneTime(HasName entity, EntityId entityId, EntityId originatorId, + TenantId tenantId, CustomerId customerId, UserId userId, String userName, + ActionType actionType, ActionType actionTypeEdge, Object... additionalInfo) { + int cntTime = 1; + testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionTypeEdge, cntTime); + testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); + ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId); + testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime); + Mockito.reset(tbClusterService, auditLogService); + } + protected void testNotifyEntityAllOneTimeRelation(EntityRelation relation, TenantId tenantId, CustomerId customerId, UserId userId, String userName, ActionType actionType, Object... additionalInfo) { @@ -115,9 +126,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { protected void testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(HasName entity, EntityId entityId, EntityId originatorId, TenantId tenantId, CustomerId customerId, UserId userId, String userName, - ActionType actionType, Object... additionalInfo) { + ActionType actionType, ActionType actionTypeEdge, Object... additionalInfo) { int cntTime = 1; - testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime); + testNotificationMsgToEdgeServiceTime(entityId, tenantId, actionTypeEdge, cntTime); testLogEntityActionEntityEqClass(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); ArgumentMatcher matcherOriginatorId = argument -> argument.equals(originatorId); testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, entity, cntTime); @@ -163,10 +174,10 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest { protected void testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(HasName entity, HasName originator, TenantId tenantId, CustomerId customerId, UserId userId, String userName, - ActionType actionType, ActionType actionTypeEdge, + ActionType actionType, int cntTime, int cntTimeEdge, int cntTimeRuleEngine, Object... additionalInfo) { EntityId originatorId = createEntityId_NULL_UUID(originator); - testSendNotificationMsgToEdgeServiceTimeEntityEqAny(tenantId, actionTypeEdge, cntTimeEdge); + testSendNotificationMsgToEdgeServiceTimeEntityEqAny(tenantId, actionType, cntTimeEdge); ArgumentMatcher matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass()); ArgumentMatcher matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass()); ArgumentMatcher matcherCustomerId = customerId == null ? diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index 7f57fbbb3f..58367c9531 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -95,6 +95,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; @@ -188,7 +189,9 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { protected String username; protected TenantId tenantId; + protected TenantProfileId tenantProfileId; protected UserId tenantAdminUserId; + protected User tenantAdminUser; protected CustomerId tenantAdminCustomerId; protected CustomerId customerId; protected TenantId differentTenantId; @@ -269,15 +272,16 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Assert.assertNotNull(savedTenant); tenantId = savedTenant.getId(); + tenantProfileId = savedTenant.getTenantProfileId(); - User tenantAdmin = new User(); - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); - tenantAdmin.setTenantId(tenantId); - tenantAdmin.setEmail(TENANT_ADMIN_EMAIL); + tenantAdminUser = new User(); + tenantAdminUser.setAuthority(Authority.TENANT_ADMIN); + tenantAdminUser.setTenantId(tenantId); + tenantAdminUser.setEmail(TENANT_ADMIN_EMAIL); - tenantAdmin = createUserAndLogin(tenantAdmin, TENANT_ADMIN_PASSWORD); - tenantAdminUserId = tenantAdmin.getId(); - tenantAdminCustomerId = tenantAdmin.getCustomerId(); + tenantAdminUser = createUserAndLogin(tenantAdminUser, TENANT_ADMIN_PASSWORD); + tenantAdminUserId = tenantAdminUser.getId(); + tenantAdminCustomerId = tenantAdminUser.getCustomerId(); Customer customer = new Customer(); customer.setTitle("Customer"); diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index 6ce6e22e9a..36c5eacd36 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -158,8 +158,10 @@ public class AlarmControllerTest extends AbstractControllerTest { Assert.assertEquals(alarm.getAckTs(), updatedAlarm.getAckTs()); foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class); - testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), - tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ACK); + + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundAlarm, customerDevice, tenantId, + customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ACK, 1, 1, 1); + Mockito.reset(tbClusterService, auditLogService); alarm = updatedAlarm; alarm.setCleared(true); @@ -170,8 +172,10 @@ public class AlarmControllerTest extends AbstractControllerTest { Assert.assertEquals(alarm.getClearTs(), updatedAlarm.getClearTs()); foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class); - testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), - tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_CLEAR); + + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundAlarm, customerDevice, tenantId, + customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_CLEAR, 1, 1, 1); + Mockito.reset(tbClusterService, auditLogService); alarm = updatedAlarm; alarm.setAssigneeId(tenantAdminUserId); @@ -182,8 +186,10 @@ public class AlarmControllerTest extends AbstractControllerTest { Assert.assertEquals(alarm.getAssignTs(), updatedAlarm.getAssignTs()); foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class); - testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), - tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ASSIGNED); + + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundAlarm, customerDevice, tenantId, + customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_ASSIGNED, 1, 1, 1); + Mockito.reset(tbClusterService, auditLogService); alarm = updatedAlarm; alarm.setAssigneeId(null); @@ -194,8 +200,11 @@ public class AlarmControllerTest extends AbstractControllerTest { Assert.assertEquals(alarm.getAssignTs(), updatedAlarm.getAssignTs()); foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class); - testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), - tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_UNASSIGNED); + + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundAlarm, customerDevice, tenantId, + customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.ALARM_UNASSIGNED, 1, 1, 1); + Mockito.reset(tbClusterService, auditLogService); + } @Test @@ -241,7 +250,7 @@ public class AlarmControllerTest extends AbstractControllerTest { doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isOk()); - testNotifyEntityOneTimeMsgToEdgeServiceNever(new Alarm(alarm), alarm.getId(), alarm.getOriginator(), + testNotifyEntityAllOneTime(new Alarm(alarm), alarm.getId(), alarm.getOriginator(), tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.DELETED); } @@ -254,7 +263,7 @@ public class AlarmControllerTest extends AbstractControllerTest { doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isOk()); - testNotifyEntityOneTimeMsgToEdgeServiceNever(new Alarm(alarm), alarm.getId(), alarm.getOriginator(), + testNotifyEntityAllOneTime(new Alarm(alarm), alarm.getId(), alarm.getOriginator(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.DELETED); } diff --git a/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java index 40b1707271..88a8b939b8 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AssetControllerTest.java @@ -50,7 +50,6 @@ import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.service.stats.DefaultRuleEngineStatisticsService; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import static org.hamcrest.Matchers.containsString; @@ -114,8 +113,8 @@ public class AssetControllerTest extends AbstractControllerTest { Asset savedAsset = doPost("/api/asset", asset, Asset.class); - testNotifyEntityOneTimeMsgToEdgeServiceNever(savedAsset, savedAsset.getId(), savedAsset.getId(), - savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED); + testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), savedTenant.getId(), + tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED); Assert.assertNotNull(savedAsset); Assert.assertNotNull(savedAsset.getId()); @@ -130,8 +129,8 @@ public class AssetControllerTest extends AbstractControllerTest { savedAsset.setName("My new asset"); doPost("/api/asset", savedAsset, Asset.class); - testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), - savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED); + testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), savedTenant.getId(), + tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED); Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(foundAsset.getName(), savedAsset.getName()); @@ -229,7 +228,8 @@ public class AssetControllerTest extends AbstractControllerTest { @Test public void testFindAssetTypesByTenantId() throws Exception { - List assets = new ArrayList<>(); + AssetProfile assetProfile = createAssetProfile("typeB"); + assetProfile = doPost("/api/assetProfile", assetProfile, AssetProfile.class); Mockito.reset(tbClusterService, auditLogService); @@ -238,24 +238,25 @@ public class AssetControllerTest extends AbstractControllerTest { Asset asset = new Asset(); asset.setName("My asset B" + i); asset.setType("typeB"); - assets.add(doPost("/api/asset", asset, Asset.class)); + asset.setAssetProfileId(assetProfile.getId()); + doPost("/api/asset", asset, Asset.class); } - testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Asset(), new Asset(), + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Asset(), new Asset(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, cntTime); + ActionType.ADDED, cntTime, cntTime, cntTime); for (int i = 0; i < 7; i++) { Asset asset = new Asset(); asset.setName("My asset C" + i); asset.setType("typeC"); - assets.add(doPost("/api/asset", asset, Asset.class)); + doPost("/api/asset", asset, Asset.class); } for (int i = 0; i < 9; i++) { Asset asset = new Asset(); asset.setName("My asset A" + i); asset.setType("typeA"); - assets.add(doPost("/api/asset", asset, Asset.class)); + doPost("/api/asset", asset, Asset.class); } List assetTypes = doGetTyped("/api/asset/types", new TypeReference>() { @@ -280,7 +281,7 @@ public class AssetControllerTest extends AbstractControllerTest { doDelete("/api/asset/" + savedAsset.getId().getId().toString()) .andExpect(status().isOk()); - testNotifyEntityOneTimeMsgToEdgeServiceNever(savedAsset, savedAsset.getId(), savedAsset.getId(), + testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED, savedAsset.getId().getId().toString()); @@ -342,7 +343,7 @@ public class AssetControllerTest extends AbstractControllerTest { Asset savedAsset = doPost("/api/asset", asset, Asset.class); Assert.assertEquals("default", savedAsset.getType()); - testNotifyEntityOneTimeMsgToEdgeServiceNever(savedAsset, savedAsset.getId(), savedAsset.getId(), + testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED); } @@ -380,9 +381,9 @@ public class AssetControllerTest extends AbstractControllerTest { + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(savedCustomer.getId(), assignedAsset.getCustomerId()); - testNotifyEntityAllOneTime(assignedAsset, assignedAsset.getId(), assignedAsset.getId(), + testNotifyAssignUnassignEntityAllOneTime(assignedAsset, assignedAsset.getId(), assignedAsset.getId(), savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ASSIGNED_TO_CUSTOMER, assignedAsset.getId().toString(), savedCustomer.getId().toString(), savedCustomer.getTitle()); + ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED, assignedAsset.getId().toString(), savedCustomer.getId().toString(), savedCustomer.getTitle()); Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(savedCustomer.getId(), foundAsset.getCustomerId()); @@ -393,9 +394,9 @@ public class AssetControllerTest extends AbstractControllerTest { doDelete("/api/customer/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(ModelConstants.NULL_UUID, unassignedAsset.getCustomerId().getId()); - testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), + testNotifyAssignUnassignEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.UNASSIGNED_FROM_CUSTOMER, savedAsset.getId().toString(), savedCustomer.getId().toString(), savedCustomer.getTitle()); + ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, savedAsset.getId().toString(), savedCustomer.getId().toString(), savedCustomer.getTitle()); foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(ModelConstants.NULL_UUID, foundAsset.getCustomerId().getId()); @@ -415,9 +416,10 @@ public class AssetControllerTest extends AbstractControllerTest { Customer publicCustomer = doGet("/api/customer/" + assignedAsset.getCustomerId(), Customer.class); Assert.assertTrue(publicCustomer.isPublic()); - testNotifyEntityAllOneTime(assignedAsset, assignedAsset.getId(), assignedAsset.getId(), + testNotifyAssignUnassignEntityAllOneTime(assignedAsset, assignedAsset.getId(), assignedAsset.getId(), savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ASSIGNED_TO_CUSTOMER, assignedAsset.getId().toString(), publicCustomer.getId().toString(), publicCustomer.getTitle()); + ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED, assignedAsset.getId().toString(), + publicCustomer.getId().toString(), publicCustomer.getTitle()); Asset foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(publicCustomer.getId(), foundAsset.getCustomerId()); @@ -428,9 +430,10 @@ public class AssetControllerTest extends AbstractControllerTest { doDelete("/api/customer/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(ModelConstants.NULL_UUID, unassignedAsset.getCustomerId().getId()); - testNotifyEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), + testNotifyAssignUnassignEntityAllOneTime(savedAsset, savedAsset.getId(), savedAsset.getId(), savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.UNASSIGNED_FROM_CUSTOMER, savedAsset.getId().toString(), publicCustomer.getId().toString(), publicCustomer.getTitle()); + ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, savedAsset.getId().toString(), + publicCustomer.getId().toString(), publicCustomer.getTitle()); foundAsset = doGet("/api/asset/" + savedAsset.getId().getId().toString(), Asset.class); Assert.assertEquals(ModelConstants.NULL_UUID, foundAsset.getCustomerId().getId()); @@ -513,7 +516,7 @@ public class AssetControllerTest extends AbstractControllerTest { } List loadedAssets = new ArrayList<>(); PageLink pageLink = new PageLink(23); - PageData pageData = null; + PageData pageData; do { pageData = doGetTypedWithPageLink("/api/tenant/assets?", new TypeReference>() { @@ -524,14 +527,14 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Asset(), new Asset(), + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Asset(), new Asset(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, cntEntity); + ActionType.ADDED, cntEntity, cntEntity, cntEntity); loadedAssets.removeIf(asset -> asset.getType().equals(DefaultRuleEngineStatisticsService.TB_SERVICE_QUEUE)); - Collections.sort(assets, idComparator); - Collections.sort(loadedAssets, idComparator); + assets.sort(idComparator); + loadedAssets.sort(idComparator); Assert.assertEquals(assets, loadedAssets); } @@ -574,8 +577,8 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(assetsTitle1, idComparator); - Collections.sort(loadedAssetsTitle1, idComparator); + assetsTitle1.sort(idComparator); + loadedAssetsTitle1.sort(idComparator); Assert.assertEquals(assetsTitle1, loadedAssetsTitle1); @@ -591,8 +594,8 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(assetsTitle2, idComparator); - Collections.sort(loadedAssetsTitle2, idComparator); + assetsTitle2.sort(idComparator); + loadedAssetsTitle2.sort(idComparator); Assert.assertEquals(assetsTitle2, loadedAssetsTitle2); @@ -661,8 +664,8 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(assetsType1, idComparator); - Collections.sort(loadedAssetsType1, idComparator); + assetsType1.sort(idComparator); + loadedAssetsType1.sort(idComparator); Assert.assertEquals(assetsType1, loadedAssetsType1); @@ -678,8 +681,8 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(assetsType2, idComparator); - Collections.sort(loadedAssetsType2, idComparator); + assetsType2.sort(idComparator); + loadedAssetsType2.sort(idComparator); Assert.assertEquals(assetsType2, loadedAssetsType2); @@ -738,8 +741,8 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(assets, idComparator); - Collections.sort(loadedAssets, idComparator); + assets.sort(idComparator); + loadedAssets.sort(idComparator); Assert.assertEquals(assets, loadedAssets); } @@ -791,8 +794,8 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(assetsTitle1, idComparator); - Collections.sort(loadedAssetsTitle1, idComparator); + assetsTitle1.sort(idComparator); + loadedAssetsTitle1.sort(idComparator); Assert.assertEquals(assetsTitle1, loadedAssetsTitle1); @@ -808,8 +811,8 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(assetsTitle2, idComparator); - Collections.sort(loadedAssetsTitle2, idComparator); + assetsTitle2.sort(idComparator); + loadedAssetsTitle2.sort(idComparator); Assert.assertEquals(assetsTitle2, loadedAssetsTitle2); @@ -887,8 +890,8 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(assetsType1, idComparator); - Collections.sort(loadedAssetsType1, idComparator); + assetsType1.sort(idComparator); + loadedAssetsType1.sort(idComparator); Assert.assertEquals(assetsType1, loadedAssetsType1); @@ -904,8 +907,8 @@ public class AssetControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(assetsType2, idComparator); - Collections.sort(loadedAssetsType2, idComparator); + assetsType2.sort(idComparator); + loadedAssetsType2.sort(idComparator); Assert.assertEquals(assetsType2, loadedAssetsType2); diff --git a/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java index c84b058cc7..38420c3e32 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AssetProfileControllerTest.java @@ -355,7 +355,7 @@ public class AssetProfileControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new AssetProfile(), new AssetProfile(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, ActionType.ADDED, cntEntity, cntEntity, cntEntity); + ActionType.ADDED, cntEntity, cntEntity, cntEntity); Mockito.reset(tbClusterService, auditLogService); List loadedAssetProfiles = new ArrayList<>(); @@ -384,7 +384,7 @@ public class AssetProfileControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(loadedAssetProfiles.get(0), loadedAssetProfiles.get(0), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.DELETED, ActionType.DELETED, cntEntity, cntEntity, cntEntity, loadedAssetProfiles.get(0).getId().getId().toString()); + ActionType.DELETED, cntEntity, cntEntity, cntEntity, loadedAssetProfiles.get(0).getId().getId().toString()); pageLink = new PageLink(17); pageData = doGetTypedWithPageLink("/api/assetProfiles?", diff --git a/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java index 125e533471..f5c33debb2 100644 --- a/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java @@ -117,8 +117,8 @@ public class CustomerControllerTest extends AbstractControllerTest { Customer savedCustomer = doPost("/api/customer", customer, Customer.class); - testNotifyEntityOneTimeMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(), savedCustomer.getId(), - savedCustomer.getTenantId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + testNotifyEntityAllOneTime(savedCustomer, savedCustomer.getId(), savedCustomer.getId(), savedCustomer.getTenantId(), + new CustomerId(CustomerId.NULL_UUID), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED); Assert.assertNotNull(savedCustomer); @@ -242,7 +242,7 @@ public class CustomerControllerTest extends AbstractControllerTest { doDelete("/api/customer/" + savedCustomer.getId().getId().toString()) .andExpect(status().isOk()); - testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(), + testNotifyEntityBroadcastEntityStateChangeEventOneTime(savedCustomer, savedCustomer.getId(), savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString()); } @@ -272,7 +272,7 @@ public class CustomerControllerTest extends AbstractControllerTest { doDelete("/api/customer/" + savedCustomer.getId().getId().toString()) .andExpect(status().isOk()); - testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedCustomer, savedCustomer.getId(), + testNotifyEntityBroadcastEntityStateChangeEventOneTime(savedCustomer, savedCustomer.getId(), savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString()); @@ -332,9 +332,9 @@ public class CustomerControllerTest extends AbstractControllerTest { } List customers = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS); - testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Customer(), new Customer(), + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Customer(), new Customer(), tenantId, tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, cntEntity); + ActionType.ADDED, cntEntity, cntEntity, cntEntity); List loadedCustomers = new ArrayList<>(135); PageLink pageLink = new PageLink(23); diff --git a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java index 9f8e63e3b0..6f0d6f9465 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DashboardControllerTest.java @@ -46,7 +46,6 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DaoSqlTest; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import static org.hamcrest.Matchers.containsString; @@ -154,7 +153,7 @@ public class DashboardControllerTest extends AbstractControllerTest { doDelete("/api/dashboard/" + savedDashboard.getId().getId().toString()).andExpect(status().isOk()); - testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDashboard, savedDashboard.getId(), savedDashboard.getId(), + testNotifyEntityAllOneTime(savedDashboard, savedDashboard.getId(), savedDashboard.getId(), savedDashboard.getTenantId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED, savedDashboard.getId().getId().toString()); @@ -198,7 +197,7 @@ public class DashboardControllerTest extends AbstractControllerTest { testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(), savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER, - assignedDashboard .getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); + ActionType.UPDATED, assignedDashboard.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); Assert.assertTrue(foundDashboard.getAssignedCustomers().contains(savedCustomer.toShortCustomerInfo())); @@ -210,7 +209,7 @@ public class DashboardControllerTest extends AbstractControllerTest { testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(), savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER, - unassignedDashboard.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); + ActionType.UPDATED, unassignedDashboard.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); Assert.assertTrue(unassignedDashboard.getAssignedCustomers() == null || unassignedDashboard.getAssignedCustomers().isEmpty()); @@ -241,7 +240,7 @@ public class DashboardControllerTest extends AbstractControllerTest { testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(), savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER, - assignedDashboard .getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle()); + ActionType.UPDATED, assignedDashboard .getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle()); Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); Assert.assertTrue(foundDashboard.getAssignedCustomers().contains(publicCustomer.toShortCustomerInfo())); @@ -253,7 +252,7 @@ public class DashboardControllerTest extends AbstractControllerTest { testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(), savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER, - unassignedDashboard.getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle()); + ActionType.UPDATED, unassignedDashboard.getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle()); Assert.assertTrue(unassignedDashboard.getAssignedCustomers() == null || unassignedDashboard.getAssignedCustomers().isEmpty()); @@ -339,9 +338,9 @@ public class DashboardControllerTest extends AbstractControllerTest { dashboards.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class))); } - testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Dashboard(), new Dashboard(), + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Dashboard(), new Dashboard(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, cntEntity); + ActionType.ADDED, cntEntity, cntEntity, cntEntity); List loadedDashboards = new ArrayList<>(); PageLink pageLink = new PageLink(24); @@ -356,8 +355,8 @@ public class DashboardControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(dashboards, idComparator); - Collections.sort(loadedDashboards, idComparator); + dashboards.sort(idComparator); + loadedDashboards.sort(idComparator); Assert.assertEquals(dashboards, loadedDashboards); } @@ -400,8 +399,8 @@ public class DashboardControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(dashboardsTitle1, idComparator); - Collections.sort(loadedDashboardsTitle1, idComparator); + dashboardsTitle1.sort(idComparator); + loadedDashboardsTitle1.sort(idComparator); Assert.assertEquals(dashboardsTitle1, loadedDashboardsTitle1); @@ -417,8 +416,8 @@ public class DashboardControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(dashboardsTitle2, idComparator); - Collections.sort(loadedDashboardsTitle2, idComparator); + dashboardsTitle2.sort(idComparator); + loadedDashboardsTitle2.sort(idComparator); Assert.assertEquals(dashboardsTitle2, loadedDashboardsTitle2); @@ -429,9 +428,9 @@ public class DashboardControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); } - testNotifyManyEntityManyTimeMsgToEdgeServiceNeverAdditionalInfoAny(new Dashboard(), new Dashboard(), + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Dashboard(), new Dashboard(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.DELETED, cntEntity, 1); + ActionType.DELETED, ActionType.DELETED, cntEntity, cntEntity, 1); pageLink = new PageLink(4, 0, title1); pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", @@ -474,7 +473,7 @@ public class DashboardControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Dashboard(), new Dashboard(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity*2); + ActionType.ADDED, cntEntity, cntEntity, cntEntity*2); List loadedDashboards = new ArrayList<>(); PageLink pageLink = new PageLink(21); @@ -489,8 +488,8 @@ public class DashboardControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(dashboards, idComparator); - Collections.sort(loadedDashboards, idComparator); + dashboards.sort(idComparator); + loadedDashboards.sort(idComparator); Assert.assertEquals(dashboards, loadedDashboards); } diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java index 1c952bd549..5cc9c3dc91 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java @@ -156,9 +156,8 @@ public class DeviceControllerTest extends AbstractControllerTest { Device oldDevice = new Device(savedDevice); - testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(), - savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED); + testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(), + tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED); testNotificationUpdateGatewayNever(); Assert.assertNotNull(savedDevice); @@ -212,7 +211,7 @@ public class DeviceControllerTest extends AbstractControllerTest { Device oldDevice = new Device(savedDevice); - testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(), + testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED); testNotificationUpdateGatewayNever(); @@ -436,6 +435,9 @@ public class DeviceControllerTest extends AbstractControllerTest { @Test public void testFindDeviceTypesByTenantId() throws Exception { + DeviceProfile deviceProfile = createDeviceProfile("typeB"); + deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); + List devices = new ArrayList<>(); int cntEntity = 3; @@ -446,12 +448,13 @@ public class DeviceControllerTest extends AbstractControllerTest { Device device = new Device(); device.setName("My device B" + i); device.setType("typeB"); + device.setDeviceProfileId(deviceProfile.getId()); devices.add(doPost("/api/device", device, Device.class)); } - testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Device(), new Device(), + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Device(), new Device(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, cntEntity); + ActionType.ADDED, cntEntity, cntEntity, cntEntity); testNotificationUpdateGatewayNever(); for (int i = 0; i < 7; i++) { @@ -491,7 +494,7 @@ public class DeviceControllerTest extends AbstractControllerTest { doDelete("/api/device/" + savedDevice.getId().getId()) .andExpect(status().isOk()); - testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(), + testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED, savedDevice.getId().getId().toString()); testNotificationDeleteGatewayOneTime(savedDevice); @@ -511,7 +514,7 @@ public class DeviceControllerTest extends AbstractControllerTest { Device savedDevice = doPost("/api/device", device, Device.class); Assert.assertEquals("default", savedDevice.getType()); - testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(), + testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED); testNotificationUpdateGatewayNever(); @@ -551,9 +554,9 @@ public class DeviceControllerTest extends AbstractControllerTest { + "/device/" + savedDevice.getId().getId(), Device.class); Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId()); - testNotifyEntityAllOneTime(assignedDevice, assignedDevice.getId(), assignedDevice.getId(), savedTenant.getId(), + testNotifyAssignUnassignEntityAllOneTime(assignedDevice, assignedDevice.getId(), assignedDevice.getId(), savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER, - assignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(), + ActionType.UPDATED, assignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); testNotificationUpdateGatewayNever(); @@ -566,9 +569,9 @@ public class DeviceControllerTest extends AbstractControllerTest { doDelete("/api/customer/device/" + savedDevice.getId().getId(), Device.class); Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId()); - testNotifyEntityAllOneTime(unassignedDevice, unassignedDevice.getId(), unassignedDevice.getId(), savedTenant.getId(), + testNotifyAssignUnassignEntityAllOneTime(unassignedDevice, unassignedDevice.getId(), unassignedDevice.getId(), savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER, - unassignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(), + ActionType.UPDATED, unassignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); testNotificationDeleteGatewayNever(); @@ -590,9 +593,9 @@ public class DeviceControllerTest extends AbstractControllerTest { Customer publicCustomer = doGet("/api/customer/" + assignedDevice.getCustomerId(), Customer.class); Assert.assertTrue(publicCustomer.isPublic()); - testNotifyEntityAllOneTime(assignedDevice, assignedDevice.getId(), assignedDevice.getId(), savedTenant.getId(), + testNotifyAssignUnassignEntityAllOneTime(assignedDevice, assignedDevice.getId(), assignedDevice.getId(), savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER, - assignedDevice.getId().getId().toString(), publicCustomer.getId().getId().toString(), + ActionType.UPDATED, assignedDevice.getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle()); testNotificationUpdateGatewayNever(); @@ -605,9 +608,9 @@ public class DeviceControllerTest extends AbstractControllerTest { doDelete("/api/customer/device/" + savedDevice.getId().getId(), Device.class); Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId()); - testNotifyEntityAllOneTime(unassignedDevice, unassignedDevice.getId(), unassignedDevice.getId(), savedTenant.getId(), + testNotifyAssignUnassignEntityAllOneTime(unassignedDevice, unassignedDevice.getId(), unassignedDevice.getId(), savedTenant.getId(), publicCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER, - unassignedDevice.getId().getId().toString(), publicCustomer.getId().getId().toString(), + ActionType.UPDATED, unassignedDevice.getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle()); testNotificationDeleteGatewayNever(); @@ -842,9 +845,9 @@ public class DeviceControllerTest extends AbstractControllerTest { List devices = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS); - testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Device(), new Device(), + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Device(), new Device(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, cntEntity); + ActionType.ADDED, cntEntity, cntEntity, cntEntity); testNotificationUpdateGatewayNever(); List loadedDevices = new ArrayList<>(cntEntity); @@ -865,9 +868,9 @@ public class DeviceControllerTest extends AbstractControllerTest { deleteEntitiesAsync("/api/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS); - testNotifyManyEntityManyTimeMsgToEdgeServiceNeverAdditionalInfoAny(new Device(), new Device(), + testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Device(), new Device(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.DELETED, cntEntity, 1); + ActionType.DELETED, ActionType.DELETED, cntEntity, cntEntity,1); testNotificationUpdateGatewayNever(); } @@ -1052,7 +1055,7 @@ public class DeviceControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Device(), new Device(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity * 2); + ActionType.ADDED, cntEntity, cntEntity, cntEntity * 2); Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService); testNotificationUpdateGatewayNever(); Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService); @@ -1074,7 +1077,7 @@ public class DeviceControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Device(), new Device(), savedTenant.getId(), customerId, tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UNASSIGNED_FROM_CUSTOMER, cntEntity, cntEntity, 3); + ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, cntEntity, cntEntity, 3); testNotificationUpdateGatewayNever(); } diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java index d2bcfe2b88..14b052d93c 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceProfileControllerTest.java @@ -498,7 +498,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new DeviceProfile(), new DeviceProfile(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, ActionType.ADDED, cntEntity, cntEntity, cntEntity); + ActionType.ADDED, cntEntity, cntEntity, cntEntity); Mockito.reset(tbClusterService, auditLogService); List loadedDeviceProfiles = new ArrayList<>(); @@ -527,7 +527,7 @@ public class DeviceProfileControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(loadedDeviceProfiles.get(0), loadedDeviceProfiles.get(0), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.DELETED, ActionType.DELETED, cntEntity, cntEntity, cntEntity, loadedDeviceProfiles.get(0).getId().getId().toString()); + ActionType.DELETED, cntEntity, cntEntity, cntEntity, loadedDeviceProfiles.get(0).getId().getId().toString()); pageLink = new PageLink(17); pageData = doGetTypedWithPageLink("/api/deviceProfiles?", diff --git a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java index c8a20a38f5..78729eecf1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java @@ -21,6 +21,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; +import com.google.protobuf.AbstractMessage; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -45,7 +46,6 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; @@ -62,6 +62,8 @@ import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; import org.thingsboard.server.gen.edge.v1.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg; +import org.thingsboard.server.gen.edge.v1.SyncCompletedMsg; +import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UserCredentialsUpdateMsg; import org.thingsboard.server.gen.edge.v1.UserUpdateMsg; @@ -77,6 +79,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @TestPropertySource(properties = { "edges.enabled=true", + "queue.rule-engine.stats.enabled=false" }) @ContextConfiguration(classes = {EdgeControllerTest.Config.class}) @DaoSqlTest @@ -87,10 +90,6 @@ public class EdgeControllerTest extends AbstractControllerTest { private IdComparator idComparator = new IdComparator<>(); - private Tenant savedTenant; - private TenantId tenantId; - private User tenantAdmin; - ListeningExecutorService executor; List> futures; @@ -107,35 +106,14 @@ public class EdgeControllerTest extends AbstractControllerTest { } @Before - public void beforeTest() throws Exception { + public void setupEdgeTest() throws Exception { executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass())); - - loginSysAdmin(); - - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant for Edge"); - savedTenant = doPost("/api/tenant", tenant, Tenant.class); - tenantId = savedTenant.getId(); - Assert.assertNotNull(savedTenant); - - tenantAdmin = new User(); - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); - tenantAdmin.setTenantId(savedTenant.getId()); - tenantAdmin.setEmail("tenant2@thingsboard.org"); - tenantAdmin.setFirstName("Joe"); - tenantAdmin.setLastName("Downs"); - - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + loginTenantAdmin(); } @After - public void afterTest() throws Exception { + public void teardownEdgeTest() throws Exception { executor.shutdownNow(); - - loginSysAdmin(); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test @@ -149,13 +127,13 @@ public class EdgeControllerTest extends AbstractControllerTest { Assert.assertNotNull(savedEdge); Assert.assertNotNull(savedEdge.getId()); Assert.assertTrue(savedEdge.getCreatedTime() > 0); - Assert.assertEquals(savedTenant.getId(), savedEdge.getTenantId()); + Assert.assertEquals(tenantId, savedEdge.getTenantId()); Assert.assertNotNull(savedEdge.getCustomerId()); Assert.assertEquals(NULL_UUID, savedEdge.getCustomerId().getId()); Assert.assertEquals(edge.getName(), savedEdge.getName()); testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedEdge, savedEdge.getId(), savedEdge.getId(), - savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + tenantId, tenantAdminUser.getCustomerId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED); savedEdge.setName("My new edge"); @@ -165,7 +143,7 @@ public class EdgeControllerTest extends AbstractControllerTest { Assert.assertEquals(foundEdge.getName(), savedEdge.getName()); testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(foundEdge, foundEdge.getId(), foundEdge.getId(), - savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + tenantId, tenantAdminUser.getCustomerId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.UPDATED); } @@ -180,8 +158,8 @@ public class EdgeControllerTest extends AbstractControllerTest { .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString(msgError))); - testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId, + tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); msgError = msgErrorFieldLength("type"); @@ -191,8 +169,8 @@ public class EdgeControllerTest extends AbstractControllerTest { .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString(msgError))); - testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId, + tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); Mockito.reset(tbClusterService, auditLogService); msgError = msgErrorFieldLength("label"); @@ -202,8 +180,8 @@ public class EdgeControllerTest extends AbstractControllerTest { .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString(msgError))); - testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId, + tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @Test @@ -229,7 +207,7 @@ public class EdgeControllerTest extends AbstractControllerTest { } testNotifyManyEntityManyTimeMsgToEdgeServiceNeverAdditionalInfoAny(new Edge(), new Edge(), - savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + tenantId, tenantAdminUser.getCustomerId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, cntEntity, 0); for (int i = 0; i < 7; i++) { @@ -262,7 +240,7 @@ public class EdgeControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedEdge, savedEdge.getId(), savedEdge.getId(), - savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), + tenantId, tenantAdminUser.getCustomerId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.DELETED, savedEdge.getId().getId().toString()); doGet("/api/edge/" + savedEdge.getId().getId().toString()) @@ -281,8 +259,8 @@ public class EdgeControllerTest extends AbstractControllerTest { .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString(msgError))); - testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId, + tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @Test @@ -296,8 +274,8 @@ public class EdgeControllerTest extends AbstractControllerTest { .andExpect(status().isBadRequest()) .andExpect(statusReason(containsString(msgError))); - testNotifyEntityEqualsOneTimeServiceNeverError(edge, savedTenant.getId(), - tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); + testNotifyEntityEqualsOneTimeServiceNeverError(edge, tenantId, + tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); } @Test @@ -316,8 +294,8 @@ public class EdgeControllerTest extends AbstractControllerTest { Assert.assertEquals(savedCustomer.getId(), assignedEdge.getCustomerId()); testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedEdge, assignedEdge.getId(), assignedEdge.getId(), - savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER, - assignedEdge.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); + tenantId, savedCustomer.getId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER, + ActionType.ASSIGNED_TO_CUSTOMER, assignedEdge.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); Edge foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); Assert.assertEquals(savedCustomer.getId(), foundEdge.getCustomerId()); @@ -327,8 +305,8 @@ public class EdgeControllerTest extends AbstractControllerTest { Assert.assertEquals(ModelConstants.NULL_UUID, unassignedEdge.getCustomerId().getId()); testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(unassignedEdge, unassignedEdge.getId(), unassignedEdge.getId(), - savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER, - unassignedEdge.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); + tenantId, savedCustomer.getId(), tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER, + ActionType.UNASSIGNED_FROM_CUSTOMER, unassignedEdge.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle()); foundEdge = doGet("/api/edge/" + savedEdge.getId().getId().toString(), Edge.class); Assert.assertEquals(ModelConstants.NULL_UUID, foundEdge.getCustomerId().getId()); @@ -375,7 +353,7 @@ public class EdgeControllerTest extends AbstractControllerTest { customer.setTitle("Different customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); - login(tenantAdmin.getEmail(), "testPassword1"); + loginTenantAdmin(); Edge edge = constructEdge("My edge", "default"); Edge savedEdge = doPost("/api/edge", edge, Edge.class); @@ -625,8 +603,8 @@ public class EdgeControllerTest extends AbstractControllerTest { List edges = new ArrayList<>(Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS)); testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Edge(), new Edge(), - savedTenant.getId(), customerId, tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ASSIGNED_TO_CUSTOMER, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity * 2, + tenantId, customerId, tenantAdminUser.getId(), tenantAdminUser.getEmail(), + ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity * 2, new String(), new String(), new String()); List loadedEdges = new ArrayList<>(); @@ -731,7 +709,7 @@ public class EdgeControllerTest extends AbstractControllerTest { cntEntity = loadedEdgesTitle1.size(); testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Edge(), new Edge(), - savedTenant.getId(), customerId, tenantAdmin.getId(), tenantAdmin.getEmail(), + tenantId, customerId, tenantAdminUser.getId(), tenantAdminUser.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UNASSIGNED_FROM_CUSTOMER, cntEntity, cntEntity, 3); pageLink = new PageLink(4, 0, title1); @@ -857,56 +835,45 @@ public class EdgeControllerTest extends AbstractControllerTest { @Test public void testSyncEdge() throws Exception { - Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge", "test"), Edge.class); + Asset asset = new Asset(); + asset.setName("Test Sync Edge Asset 1"); + asset.setType("test"); + Asset savedAsset = doPost("/api/asset", asset, Asset.class); Device device = new Device(); device.setName("Test Sync Edge Device 1"); device.setType("default"); Device savedDevice = doPost("/api/device", device, Device.class); + + Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge", "test"), Edge.class); + doPost("/api/edge/" + edge.getId().getId().toString() + "/device/" + savedDevice.getId().getId().toString(), Device.class); - - Asset asset = new Asset(); - asset.setName("Test Sync Edge Asset 1"); - asset.setType("test"); - Asset savedAsset = doPost("/api/asset", asset, Asset.class); doPost("/api/edge/" + edge.getId().getId().toString() + "/asset/" + savedAsset.getId().getId().toString(), Asset.class); EdgeImitator edgeImitator = new EdgeImitator(EDGE_HOST, EDGE_PORT, edge.getRoutingKey(), edge.getSecret()); edgeImitator.ignoreType(UserCredentialsUpdateMsg.class); - edgeImitator.expectMessageAmount(20); + edgeImitator.expectMessageAmount(21); edgeImitator.connect(); assertThat(edgeImitator.waitForMessages()).as("await for messages on first connect").isTrue(); - assertThat(edgeImitator.findAllMessagesByType(QueueUpdateMsg.class)).as("one msg during sync process").hasSize(1); - List ruleChainUpdateMsgs = edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class); - assertThat(ruleChainUpdateMsgs).as("one msg during sync process, another from edge creation").hasSize(2); - assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("one msg during sync process for 'default' device profile").hasSize(3); - assertThat(edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class)).as("one msg once device assigned to edge").hasSize(2); - assertThat(edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class)).as("two msgs during sync process for 'default' and 'test' asset profiles").hasSize(4); - assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("two msgs - one during sync process, and one more once asset assigned to edge").hasSize(2); - assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("one msg during sync process for tenant admin user").hasSize(1); - assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update").hasSize(4); - assertThat(edgeImitator.findAllMessagesByType(CustomerUpdateMsg.class)).as("one msg during sync process for 'Public' customer").hasSize(1); - verifyRuleChainMsgsAreRoot(ruleChainUpdateMsgs); - - edgeImitator.expectMessageAmount(15); + verifyFetchersMsgs(edgeImitator); + // verify queue msgs + Assert.assertTrue(popRuleChainMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, "Edge Root Rule Chain")); + Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default")); + Assert.assertTrue(popDeviceMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Device 1")); + Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "test")); + Assert.assertTrue(popAssetMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Asset 1")); + Assert.assertTrue(edgeImitator.getDownlinkMsgs().isEmpty()); + + edgeImitator.expectMessageAmount(16); doPost("/api/edge/sync/" + edge.getId()); assertThat(edgeImitator.waitForMessages()).as("await for messages after edge sync rest api call").isTrue(); - assertThat(edgeImitator.findAllMessagesByType(QueueUpdateMsg.class)).as("queue msg").hasSize(1); - ruleChainUpdateMsgs = edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class); - assertThat(ruleChainUpdateMsgs).as("rule chain msg").hasSize(1); - assertThat(edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class)).as("device profile msg").hasSize(2); - assertThat(edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class)).as("asset profile msg").hasSize(3); - assertThat(edgeImitator.findAllMessagesByType(AssetUpdateMsg.class)).as("asset update msg").hasSize(1); - assertThat(edgeImitator.findAllMessagesByType(UserUpdateMsg.class)).as("user update msg").hasSize(1); - assertThat(edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class)).as("admin setting update msg").hasSize(4); - assertThat(edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class)).as("asset update msg").hasSize(1); - assertThat(edgeImitator.findAllMessagesByType(CustomerUpdateMsg.class)).as("one msg during sync process for 'Public' customer").hasSize(1); - verifyRuleChainMsgsAreRoot(ruleChainUpdateMsgs); + verifyFetchersMsgs(edgeImitator); + Assert.assertTrue(edgeImitator.getDownlinkMsgs().isEmpty()); edgeImitator.allowIgnoredTypes(); try { @@ -922,23 +889,174 @@ public class EdgeControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); } - private void verifyRuleChainMsgsAreRoot(List ruleChainUpdateMsgs) { - for (RuleChainUpdateMsg ruleChainUpdateMsg : ruleChainUpdateMsgs) { - Assert.assertTrue(ruleChainUpdateMsg.getRoot()); + private void verifyFetchersMsgs(EdgeImitator edgeImitator) { + Assert.assertTrue(popQueueMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Main")); + Assert.assertTrue(popRuleChainMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Edge Root Rule Chain")); + Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mail", true)); + Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mail", false)); + Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mailTemplates", true)); + Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mailTemplates", false)); + Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default")); + Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default")); + Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "test")); + Assert.assertTrue(popUserMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, TENANT_ADMIN_EMAIL, Authority.TENANT_ADMIN)); + Assert.assertTrue(popCustomerMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Public")); + Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default")); + Assert.assertTrue(popDeviceMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Device 1")); + Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "test")); + Assert.assertTrue(popAssetMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Asset 1")); + Assert.assertTrue(popSyncCompletedMsg(edgeImitator.getDownlinkMsgs())); + } + + private boolean popQueueMsg(List messages, UpdateMsgType msgType, String name) { + for (AbstractMessage message : messages) { + if (message instanceof QueueUpdateMsg) { + QueueUpdateMsg queueUpdateMsg = (QueueUpdateMsg) message; + if (msgType.equals(queueUpdateMsg.getMsgType()) + && name.equals(queueUpdateMsg.getName())) { + messages.remove(message); + return true; + } + } + } + return false; + } + + private boolean popRuleChainMsg(List messages, UpdateMsgType msgType, String name) { + for (AbstractMessage message : messages) { + if (message instanceof RuleChainUpdateMsg) { + RuleChainUpdateMsg ruleChainUpdateMsg = (RuleChainUpdateMsg) message; + if (msgType.equals(ruleChainUpdateMsg.getMsgType()) + && name.equals(ruleChainUpdateMsg.getName()) + && ruleChainUpdateMsg.getRoot()) { + messages.remove(message); + return true; + } + } + } + return false; + } + + private boolean popAdminSettingsMsg(List messages, String key, boolean isSystem) { + for (AbstractMessage message : messages) { + if (message instanceof AdminSettingsUpdateMsg) { + AdminSettingsUpdateMsg adminSettingsUpdateMsg = (AdminSettingsUpdateMsg) message; + if (key.equals(adminSettingsUpdateMsg.getKey()) + && isSystem == adminSettingsUpdateMsg.getIsSystem()) { + messages.remove(message); + return true; + } + } + } + return false; + } + + private boolean popDeviceProfileMsg(List messages, UpdateMsgType msgType, String name) { + for (AbstractMessage message : messages) { + if (message instanceof DeviceProfileUpdateMsg) { + DeviceProfileUpdateMsg deviceProfileUpdateMsg = (DeviceProfileUpdateMsg) message; + if (msgType.equals(deviceProfileUpdateMsg.getMsgType()) + && name.equals(deviceProfileUpdateMsg.getName())) { + messages.remove(message); + return true; + } + } + } + return false; + } + + private boolean popDeviceMsg(List messages, UpdateMsgType msgType, String name) { + for (AbstractMessage message : messages) { + if (message instanceof DeviceUpdateMsg) { + DeviceUpdateMsg deviceUpdateMsg = (DeviceUpdateMsg) message; + if (msgType.equals(deviceUpdateMsg.getMsgType()) + && name.equals(deviceUpdateMsg.getName())) { + messages.remove(message); + return true; + } + } + } + return false; + } + + private boolean popAssetProfileMsg(List messages, UpdateMsgType msgType, String name) { + for (AbstractMessage message : messages) { + if (message instanceof AssetProfileUpdateMsg) { + AssetProfileUpdateMsg assetProfileUpdateMsg = (AssetProfileUpdateMsg) message; + if (msgType.equals(assetProfileUpdateMsg.getMsgType()) + && name.equals(assetProfileUpdateMsg.getName())) { + messages.remove(message); + return true; + } + } + } + return false; + } + + private boolean popAssetMsg(List messages, UpdateMsgType msgType, String name) { + for (AbstractMessage message : messages) { + if (message instanceof AssetUpdateMsg) { + AssetUpdateMsg assetUpdateMsg = (AssetUpdateMsg) message; + if (msgType.equals(assetUpdateMsg.getMsgType()) + && name.equals(assetUpdateMsg.getName())) { + messages.remove(message); + return true; + } + } + } + return false; + } + + private boolean popUserMsg(List messages, UpdateMsgType msgType, String email, Authority authority) { + for (AbstractMessage message : messages) { + if (message instanceof UserUpdateMsg) { + UserUpdateMsg userUpdateMsg = (UserUpdateMsg) message; + if (msgType.equals(userUpdateMsg.getMsgType()) + && email.equals(userUpdateMsg.getEmail()) + && authority.name().equals(userUpdateMsg.getAuthority())) { + messages.remove(message); + return true; + } + } + } + return false; + } + + private boolean popCustomerMsg(List messages, UpdateMsgType msgType, String title) { + for (AbstractMessage message : messages) { + if (message instanceof CustomerUpdateMsg) { + CustomerUpdateMsg customerUpdateMsg = (CustomerUpdateMsg) message; + if (msgType.equals(customerUpdateMsg.getMsgType()) + && title.equals(customerUpdateMsg.getTitle())) { + messages.remove(message); + return true; + } + } + } + return false; + } + + private boolean popSyncCompletedMsg(List messages) { + for (AbstractMessage message : messages) { + if (message instanceof SyncCompletedMsg) { + messages.remove(message); + return true; + } } + return false; } @Test public void testDeleteEdgeWithDeleteRelationsOk() throws Exception { EdgeId edgeId = savedEdge("Edge for Test WithRelationsOk").getId(); - testEntityDaoWithRelationsOk(savedTenant.getId(), edgeId, "/api/edge/" + edgeId); + testEntityDaoWithRelationsOk(tenantId, edgeId, "/api/edge/" + edgeId); } @Ignore @Test public void testDeleteEdgeExceptionWithRelationsTransactional() throws Exception { EdgeId edgeId = savedEdge("Edge for Test WithRelations Transactional Exception").getId(); - testEntityDaoWithRelationsTransactionalException(edgeDao, savedTenant.getId(), edgeId, "/api/edge/" + edgeId); + testEntityDaoWithRelationsTransactionalException(edgeDao, tenantId, edgeId, "/api/edge/" + edgeId); } private Edge savedEdge(String name) { diff --git a/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java index 255aa2bdf1..04842df6a0 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java @@ -27,8 +27,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.context.TestPropertySource; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; @@ -38,7 +36,6 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; -import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.edge.EdgeEventDao; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; @@ -54,18 +51,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @TestPropertySource(properties = { "edges.enabled=true", + "queue.rule-engine.stats.enabled=false" }) @Slf4j @DaoSqlTest public class EdgeEventControllerTest extends AbstractControllerTest { - private Tenant savedTenant; - private User tenantAdmin; - @Autowired private EdgeEventDao edgeEventDao; @SpyBean @@ -80,33 +74,11 @@ public class EdgeEventControllerTest extends AbstractControllerTest { @Before public void beforeTest() throws Exception { - loginSysAdmin(); - - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - savedTenant = doPost("/api/tenant", tenant, Tenant.class); - Assert.assertNotNull(savedTenant); - - tenantAdmin = new User(); - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); - tenantAdmin.setTenantId(savedTenant.getId()); - tenantAdmin.setEmail("tenant2@thingsboard.org"); - tenantAdmin.setFirstName("Joe"); - tenantAdmin.setLastName("Downs"); - - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); - // sleep 1 seconds to avoid CREDENTIALS updated message for the user - // user credentials is going to be stored and updated event pushed to edge notification service - // while service will be processing this event edge could be already added and additional message will be pushed - Thread.sleep(1000); + loginTenantAdmin(); } @After public void afterTest() throws Exception { - loginSysAdmin(); - - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) - .andExpect(status().isOk()); } @Test @@ -127,19 +99,37 @@ public class EdgeEventControllerTest extends AbstractControllerTest { EntityRelation relation = new EntityRelation(savedAsset.getId(), savedDevice.getId(), EntityRelation.CONTAINS_TYPE); + awaitForNumberOfEdgeEvents(edgeId, 3); + doPost("/api/relation", relation); + awaitForNumberOfEdgeEvents(edgeId, 4); + + List edgeEvents = findEdgeEvents(edgeId); + Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.RULE_CHAIN)); // root rule chain + Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.DEVICE)); // TestDevice + Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.ASSET)); // TestAsset + Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.RELATION)); + Assert.assertTrue(edgeEvents.isEmpty()); + } + + private boolean popEdgeEvent(List edgeEvents, EdgeEventType edgeEventType) { + for (EdgeEvent edgeEvent : edgeEvents) { + if (edgeEventType.equals(edgeEvent.getType())) { + edgeEvents.remove(edgeEvent); + return true; + } + } + return false; + } + + private void awaitForNumberOfEdgeEvents(EdgeId edgeId, int expectedNumber) { Awaitility.await() .atMost(30, TimeUnit.SECONDS) .until(() -> { List edgeEvents = findEdgeEvents(edgeId); - return edgeEvents.size() == 4; + return edgeEvents.size() == expectedNumber; }); - List edgeEvents = findEdgeEvents(edgeId); - Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RULE_CHAIN.equals(ee.getType()))); - Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.DEVICE.equals(ee.getType()))); - Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.ASSET.equals(ee.getType()))); - Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RELATION.equals(ee.getType()))); } @Test @@ -195,7 +185,7 @@ public class EdgeEventControllerTest extends AbstractControllerTest { edgeEvent.setCreatedTime(System.currentTimeMillis()); edgeEvent.setTenantId(tenantId); edgeEvent.setAction(EdgeEventActionType.ADDED); - edgeEvent.setEntityId(tenantAdmin.getUuidId()); + edgeEvent.setEntityId(tenantAdminUser.getUuidId()); edgeEvent.setType(EdgeEventType.ALARM); try { edgeEventDao.saveAsync(edgeEvent).get(); diff --git a/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java index cb41019f6f..beabcf77d1 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java @@ -171,7 +171,7 @@ public class EntityViewControllerTest extends AbstractControllerTest { testBroadcastEntityStateChangeEventTime(foundEntityView.getId(), tenantId, 1); testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundEntityView, foundEntityView, tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.ADDED, ActionType.ADDED, 1, 0, 1); + ActionType.ADDED, 1, 1, 1); Mockito.reset(tbClusterService, auditLogService); savedView.setName("New test entity view"); @@ -184,7 +184,7 @@ public class EntityViewControllerTest extends AbstractControllerTest { testBroadcastEntityStateChangeEventTime(foundEntityView.getId(), tenantId, 1); testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundEntityView, foundEntityView, tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.UPDATED, ActionType.UPDATED, 1, 1, 5); + ActionType.UPDATED, 1, 1, 5); doGet("/api/tenant/entityViews?entityViewName=" + name) .andExpect(status().isNotFound()) @@ -248,7 +248,7 @@ public class EntityViewControllerTest extends AbstractControllerTest { doDelete("/api/entityView/" + entityIdStr) .andExpect(status().isOk()); - testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedView, savedView.getId(), savedView.getId(), + testNotifyEntityBroadcastEntityStateChangeEventOneTime(savedView, savedView.getId(), savedView.getId(), tenantId, view.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.DELETED, entityIdStr); @@ -287,7 +287,7 @@ public class EntityViewControllerTest extends AbstractControllerTest { testBroadcastEntityStateChangeEventTime(savedView.getId(), tenantId, 1); testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(savedView, savedView, tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.UPDATED, ActionType.UPDATED, 1, 1, 5); + ActionType.UPDATED, 1, 1, 5); Mockito.reset(tbClusterService, auditLogService); EntityView assignedView = doPost( @@ -299,9 +299,9 @@ public class EntityViewControllerTest extends AbstractControllerTest { assertEquals(savedCustomer.getId(), foundView.getCustomerId()); testBroadcastEntityStateChangeEventNever(foundView.getId()); - testNotifyEntityAllOneTime(foundView, foundView.getId(), foundView.getId(), + testNotifyAssignUnassignEntityAllOneTime(foundView, foundView.getId(), foundView.getId(), tenantId, foundView.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.ASSIGNED_TO_CUSTOMER, + ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED, foundView.getId().getId().toString(), foundView.getCustomerId().getId().toString(), savedCustomer.getTitle()); EntityView unAssignedView = doDelete("/api/customer/entityView/" + savedView.getId().getId().toString(), EntityView.class); @@ -311,9 +311,9 @@ public class EntityViewControllerTest extends AbstractControllerTest { assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId()); testBroadcastEntityStateChangeEventNever(foundView.getId()); - testNotifyEntityAllOneTime(unAssignedView, savedView.getId(), savedView.getId(), + testNotifyAssignUnassignEntityAllOneTime(unAssignedView, savedView.getId(), savedView.getId(), tenantId, savedView.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.UNASSIGNED_FROM_CUSTOMER, + ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, assignedView.getId().getId().toString(), savedView.getCustomerId().getId().toString(), savedCustomer.getTitle()); } @@ -329,9 +329,9 @@ public class EntityViewControllerTest extends AbstractControllerTest { Assert.assertTrue(publicCustomer.isPublic()); testBroadcastEntityStateChangeEventNever(assignedView.getId()); - testNotifyEntityAllOneTime(assignedView, assignedView.getId(), assignedView.getId(), + testNotifyAssignUnassignEntityAllOneTime(assignedView, assignedView.getId(), assignedView.getId(), tenantId, assignedView.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.ASSIGNED_TO_CUSTOMER, + ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED, assignedView.getId().getId().toString(), assignedView.getCustomerId().getId().toString(), publicCustomer.getTitle()); EntityView foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); @@ -344,9 +344,9 @@ public class EntityViewControllerTest extends AbstractControllerTest { assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId()); testBroadcastEntityStateChangeEventNever(foundView.getId()); - testNotifyEntityAllOneTime(unAssignedView, unAssignedView.getId(), unAssignedView.getId(), + testNotifyAssignUnassignEntityAllOneTime(unAssignedView, unAssignedView.getId(), unAssignedView.getId(), tenantId, publicCustomer.getId(), tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.UNASSIGNED_FROM_CUSTOMER, + ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, unAssignedView.getId().getId().toString(), publicCustomer.getId().getId().toString(), publicCustomer.getTitle()); } @@ -426,12 +426,12 @@ public class EntityViewControllerTest extends AbstractControllerTest { testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(), tenantId, tenantAdminCustomerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.ADDED, ActionType.ADDED, cntEntity, 0, cntEntity * 2, 0); + ActionType.ADDED, ActionType.ADDED, cntEntity, cntEntity, cntEntity * 2, 0); testNotifyEntityBroadcastEntityStateChangeEventMany(new EntityView(), new EntityView(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.ASSIGNED_TO_CUSTOMER, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, - cntEntity * 2, 3); + ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED, cntEntity, cntEntity, + cntEntity*2, 3); } @Test @@ -465,7 +465,7 @@ public class EntityViewControllerTest extends AbstractControllerTest { testBroadcastEntityStateChangeEventNever(loadedNamesOfView1.get(0).getId()); testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new EntityView(), new EntityView(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, - ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UNASSIGNED_FROM_CUSTOMER, cntEntity, cntEntity, 3); + ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED, cntEntity, cntEntity, 3); PageData pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_TYPE_REF, new PageLink(4, 0, name1)); diff --git a/application/src/test/java/org/thingsboard/server/controller/OtaPackageControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/OtaPackageControllerTest.java index f4472e83be..3ebbb9ebbc 100644 --- a/application/src/test/java/org/thingsboard/server/controller/OtaPackageControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/OtaPackageControllerTest.java @@ -339,7 +339,7 @@ public class OtaPackageControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new OtaPackageInfo(), new OtaPackageInfo(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, ActionType.ADDED, cntEntity, 0, (cntEntity*2 - startIndexSaveData)); + ActionType.ADDED, cntEntity, 0, (cntEntity*2 - startIndexSaveData)); List loadedFirmwares = new ArrayList<>(); PageLink pageLink = new PageLink(24); diff --git a/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java index 59a305fe5a..cafeabcf16 100644 --- a/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java @@ -21,7 +21,6 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import org.junit.jupiter.api.Assertions; import org.mockito.AdditionalAnswers; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; @@ -31,7 +30,6 @@ import org.springframework.test.context.ContextConfiguration; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.action.TbCreateAlarmNode; import org.thingsboard.rule.engine.action.TbCreateAlarmNodeConfiguration; -import org.thingsboard.rule.engine.api.TbVersionedNode; import org.thingsboard.rule.engine.metadata.TbGetRelatedAttributeNode; import org.thingsboard.rule.engine.metadata.TbGetRelatedDataNodeConfiguration; import org.thingsboard.server.common.data.StringUtils; @@ -52,7 +50,6 @@ import org.thingsboard.server.dao.rule.RuleChainDao; import org.thingsboard.server.dao.service.DaoSqlTest; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -63,7 +60,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @DaoSqlTest public class RuleChainControllerTest extends AbstractControllerTest { - private IdComparator idComparator = new IdComparator<>(); + private final IdComparator idComparator = new IdComparator<>(); private Tenant savedTenant; private User tenantAdmin; @@ -245,7 +242,7 @@ public class RuleChainControllerTest extends AbstractControllerTest { doDelete("/api/ruleChain/" + savedRuleChain.getId().getId().toString()) .andExpect(status().isOk()); - testNotifyEntityBroadcastEntityStateChangeEventOneTimeMsgToEdgeServiceNever(savedRuleChain, savedRuleChain.getId(), savedRuleChain.getId(), + testNotifyEntityBroadcastEntityStateChangeEventOneTime(savedRuleChain, savedRuleChain.getId(), savedRuleChain.getId(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED, savedRuleChain.getId().getId().toString()); @@ -260,14 +257,13 @@ public class RuleChainControllerTest extends AbstractControllerTest { Edge savedEdge = doPost("/api/edge", edge, Edge.class); - List edgeRuleChains = new ArrayList<>(); PageLink pageLink = new PageLink(17); PageData pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId() + "/ruleChains?", new TypeReference<>() { }, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(1, pageData.getTotalElements()); - edgeRuleChains.addAll(pageData.getData()); + List edgeRuleChains = new ArrayList<>(pageData.getData()); Mockito.reset(tbClusterService, auditLogService); @@ -284,11 +280,7 @@ public class RuleChainControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new RuleChain(), new RuleChain(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ADDED, ActionType.ADDED, cntEntity, 0, cntEntity * 2); - testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new RuleChain(), new RuleChain(), - savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), - ActionType.ASSIGNED_TO_EDGE, ActionType.ASSIGNED_TO_EDGE, cntEntity, cntEntity, cntEntity * 2, - new String(), new String(), new String()); + ActionType.ADDED, cntEntity, cntEntity, cntEntity * 2); Mockito.reset(tbClusterService, auditLogService); List loadedEdgeRuleChains = new ArrayList<>(); @@ -303,8 +295,8 @@ public class RuleChainControllerTest extends AbstractControllerTest { } } while (pageData.hasNext()); - Collections.sort(edgeRuleChains, idComparator); - Collections.sort(loadedEdgeRuleChains, idComparator); + edgeRuleChains.sort(idComparator); + loadedEdgeRuleChains.sort(idComparator); Assert.assertEquals(edgeRuleChains, loadedEdgeRuleChains); diff --git a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java index 67564ec898..28bb987257 100644 --- a/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java @@ -113,7 +113,7 @@ public class UserControllerTest extends AbstractControllerTest { testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(foundUser, foundUser, SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL, - ActionType.ADDED, ActionType.ADDED, 1, 1, 1); + ActionType.ADDED, 1, 1, 1); Mockito.reset(tbClusterService, auditLogService); resetTokens(); @@ -152,7 +152,7 @@ public class UserControllerTest extends AbstractControllerTest { testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(foundUser, foundUser.getId(), foundUser.getId(), SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL, - ActionType.DELETED, SYSTEM_TENANT.getId().toString()); + ActionType.DELETED, ActionType.DELETED, SYSTEM_TENANT.getId().toString()); } @Test @@ -397,7 +397,7 @@ public class UserControllerTest extends AbstractControllerTest { testManyUser.setTenantId(tenantId); testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(testManyUser, testManyUser, SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL, - ActionType.ADDED, ActionType.ADDED, cntEntity, cntEntity, cntEntity); + ActionType.ADDED, cntEntity, cntEntity, cntEntity); List loadedTenantAdmins = new ArrayList<>(); PageLink pageLink = new PageLink(33); @@ -510,7 +510,7 @@ public class UserControllerTest extends AbstractControllerTest { testManyUser.setTenantId(tenantId); testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(testManyUser, testManyUser, SYSTEM_TENANT, customerNUULId, null, SYS_ADMIN_EMAIL, - ActionType.DELETED, ActionType.DELETED, cntEntity, NUMBER_OF_USERS, cntEntity, new String()); + ActionType.DELETED, cntEntity, NUMBER_OF_USERS, cntEntity, ""); pageLink = new PageLink(4, 0, email1); pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", diff --git a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java index 82b2ce3ec2..32f5aa109b 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java @@ -36,7 +36,6 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.asset.Asset; @@ -70,7 +69,6 @@ import org.thingsboard.server.common.data.query.NumericFilterPredicate; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainType; -import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.controller.AbstractControllerTest; import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.edge.imitator.EdgeImitator; @@ -85,6 +83,7 @@ import org.thingsboard.server.gen.edge.v1.QueueUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg; +import org.thingsboard.server.gen.edge.v1.SyncCompletedMsg; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UplinkMsg; import org.thingsboard.server.gen.edge.v1.UserUpdateMsg; @@ -100,16 +99,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @TestPropertySource(properties = { "edges.enabled=true", - "queue.rule-engine.stats.enabled=false", + "queue.rule-engine.stats.enabled=false" }) abstract public class AbstractEdgeTest extends AbstractControllerTest { private static final String THERMOSTAT_DEVICE_PROFILE_NAME = "Thermostat"; - protected Tenant savedTenant; - protected TenantId tenantId; - protected User tenantAdmin; - protected DeviceProfile thermostatDeviceProfile; protected EdgeImitator edgeImitator; @@ -125,27 +120,8 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { protected TbClusterService clusterService; @Before - public void beforeTest() throws Exception { - loginSysAdmin(); - - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - savedTenant = doPost("/api/tenant", tenant, Tenant.class); - tenantId = savedTenant.getId(); - Assert.assertNotNull(savedTenant); - - tenantAdmin = new User(); - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); - tenantAdmin.setTenantId(savedTenant.getId()); - tenantAdmin.setEmail("tenant2@thingsboard.org"); - tenantAdmin.setFirstName("Joe"); - tenantAdmin.setLastName("Downs"); - - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); - // sleep 0.5 second to avoid CREDENTIALS updated message for the user - // user credentials is going to be stored and updated event pushed to edge notification service - // while service will be processing this event edge could be already added and additional message will be pushed - Thread.sleep(500); + public void setupEdgeTest() throws Exception { + loginTenantAdmin(); installation(); @@ -181,31 +157,32 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { } @After - public void afterTest() throws Exception { + public void teardownEdgeTest() { try { - edgeImitator.disconnect(); - } catch (Exception ignored){} - - loginSysAdmin(); + edgeImitator.expectMessageAmount(2); + loginTenantAdmin(); + Assert.assertTrue(edgeImitator.waitForMessages()); - doDelete("/api/tenant/" + savedTenant.getUuidId()) - .andExpect(status().isOk()); + doDelete("/api/edge/" + edge.getId().toString()) + .andExpect(status().isOk()); + edgeImitator.disconnect(); + } catch (Exception ignored) {} } private void installation() { - edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class); - thermostatDeviceProfile = this.createDeviceProfile(THERMOSTAT_DEVICE_PROFILE_NAME, createMqttDeviceProfileTransportConfiguration(new JsonTransportPayloadConfiguration(), false)); - extendDeviceProfileData(thermostatDeviceProfile); thermostatDeviceProfile = doPost("/api/deviceProfile", thermostatDeviceProfile, DeviceProfile.class); Device savedDevice = saveDevice("Edge Device 1", THERMOSTAT_DEVICE_PROFILE_NAME); - doPost("/api/edge/" + edge.getUuidId() - + "/device/" + savedDevice.getUuidId(), Device.class); Asset savedAsset = saveAsset("Edge Asset 1"); + + edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class); + + doPost("/api/edge/" + edge.getUuidId() + + "/device/" + savedDevice.getUuidId(), Device.class); doPost("/api/edge/" + edge.getUuidId() + "/asset/" + savedAsset.getUuidId(), Asset.class); } @@ -244,18 +221,8 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { validateEdgeConfiguration(); - // 5 messages - // - 2 from device profile fetcher (default and thermostat) - // - 1 from device fetcher - // - 1 from device profile controller (thermostat) - // - 1 from device controller (thermostat) - validateDeviceProfiles(); - - // 2 messages - 1 from device fetcher and 1 from device controller - validateDevices(); - - // 2 messages - 1 from asset fetcher and 1 from asset controller - validateAssets(); + // 1 message from queue fetcher + validateQueues(); // 2 messages - 1 from rule chain fetcher and 1 from rule chain controller UUID ruleChainUUID = validateRuleChains(); @@ -266,20 +233,32 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { // 4 messages - 4 messages from fetcher - 2 from system level ('mail', 'mailTemplates') and 2 from admin level ('mail', 'mailTemplates') validateAdminSettings(); + // 4 messages + // - 2 from device profile fetcher (default and thermostat) + // - 1 from device fetcher + // - 1 from device controller (thermostat) + validateDeviceProfiles(); + // 3 messages // - 1 message from asset profile fetcher // - 1 message from asset fetcher // - 1 message from asset controller validateAssetProfiles(); - // 1 message from queue fetcher - validateQueues(); + // 2 messages - 1 from device fetcher and 1 from device controller + validateDevices(); - // 1 message from user fetcher - validateUsers(); + // 2 messages - 1 from asset fetcher and 1 from asset controller + validateAssets(); // 1 message from public customer fetcher validatePublicCustomer(); + + // 1 message from user fetcher + validateUsers(); + + // 1 message sync completed + validateSyncCompleted(); } private void validateEdgeConfiguration() throws Exception { @@ -290,12 +269,11 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { private void validateDeviceProfiles() throws Exception { List deviceProfileUpdateMsgList = edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class); - // default msg - // thermostat msg from fetcher + // default msg device profile from fetcher + // thermostat msg from device profile fetcher // thermostat msg from device fetcher - // thermostat msg from controller // thermostat msg from creation of device - Assert.assertEquals(5, deviceProfileUpdateMsgList.size()); + Assert.assertEquals(4, deviceProfileUpdateMsgList.size()); Optional thermostatProfileUpdateMsgOpt = deviceProfileUpdateMsgList.stream().filter(dfum -> THERMOSTAT_DEVICE_PROFILE_NAME.equals(dfum.getName())).findAny(); Assert.assertTrue(thermostatProfileUpdateMsgOpt.isPresent()); @@ -394,7 +372,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { } } - private void validateMailAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) throws JsonProcessingException { + private void validateMailAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) { JsonNode jsonNode = JacksonUtil.toJsonNode(adminSettingsUpdateMsg.getJsonValue()); Assert.assertNotNull(jsonNode.get("mailFrom")); Assert.assertNotNull(jsonNode.get("smtpProtocol")); @@ -403,7 +381,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { Assert.assertNotNull(jsonNode.get("timeout")); } - private void validateMailTemplatesAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) throws JsonProcessingException { + private void validateMailTemplatesAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) { JsonNode jsonNode = JacksonUtil.toJsonNode(adminSettingsUpdateMsg.getJsonValue()); Assert.assertNotNull(jsonNode.get("accountActivated")); Assert.assertNotNull(jsonNode.get("accountLockout")); @@ -449,7 +427,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { UUID userUUID = new UUID(userUpdateMsg.getIdMSB(), userUpdateMsg.getIdLSB()); User user = doGet("/api/user/" + userUUID, User.class); Assert.assertNotNull(user); - Assert.assertEquals("tenant2@thingsboard.org", userUpdateMsg.getEmail()); + Assert.assertEquals("testtenant@thingsboard.org", userUpdateMsg.getEmail()); testAutoGeneratedCodeByProtobuf(userUpdateMsg); } @@ -464,6 +442,11 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { Assert.assertTrue(customer.isPublic()); } + private void validateSyncCompleted() { + Optional syncCompletedMsgOpt = edgeImitator.findMessageByType(SyncCompletedMsg.class); + Assert.assertTrue(syncCompletedMsgOpt.isPresent()); + } + protected Device saveDeviceOnCloudAndVerifyDeliveryToEdge() throws Exception { // create device and assign to edge Device savedDevice = saveDevice(StringUtils.randomAlphanumeric(15), thermostatDeviceProfile.getName()); diff --git a/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java index 2f5848ece6..e8639e0db7 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java @@ -82,11 +82,11 @@ public class AssetEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedAsset.getUuidId().getMostSignificantBits(), assetUpdateMsg.getIdMSB()); Assert.assertEquals(savedAsset.getUuidId().getLeastSignificantBits(), assetUpdateMsg.getIdLSB()); - // delete asset - no messages expected + // delete asset - message expected, it was sent to all edges edgeImitator.expectMessageAmount(1); doDelete("/api/asset/" + savedAsset.getUuidId()) .andExpect(status().isOk()); - Assert.assertFalse(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(1)); // create asset #2 and assign to edge edgeImitator.expectMessageAmount(2); @@ -94,7 +94,6 @@ public class AssetEdgeTest extends AbstractEdgeTest { doPost("/api/edge/" + edge.getUuidId() + "/asset/" + savedAsset.getUuidId(), Asset.class); Assert.assertTrue(edgeImitator.waitForMessages()); - latestMessage = edgeImitator.getLatestMessage(); assetUpdateMsgOpt = edgeImitator.findMessageByType(AssetUpdateMsg.class); Assert.assertTrue(assetUpdateMsgOpt.isPresent()); assetUpdateMsg = assetUpdateMsgOpt.get(); diff --git a/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java index b9bf41fde6..251b4b4caf 100644 --- a/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java @@ -20,12 +20,15 @@ import org.junit.Assert; import org.junit.Test; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg; import org.thingsboard.server.gen.edge.v1.EdgeConfiguration; import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import java.util.Optional; +import java.util.UUID; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -74,13 +77,19 @@ public class CustomerEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedCustomer.getTitle(), customerUpdateMsg.getTitle()); // delete customer - edgeImitator.expectMessageAmount(1); + edgeImitator.expectMessageAmount(2); doDelete("/api/customer/" + savedCustomer.getUuidId()) .andExpect(status().isOk()); Assert.assertTrue(edgeImitator.waitForMessages()); - latestMessage = edgeImitator.getLatestMessage(); - Assert.assertTrue(latestMessage instanceof CustomerUpdateMsg); - customerUpdateMsg = (CustomerUpdateMsg) latestMessage; + edgeConfigurationOpt = edgeImitator.findMessageByType(EdgeConfiguration.class); + Assert.assertTrue(edgeConfigurationOpt.isPresent()); + edgeConfiguration = edgeConfigurationOpt.get(); + Assert.assertEquals( + new CustomerId(EntityId.NULL_UUID), + new CustomerId(new UUID(edgeConfiguration.getCustomerIdMSB(), edgeConfiguration.getCustomerIdLSB()))); + customerUpdateOpt = edgeImitator.findMessageByType(CustomerUpdateMsg.class); + Assert.assertTrue(customerUpdateOpt.isPresent()); + customerUpdateMsg = customerUpdateOpt.get(); Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, customerUpdateMsg.getMsgType()); Assert.assertEquals(customerUpdateMsg.getIdMSB(), savedCustomer.getUuidId().getMostSignificantBits()); Assert.assertEquals(customerUpdateMsg.getIdLSB(), savedCustomer.getUuidId().getLeastSignificantBits()); diff --git a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java index 988d6fdc98..94743c4a6b 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java @@ -77,11 +77,11 @@ public class DashboardEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedDashboard.getUuidId().getMostSignificantBits(), dashboardUpdateMsg.getIdMSB()); Assert.assertEquals(savedDashboard.getUuidId().getLeastSignificantBits(), dashboardUpdateMsg.getIdLSB()); - // delete dashboard - no messages expected + // delete dashboard - message expected, it was sent to all edges edgeImitator.expectMessageAmount(1); doDelete("/api/dashboard/" + savedDashboard.getUuidId()) .andExpect(status().isOk()); - Assert.assertFalse(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(1)); // create dashboard #2 and assign to edge edgeImitator.expectMessageAmount(1); diff --git a/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java index 15d5b5c809..1c9a6359d6 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java @@ -83,6 +83,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @DaoSqlTest public class DeviceEdgeTest extends AbstractEdgeTest { + private static final String DEFAULT_DEVICE_TYPE = "default"; + @Test public void testDevices() throws Exception { // create device and assign to edge; update device @@ -100,15 +102,15 @@ public class DeviceEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedDevice.getUuidId().getMostSignificantBits(), deviceUpdateMsg.getIdMSB()); Assert.assertEquals(savedDevice.getUuidId().getLeastSignificantBits(), deviceUpdateMsg.getIdLSB()); - // delete device - no messages expected + // delete device - message expected, message send to all edges edgeImitator.expectMessageAmount(1); doDelete("/api/device/" + savedDevice.getUuidId()) .andExpect(status().isOk()); - Assert.assertFalse(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(1)); // create device #2 and assign to edge edgeImitator.expectMessageAmount(2); - savedDevice = saveDevice("Edge Device 3", "Default"); + savedDevice = saveDevice("Edge Device 3", DEFAULT_DEVICE_TYPE); doPost("/api/edge/" + edge.getUuidId() + "/device/" + savedDevice.getUuidId(), Device.class); Assert.assertTrue(edgeImitator.waitForMessages()); @@ -265,14 +267,16 @@ public class DeviceEdgeTest extends AbstractEdgeTest { public void testDeviceReachedMaximumAllowedOnCloud() throws Exception { // update tenant profile configuration loginSysAdmin(); - TenantProfile tenantProfile = doGet("/api/tenantProfile/" + savedTenant.getTenantProfileId().getId(), TenantProfile.class); + TenantProfile tenantProfile = doGet("/api/tenantProfile/" + tenantProfileId.getId(), TenantProfile.class); DefaultTenantProfileConfiguration profileConfiguration = (DefaultTenantProfileConfiguration) tenantProfile.getProfileData().getConfiguration(); profileConfiguration.setMaxDevices(1); tenantProfile.getProfileData().setConfiguration(profileConfiguration); doPost("/api/tenantProfile/", tenantProfile, TenantProfile.class); + edgeImitator.expectMessageAmount(2); loginTenantAdmin(); + Assert.assertTrue(edgeImitator.waitForMessages()); UUID uuid = Uuids.timeBased(); @@ -281,7 +285,7 @@ public class DeviceEdgeTest extends AbstractEdgeTest { deviceUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits()); deviceUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits()); deviceUpdateMsgBuilder.setName("Edge Device"); - deviceUpdateMsgBuilder.setType("default"); + deviceUpdateMsgBuilder.setType(DEFAULT_DEVICE_TYPE); deviceUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE); uplinkMsgBuilder.addDeviceUpdateMsg(deviceUpdateMsgBuilder.build()); @@ -479,7 +483,7 @@ public class DeviceEdgeTest extends AbstractEdgeTest { @Test public void testSendDeviceToCloudWithNameThatAlreadyExistsOnCloud() throws Exception { String deviceOnCloudName = StringUtils.randomAlphanumeric(15); - Device deviceOnCloud = saveDevice(deviceOnCloudName, "Default"); + Device deviceOnCloud = saveDevice(deviceOnCloudName, DEFAULT_DEVICE_TYPE); UUID uuid = Uuids.timeBased(); diff --git a/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java index 234a9473fa..75386dbb17 100644 --- a/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java @@ -94,11 +94,11 @@ public class EntityViewEdgeTest extends AbstractEdgeTest { Assert.assertEquals(entityViewUpdateMsg.getIdMSB(), savedEntityView.getUuidId().getMostSignificantBits()); Assert.assertEquals(entityViewUpdateMsg.getIdLSB(), savedEntityView.getUuidId().getLeastSignificantBits()); - // delete entity view - no messages expected + // delete entity view - message expected, it was sent to all edges edgeImitator.expectMessageAmount(1); doDelete("/api/entityView/" + savedEntityView.getUuidId()) .andExpect(status().isOk()); - Assert.assertFalse(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(1)); // create entity view #2 and assign to edge edgeImitator.expectMessageAmount(1); diff --git a/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java index b810810225..83b2370cf0 100644 --- a/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java @@ -19,6 +19,9 @@ import com.google.protobuf.AbstractMessage; import org.junit.Assert; import org.junit.Test; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.metadata.TbGetAttributesNode; +import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; +import org.thingsboard.rule.engine.util.TbMsgSource; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.rule.RuleChain; @@ -33,6 +36,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UplinkMsg; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -81,7 +85,7 @@ public class RuleChainEdgeTest extends AbstractEdgeTest { edgeImitator.expectMessageAmount(1); doDelete("/api/ruleChain/" + savedRuleChain.getUuidId()) .andExpect(status().isOk()); - Assert.assertFalse(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(5)); } @Test @@ -136,24 +140,30 @@ public class RuleChainEdgeTest extends AbstractEdgeTest { Assert.assertEquals(ruleChainId, receivedRuleChainId); } - private void createRuleChainMetadata(RuleChain ruleChain) throws Exception { + private void createRuleChainMetadata(RuleChain ruleChain) { RuleChainMetaData ruleChainMetaData = new RuleChainMetaData(); ruleChainMetaData.setRuleChainId(ruleChain.getId()); RuleNode ruleNode1 = new RuleNode(); ruleNode1.setName("name1"); - ruleNode1.setType("type1"); - ruleNode1.setConfiguration(JacksonUtil.toJsonNode("\"key1\": \"val1\"")); + ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode1.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); + TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration(); + configuration.setFetchTo(TbMsgSource.METADATA); + configuration.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); + ruleNode1.setConfiguration(JacksonUtil.valueToTree(configuration)); RuleNode ruleNode2 = new RuleNode(); ruleNode2.setName("name2"); - ruleNode2.setType("type2"); - ruleNode2.setConfiguration(JacksonUtil.toJsonNode("\"key2\": \"val2\"")); + ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode2.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); + ruleNode2.setConfiguration(JacksonUtil.valueToTree(configuration)); RuleNode ruleNode3 = new RuleNode(); ruleNode3.setName("name3"); - ruleNode3.setType("type3"); - ruleNode3.setConfiguration(JacksonUtil.toJsonNode("\"key3\": \"val3\"")); + ruleNode3.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode3.setConfigurationVersion(TbGetAttributesNode.class.getAnnotation(org.thingsboard.rule.engine.api.RuleNode.class).version()); + ruleNode3.setConfiguration(JacksonUtil.valueToTree(configuration)); List ruleNodes = new ArrayList<>(); ruleNodes.add(ruleNode1); @@ -172,11 +182,12 @@ public class RuleChainEdgeTest extends AbstractEdgeTest { @Test public void testSetRootRuleChain() throws Exception { // create rule chain - edgeImitator.expectMessageAmount(1); RuleChain ruleChain = new RuleChain(); ruleChain.setName("Edge New Root Rule Chain"); ruleChain.setType(RuleChainType.EDGE); RuleChain savedRuleChain = doPost("/api/ruleChain", ruleChain, RuleChain.class); + + edgeImitator.expectMessageAmount(1); doPost("/api/edge/" + edge.getUuidId() + "/ruleChain/" + savedRuleChain.getUuidId(), RuleChain.class); Assert.assertTrue(edgeImitator.waitForMessages()); @@ -211,6 +222,6 @@ public class RuleChainEdgeTest extends AbstractEdgeTest { edgeImitator.expectMessageAmount(1); doDelete("/api/ruleChain/" + savedRuleChain.getUuidId()) .andExpect(status().isOk()); - Assert.assertFalse(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(1)); } } diff --git a/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java index 0cf1c2d149..2ee267b88c 100644 --- a/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java @@ -215,7 +215,7 @@ public class TelemetryEdgeTest extends AbstractEdgeTest { @Test public void testAttributesUpdatedMsg_userEntity() throws Exception { - testAttributesUpdatedMsg(tenantAdmin.getId()); + testAttributesUpdatedMsg(tenantAdminUserId); } private void testAttributesUpdatedMsg(EntityId entityId) throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java index f376f50ac5..d1d555f691 100644 --- a/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java @@ -45,18 +45,18 @@ public class UserEdgeTest extends AbstractEdgeTest { @Test public void testCreateUpdateDeleteTenantUser() throws Exception { // create user - edgeImitator.expectMessageAmount(2); + edgeImitator.expectMessageAmount(3); User newTenantAdmin = new User(); newTenantAdmin.setAuthority(Authority.TENANT_ADMIN); - newTenantAdmin.setTenantId(savedTenant.getId()); + newTenantAdmin.setTenantId(tenantId); newTenantAdmin.setEmail("tenantAdmin@thingsboard.org"); newTenantAdmin.setFirstName("Boris"); newTenantAdmin.setLastName("Johnson"); User savedTenantAdmin = createUser(newTenantAdmin, "tenant"); - Assert.assertTrue(edgeImitator.waitForMessages()); // wait 2 messages - user update msg and user credentials update msg - Optional latestMessageOpt = edgeImitator.findMessageByType(UserUpdateMsg.class); - Assert.assertTrue(latestMessageOpt.isPresent()); - UserUpdateMsg userUpdateMsg = latestMessageOpt.get(); + Assert.assertTrue(edgeImitator.waitForMessages()); // wait 3 messages - user update msg and x2 user credentials update msgs + Optional userUpdateMsgOpt = edgeImitator.findMessageByType(UserUpdateMsg.class); + Assert.assertTrue(userUpdateMsgOpt.isPresent()); + UserUpdateMsg userUpdateMsg = userUpdateMsgOpt.get(); Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, userUpdateMsg.getMsgType()); Assert.assertEquals(savedTenantAdmin.getUuidId().getMostSignificantBits(), userUpdateMsg.getIdMSB()); Assert.assertEquals(savedTenantAdmin.getUuidId().getLeastSignificantBits(), userUpdateMsg.getIdLSB()); @@ -79,8 +79,11 @@ public class UserEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedTenantAdmin.getLastName(), userUpdateMsg.getLastName()); // update user credentials - edgeImitator.expectMessageAmount(1); + edgeImitator.expectMessageAmount(2); login(savedTenantAdmin.getEmail(), "tenant"); + Assert.assertTrue(edgeImitator.waitForMessages()); + + edgeImitator.expectMessageAmount(1); ChangePasswordRequest changePasswordRequest = new ChangePasswordRequest(); changePasswordRequest.setCurrentPassword("tenant"); changePasswordRequest.setNewPassword("newTenant"); @@ -93,9 +96,12 @@ public class UserEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedTenantAdmin.getUuidId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB()); Assert.assertTrue(passwordEncoder.matches(changePasswordRequest.getNewPassword(), userCredentialsUpdateMsg.getPassword())); + edgeImitator.expectMessageAmount(2); + loginTenantAdmin(); + Assert.assertTrue(edgeImitator.waitForMessages()); + // delete user edgeImitator.expectMessageAmount(1); - login(tenantAdmin.getEmail(), "testPassword1"); doDelete("/api/user/" + savedTenantAdmin.getUuidId()) .andExpect(status().isOk()); Assert.assertTrue(edgeImitator.waitForMessages()); @@ -123,19 +129,19 @@ public class UserEdgeTest extends AbstractEdgeTest { Assert.assertTrue(edgeImitator.waitForMessages()); // create user - edgeImitator.expectMessageAmount(2); + edgeImitator.expectMessageAmount(3); User customerUser = new User(); customerUser.setAuthority(Authority.CUSTOMER_USER); - customerUser.setTenantId(savedTenant.getId()); + customerUser.setTenantId(tenantId); customerUser.setCustomerId(savedCustomer.getId()); customerUser.setEmail("customerUser@thingsboard.org"); customerUser.setFirstName("John"); customerUser.setLastName("Edwards"); User savedCustomerUser = createUser(customerUser, "customer"); - Assert.assertTrue(edgeImitator.waitForMessages()); // wait 2 messages - user update msg and user credentials update msg - Optional latestMessageOpt = edgeImitator.findMessageByType(UserUpdateMsg.class); - Assert.assertTrue(latestMessageOpt.isPresent()); - UserUpdateMsg userUpdateMsg = latestMessageOpt.get(); + Assert.assertTrue(edgeImitator.waitForMessages()); // wait 3 messages - user update msg and x2 user credentials update msgs + Optional userUpdateMsgOpt = edgeImitator.findMessageByType(UserUpdateMsg.class); + Assert.assertTrue(userUpdateMsgOpt.isPresent()); + UserUpdateMsg userUpdateMsg = userUpdateMsgOpt.get(); Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, userUpdateMsg.getMsgType()); Assert.assertEquals(savedCustomerUser.getUuidId().getMostSignificantBits(), userUpdateMsg.getIdMSB()); Assert.assertEquals(savedCustomerUser.getUuidId().getLeastSignificantBits(), userUpdateMsg.getIdLSB()); @@ -158,8 +164,11 @@ public class UserEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedCustomerUser.getLastName(), userUpdateMsg.getLastName()); // update user credentials - edgeImitator.expectMessageAmount(1); + edgeImitator.expectMessageAmount(2); login(savedCustomerUser.getEmail(), "customer"); + Assert.assertTrue(edgeImitator.waitForMessages()); + + edgeImitator.expectMessageAmount(1); ChangePasswordRequest changePasswordRequest = new ChangePasswordRequest(); changePasswordRequest.setCurrentPassword("customer"); changePasswordRequest.setNewPassword("newCustomer"); @@ -172,9 +181,12 @@ public class UserEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedCustomerUser.getUuidId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB()); Assert.assertTrue(passwordEncoder.matches(changePasswordRequest.getNewPassword(), userCredentialsUpdateMsg.getPassword())); + edgeImitator.expectMessageAmount(2); + loginTenantAdmin(); + Assert.assertTrue(edgeImitator.waitForMessages()); + // delete user edgeImitator.expectMessageAmount(1); - login(tenantAdmin.getEmail(), "testPassword1"); doDelete("/api/user/" + savedCustomerUser.getUuidId()) .andExpect(status().isOk()); Assert.assertTrue(edgeImitator.waitForMessages()); @@ -191,8 +203,8 @@ public class UserEdgeTest extends AbstractEdgeTest { public void testSendUserCredentialsRequestToCloud() throws Exception { UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder(); UserCredentialsRequestMsg.Builder userCredentialsRequestMsgBuilder = UserCredentialsRequestMsg.newBuilder(); - userCredentialsRequestMsgBuilder.setUserIdMSB(tenantAdmin.getId().getId().getMostSignificantBits()); - userCredentialsRequestMsgBuilder.setUserIdLSB(tenantAdmin.getId().getId().getLeastSignificantBits()); + userCredentialsRequestMsgBuilder.setUserIdMSB(tenantAdminUserId.getId().getMostSignificantBits()); + userCredentialsRequestMsgBuilder.setUserIdLSB(tenantAdminUserId.getId().getLeastSignificantBits()); testAutoGeneratedCodeByProtobuf(userCredentialsRequestMsgBuilder); uplinkMsgBuilder.addUserCredentialsRequestMsg(userCredentialsRequestMsgBuilder.build()); @@ -207,16 +219,16 @@ public class UserEdgeTest extends AbstractEdgeTest { AbstractMessage latestMessage = edgeImitator.getLatestMessage(); Assert.assertTrue(latestMessage instanceof UserCredentialsUpdateMsg); UserCredentialsUpdateMsg userCredentialsUpdateMsg = (UserCredentialsUpdateMsg) latestMessage; - Assert.assertEquals(tenantAdmin.getId().getId().getMostSignificantBits(), userCredentialsUpdateMsg.getUserIdMSB()); - Assert.assertEquals(tenantAdmin.getId().getId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB()); + Assert.assertEquals(tenantAdminUserId.getId().getMostSignificantBits(), userCredentialsUpdateMsg.getUserIdMSB()); + Assert.assertEquals(tenantAdminUserId.getId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB()); } @Test public void sendUserCredentialsRequest() throws Exception { UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder(); UserCredentialsRequestMsg.Builder userCredentialsRequestMsgBuilder = UserCredentialsRequestMsg.newBuilder(); - userCredentialsRequestMsgBuilder.setUserIdMSB(tenantAdmin.getId().getId().getMostSignificantBits()); - userCredentialsRequestMsgBuilder.setUserIdLSB(tenantAdmin.getId().getId().getLeastSignificantBits()); + userCredentialsRequestMsgBuilder.setUserIdMSB(tenantAdminUserId.getId().getMostSignificantBits()); + userCredentialsRequestMsgBuilder.setUserIdLSB(tenantAdminUserId.getId().getLeastSignificantBits()); testAutoGeneratedCodeByProtobuf(userCredentialsRequestMsgBuilder); uplinkMsgBuilder.addUserCredentialsRequestMsg(userCredentialsRequestMsgBuilder.build()); @@ -231,8 +243,8 @@ public class UserEdgeTest extends AbstractEdgeTest { AbstractMessage latestMessage = edgeImitator.getLatestMessage(); Assert.assertTrue(latestMessage instanceof UserCredentialsUpdateMsg); UserCredentialsUpdateMsg userCredentialsUpdateMsg = (UserCredentialsUpdateMsg) latestMessage; - Assert.assertEquals(userCredentialsUpdateMsg.getUserIdMSB(), tenantAdmin.getId().getId().getMostSignificantBits()); - Assert.assertEquals(userCredentialsUpdateMsg.getUserIdLSB(), tenantAdmin.getId().getId().getLeastSignificantBits()); + Assert.assertEquals(userCredentialsUpdateMsg.getUserIdMSB(), tenantAdminUserId.getId().getMostSignificantBits()); + Assert.assertEquals(userCredentialsUpdateMsg.getUserIdLSB(), tenantAdminUserId.getId().getLeastSignificantBits()); testAutoGeneratedCodeByProtobuf(userCredentialsUpdateMsg); } diff --git a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java index 0edf070aef..67db3e6b27 100644 --- a/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java +++ b/application/src/test/java/org/thingsboard/server/edge/imitator/EdgeImitator.java @@ -177,16 +177,16 @@ public class EdgeImitator { result.add(saveDownlinkMsg(adminSettingsUpdateMsg)); } } - if (downlinkMsg.getDeviceUpdateMsgCount() > 0) { - for (DeviceUpdateMsg deviceUpdateMsg : downlinkMsg.getDeviceUpdateMsgList()) { - result.add(saveDownlinkMsg(deviceUpdateMsg)); - } - } if (downlinkMsg.getDeviceProfileUpdateMsgCount() > 0) { for (DeviceProfileUpdateMsg deviceProfileUpdateMsg : downlinkMsg.getDeviceProfileUpdateMsgList()) { result.add(saveDownlinkMsg(deviceProfileUpdateMsg)); } } + if (downlinkMsg.getDeviceUpdateMsgCount() > 0) { + for (DeviceUpdateMsg deviceUpdateMsg : downlinkMsg.getDeviceUpdateMsgList()) { + result.add(saveDownlinkMsg(deviceUpdateMsg)); + } + } if (downlinkMsg.getDeviceCredentialsUpdateMsgCount() > 0) { for (DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg : downlinkMsg.getDeviceCredentialsUpdateMsgList()) { result.add(saveDownlinkMsg(deviceCredentialsUpdateMsg)); @@ -293,6 +293,9 @@ public class EdgeImitator { if (downlinkMsg.hasEdgeConfiguration()) { result.add(saveDownlinkMsg(downlinkMsg.getEdgeConfiguration())); } + if (downlinkMsg.hasSyncCompletedMsg()) { + result.add(saveDownlinkMsg(downlinkMsg.getSyncCompletedMsg())); + } return Futures.allAsList(result); } diff --git a/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java index f01f4fae04..a88f25d5bf 100644 --- a/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java @@ -71,8 +71,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -; - @Slf4j @RunWith(SpringRunner.class) @ContextConfiguration(classes = DeviceProvisionServiceImpl.class) diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java index 487783b454..229ea5d9f9 100644 --- a/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmServiceTest.java @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.dao.alarm.AlarmService; @@ -42,7 +43,7 @@ import java.util.UUID; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -87,7 +88,7 @@ public class DefaultTbAlarmServiceTest { .build()); service.save(alarm, new User()); - verify(notificationEntityService, times(1)).notifyCreateOrUpdateAlarm(any(), any(), any()); + verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.ADDED), any()); verify(alarmSubscriptionService, times(1)).createAlarm(any()); } @@ -95,11 +96,11 @@ public class DefaultTbAlarmServiceTest { public void testAck() throws ThingsboardException { var alarm = new Alarm(); when(alarmSubscriptionService.acknowledgeAlarm(any(), any(), anyLong())) - .thenReturn(AlarmApiCallResult.builder().successful(true).modified(true).build()); + .thenReturn(AlarmApiCallResult.builder().successful(true).modified(true).alarm(new AlarmInfo()).build()); service.ack(alarm, new User(new UserId(UUID.randomUUID()))); verify(alarmCommentService, times(1)).saveAlarmComment(any(), any(), any()); - verify(notificationEntityService, times(1)).notifyCreateOrUpdateAlarm(any(), any(), any()); + verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.ALARM_ACK), any()); verify(alarmSubscriptionService, times(1)).acknowledgeAlarm(any(), any(), anyLong()); } @@ -108,11 +109,11 @@ public class DefaultTbAlarmServiceTest { var alarm = new Alarm(); alarm.setAcknowledged(true); when(alarmSubscriptionService.clearAlarm(any(), any(), anyLong(), any())) - .thenReturn(AlarmApiCallResult.builder().successful(true).cleared(true).build()); + .thenReturn(AlarmApiCallResult.builder().successful(true).cleared(true).alarm(new AlarmInfo()).build()); service.clear(alarm, new User(new UserId(UUID.randomUUID()))); verify(alarmCommentService, times(1)).saveAlarmComment(any(), any(), any()); - verify(notificationEntityService, times(1)).notifyCreateOrUpdateAlarm(any(), any(), any()); + verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.ALARM_CLEAR), any()); verify(alarmSubscriptionService, times(1)).clearAlarm(any(), any(), anyLong(), any()); } @@ -120,7 +121,7 @@ public class DefaultTbAlarmServiceTest { public void testDelete() { service.delete(new Alarm(), new User()); - verify(notificationEntityService, times(1)).notifyDeleteAlarm(any(), any(), any(), any(), any(), any(), anyString()); + verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.DELETED), any()); verify(alarmSubscriptionService, times(1)).deleteAlarm(any(), any()); } -} \ No newline at end of file +} diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java index 29d9a6ebb8..50055b8d1a 100644 --- a/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/entitiy/alarmComment/DefaultTbAlarmCommentServiceTest.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmComment; import org.thingsboard.server.common.data.alarm.AlarmCommentType; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.UserId; @@ -81,7 +82,7 @@ public class DefaultTbAlarmCommentServiceTest { when(alarmCommentService.createOrUpdateAlarmComment(Mockito.any(), eq(alarmComment))).thenReturn(alarmComment); service.saveAlarmComment(alarm, alarmComment, new User()); - verify(notificationEntityService, times(1)).notifyAlarmComment(any(), any(), any(), any()); + verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.ADDED_COMMENT), any(), any()); } @Test @@ -95,7 +96,7 @@ public class DefaultTbAlarmCommentServiceTest { when(alarmCommentService.saveAlarmComment(Mockito.any(), eq(alarmComment))).thenReturn(alarmComment); service.deleteAlarmComment(new Alarm(alarmId), alarmComment, new User()); - verify(notificationEntityService, times(1)).notifyAlarmComment(any(), any(), any(), any()); + verify(notificationEntityService, times(1)).logEntityAction(any(), any(), any(), any(), eq(ActionType.DELETED_COMMENT), any(), any()); } @Test diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java index 8962a35187..e81aaed39d 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java @@ -80,8 +80,6 @@ public interface TbClusterService extends TbQueueClusterService { void onDeviceUpdated(Device device, Device old); - void onDeviceUpdated(Device device, Device old, boolean notifyEdge); - void onDeviceDeleted(Device device, TbQueueCallback callback); void onResourceChange(TbResource resource, TbQueueCallback callback); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeSynchronizationManager.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeSynchronizationManager.java new file mode 100644 index 0000000000..8cce581098 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeSynchronizationManager.java @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.edge; + +public interface EdgeSynchronizationManager { + + ThreadLocal getSync(); + + boolean isSync(); +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java index e1f16be1ed..47a7423191 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java @@ -39,7 +39,7 @@ public interface UserService extends EntityDaoService { User findUserByTenantIdAndEmail(TenantId tenantId, String email); - User saveUser(User user); + User saveUser(TenantId tenantId, User user); UserCredentials findUserCredentialsByUserId(TenantId tenantId, UserId userId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java index 756c30690f..be54b70f18 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java @@ -15,24 +15,33 @@ */ package org.thingsboard.server.common.data.edge; +import lombok.Getter; + +@Getter public enum EdgeEventType { - DASHBOARD, - ASSET, - DEVICE, - DEVICE_PROFILE, - ASSET_PROFILE, - ENTITY_VIEW, - ALARM, - RULE_CHAIN, - RULE_CHAIN_METADATA, - EDGE, - USER, - CUSTOMER, - RELATION, - TENANT, - WIDGETS_BUNDLE, - WIDGET_TYPE, - ADMIN_SETTINGS, - OTA_PACKAGE, - QUEUE + DASHBOARD(false), + ASSET(false), + DEVICE(false), + DEVICE_PROFILE(true), + ASSET_PROFILE(true), + ENTITY_VIEW(false), + ALARM(false), + RULE_CHAIN(false), + RULE_CHAIN_METADATA(false), + EDGE(false), + USER(true), + CUSTOMER(true), + RELATION(true), + TENANT(true), + WIDGETS_BUNDLE(true), + WIDGET_TYPE(true), + ADMIN_SETTINGS(true), + OTA_PACKAGE(true), + QUEUE(true); + + private final boolean allEdgesRelated; + + EdgeEventType(boolean allEdgesRelated) { + this.allEdgesRelated = allEdgesRelated; + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 96342aca2f..85428e14a9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmStatusFilter; import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; import org.thingsboard.server.common.data.alarm.EntityAlarm; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ApiUsageLimitsExceededException; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; @@ -56,6 +57,9 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; +import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.ConstraintValidator; import org.thingsboard.server.dao.service.DataValidator; @@ -90,7 +94,12 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @Override public AlarmApiCallResult updateAlarm(AlarmUpdateRequest request) { validateAlarmRequest(request); - return withPropagated(alarmDao.updateAlarm(request)); + AlarmApiCallResult result = withPropagated(alarmDao.updateAlarm(request)); + if (result.getAlarm() != null) { + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(result.getAlarm().getTenantId()).entity(result) + .entityId(result.getAlarm().getId()).build()); + } + return result; } @Override @@ -112,17 +121,31 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (!result.isSuccessful() && !alarmCreationEnabled) { throw new ApiUsageLimitsExceededException("Alarms creation is disabled"); } + if (result.getAlarm() != null) { + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(result.getAlarm().getTenantId()) + .entityId(result.getAlarm().getId()).added(true).build()); + } return withPropagated(result); } @Override public AlarmApiCallResult acknowledgeAlarm(TenantId tenantId, AlarmId alarmId, long ackTs) { - return withPropagated(alarmDao.acknowledgeAlarm(tenantId, alarmId, ackTs)); + var result = withPropagated(alarmDao.acknowledgeAlarm(tenantId, alarmId, ackTs)); + if (result.getAlarm() != null) { + eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).entityId(result.getAlarm().getId()) + .actionType(ActionType.ALARM_ACK).build()); + } + return result; } @Override public AlarmApiCallResult clearAlarm(TenantId tenantId, AlarmId alarmId, long clearTs, JsonNode details) { - return withPropagated(alarmDao.clearAlarm(tenantId, alarmId, clearTs, details)); + var result = withPropagated(alarmDao.clearAlarm(tenantId, alarmId, clearTs, details)); + if (result.getAlarm() != null) { + eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).entityId(result.getAlarm().getId()) + .actionType(ActionType.ALARM_CLEAR).build()); + } + return result; } @Override @@ -188,6 +211,8 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ } else { deleteEntityRelations(tenantId, alarm.getId()); alarmDao.removeById(tenantId, alarm.getUuidId()); + eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId) + .entityId(alarmId).entity(alarm).build()); return AlarmApiCallResult.builder().alarm(alarm).deleted(true).successful(true).build(); } } @@ -300,12 +325,22 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @Override public AlarmApiCallResult assignAlarm(TenantId tenantId, AlarmId alarmId, UserId assigneeId, long assignTime) { - return withPropagated(alarmDao.assignAlarm(tenantId, alarmId, assigneeId, assignTime)); + var result = withPropagated(alarmDao.assignAlarm(tenantId, alarmId, assigneeId, assignTime)); + if (result.getAlarm() != null) { + eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).entityId(result.getAlarm().getId()) + .actionType(ActionType.ALARM_ASSIGNED).build()); + } + return result; } @Override public AlarmApiCallResult unassignAlarm(TenantId tenantId, AlarmId alarmId, long unassignTime) { - return withPropagated(alarmDao.unassignAlarm(tenantId, alarmId, unassignTime)); + var result = withPropagated(alarmDao.unassignAlarm(tenantId, alarmId, unassignTime)); + if (result.getAlarm() != null) { + eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).entityId(result.getAlarm().getId()) + .actionType(ActionType.ALARM_UNASSIGNED).build()); + } + return result; } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java index eb297e0049..b3bc89c34d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java @@ -33,6 +33,8 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -118,6 +120,8 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService sync = new ThreadLocal<>(); + + @Override + public boolean isSync() { + Boolean sync = this.sync.get(); + return sync != null && sync; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index 31b446fbd5..127741e8d0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeInfo; import org.thingsboard.server.common.data.edge.EdgeSearchQuery; @@ -53,6 +54,7 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; +import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -179,6 +181,8 @@ public class EdgeServiceImpl extends AbstractCachedEntityService cache; - @Autowired - private ApplicationEventPublisher eventPublisher; - protected void publishEvictEvent(E event) { if (TransactionSynchronizationManager.isActualTransactionActive()) { eventPublisher.publishEvent(event); diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java index 6d4ac9f97b..17cd7a15d4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.entity; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Lazy; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.StringUtils; @@ -43,6 +44,9 @@ public abstract class AbstractEntityService { public static final String INCORRECT_EDGE_ID = "Incorrect edgeId "; public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; + @Autowired + protected ApplicationEventPublisher eventPublisher; + @Lazy @Autowired protected RelationService relationService; @@ -113,7 +117,7 @@ public abstract class AbstractEntityService { List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityId(tenantId, entityId); if (entityViews != null && !entityViews.isEmpty()) { EntityView entityView = entityViews.get(0); - Boolean relationExists = relationService.checkRelation( + boolean relationExists = relationService.checkRelation( tenantId, edgeId, entityView.getId(), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE ); @@ -122,5 +126,4 @@ public abstract class AbstractEntityService { } } } - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 6433db5ae8..2e5ee9071b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityViewInfo; import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; @@ -43,6 +44,9 @@ import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; +import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -104,6 +108,8 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService { + private final TenantId tenantId; + private final EntityId entityId; + private final EdgeId edgeId; + private final T entity; +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/RelationActionEvent.java b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/RelationActionEvent.java new file mode 100644 index 0000000000..81437cd781 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/RelationActionEvent.java @@ -0,0 +1,28 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.eventsourcing; + +import lombok.Data; +import org.thingsboard.server.common.data.audit.ActionType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.relation.EntityRelation; + +@Data +public class RelationActionEvent { + private final TenantId tenantId; + private final EntityRelation relation; + private final ActionType actionType; +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java new file mode 100644 index 0000000000..205f592d43 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java @@ -0,0 +1,30 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.eventsourcing; + +import lombok.Builder; +import lombok.Data; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; + +@Builder +@Data +public class SaveEntityEvent { + private final TenantId tenantId; + private final T entity; + private final EntityId entityId; + private final Boolean added; +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java index 2a784d7985..13f84161c8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java @@ -38,6 +38,8 @@ import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -77,10 +79,12 @@ public class BaseOtaPackageService extends AbstractCachedEntityService handleEvictEvent(EntityRelationEvent.from(relation)), MoreExecutors.directExecutor()); + future.addListener(() -> { + handleEvictEvent(EntityRelationEvent.from(relation)); + eventPublisher.publishEvent(new RelationActionEvent(tenantId, relation, ActionType.RELATION_ADD_OR_UPDATE)); + }, MoreExecutors.directExecutor()); return future; } @@ -188,6 +195,7 @@ public class BaseRelationService implements RelationService { var result = relationDao.deleteRelation(tenantId, relation); //TODO: evict cache only if the relation was deleted. Note: relationDao.deleteRelation requires improvement. publishEvictEvent(EntityRelationEvent.from(relation)); + eventPublisher.publishEvent(new RelationActionEvent(tenantId, relation, ActionType.RELATION_DELETED)); return result; } @@ -196,7 +204,10 @@ public class BaseRelationService implements RelationService { log.trace("Executing deleteRelationAsync [{}]", relation); validate(relation); var future = relationDao.deleteRelationAsync(tenantId, relation); - future.addListener(() -> handleEvictEvent(EntityRelationEvent.from(relation)), MoreExecutors.directExecutor()); + future.addListener(() -> { + handleEvictEvent(EntityRelationEvent.from(relation)); + eventPublisher.publishEvent(new RelationActionEvent(tenantId, relation, ActionType.RELATION_DELETED)); + }, MoreExecutors.directExecutor()); return future; } @@ -206,7 +217,9 @@ public class BaseRelationService implements RelationService { validate(from, to, relationType, typeGroup); var result = relationDao.deleteRelation(tenantId, from, to, relationType, typeGroup); //TODO: evict cache only if the relation was deleted. Note: relationDao.deleteRelation requires improvement. - publishEvictEvent(new EntityRelationEvent(from, to, relationType, typeGroup)); + EntityRelation entityRelation = new EntityRelation(from, to, relationType, typeGroup); + publishEvictEvent(EntityRelationEvent.from(entityRelation)); + eventPublisher.publishEvent(new RelationActionEvent(tenantId, entityRelation, ActionType.RELATION_DELETED)); return result; } @@ -657,5 +670,4 @@ public class BaseRelationService implements RelationService { handleEvictEvent(event); } } - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 56e6969c9a..5e6b1e8009 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -27,10 +27,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbVersionedNode; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; @@ -54,16 +53,17 @@ import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNodeUpdateResult; import org.thingsboard.server.common.data.util.ReflectionUtils; -import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityCountService; +import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.service.validator.RuleChainDataValidator; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -114,6 +114,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (ruleChain.getId() == null) { entityCountService.publishCountEntityEvictEvent(ruleChain.getTenantId(), EntityType.RULE_CHAIN); } + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(savedRuleChain.getTenantId()) + .entity(savedRuleChain).entityId(savedRuleChain.getId()).added(ruleChain.getId() == null).build()); return savedRuleChain; } catch (Exception e) { checkConstraintViolation(e, "rule_chain_external_id_unq_key", "Rule Chain with such external id already exists!"); @@ -259,6 +261,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (!relations.isEmpty()) { relationService.saveRelations(tenantId, relations); } + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(tenantId).entity(ruleChain).entityId(ruleChain.getId()).build()); return RuleChainUpdateResult.successful(updatedRuleNodes); } @@ -594,6 +597,10 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC log.warn("[{}] Failed to create ruleChain relation. Edge Id: [{}]", ruleChainId, edgeId); throw new RuntimeException(e); } + if (!ruleChainId.equals(edge.getRootRuleChainId())) { + eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).edgeId(edgeId).entityId(ruleChainId) + .actionType(ActionType.ASSIGNED_TO_EDGE).build()); + } return ruleChain; } @@ -613,6 +620,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC log.warn("[{}] Failed to delete rule chain relation. Edge Id: [{}]", ruleChainId, edgeId); throw new RuntimeException(e); } + eventPublisher.publishEvent(ActionEntityEvent.builder().tenantId(tenantId).edgeId(edgeId).entityId(ruleChainId) + .actionType(ActionType.UNASSIGNED_FROM_EDGE).build()); return ruleChain; } @@ -726,6 +735,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC try { entityCountService.publishCountEntityEvictEvent(tenantId, EntityType.RULE_CHAIN); ruleChainDao.removeById(tenantId, ruleChainId.getId()); + eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(ruleChainId).build()); } catch (Exception t) { ConstraintViolationException e = extractConstraintViolationException(t).orElse(null); if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_default_rule_chain_device_profile")) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 5dc32b8eed..5afcc49def 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -30,6 +30,7 @@ import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.HasId; @@ -44,6 +45,9 @@ import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.security.event.UserCredentialsInvalidationEvent; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityCountService; +import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -119,7 +123,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic } @Override - public User saveUser(User user) { + public User saveUser(TenantId tenantId, User user) { log.trace("Executing saveUser [{}]", user); userValidator.validate(user, User::getTenantId); if (!userLoginCaseSensitive) { @@ -135,6 +139,11 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic userCredentials.setAdditionalInfo(JacksonUtil.newObjectNode()); userCredentialsDao.save(user.getTenantId(), userCredentials); } + eventPublisher.publishEvent(SaveEntityEvent.builder() + .tenantId(tenantId == null ? TenantId.SYS_TENANT_ID : tenantId) + .entity(user) + .entityId(savedUser.getId()) + .added(user.getId() == null).build()); return savedUser; } @@ -163,7 +172,12 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic public UserCredentials saveUserCredentials(TenantId tenantId, UserCredentials userCredentials) { log.trace("Executing saveUserCredentials [{}]", userCredentials); userCredentialsValidator.validate(userCredentials, data -> tenantId); - return userCredentialsDao.save(tenantId, userCredentials); + UserCredentials result = userCredentialsDao.save(tenantId, userCredentials); + eventPublisher.publishEvent(ActionEntityEvent.builder() + .tenantId(tenantId) + .entityId(userCredentials.getUserId()) + .actionType(ActionType.CREDENTIALS_UPDATED).build()); + return result; } @Override @@ -222,7 +236,12 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic if (userCredentials.getPassword() != null) { updatePasswordHistory(userCredentials); } - return userCredentialsDao.save(tenantId, userCredentials); + UserCredentials result = userCredentialsDao.save(tenantId, userCredentials); + eventPublisher.publishEvent(ActionEntityEvent.builder() + .tenantId(tenantId) + .entityId(userCredentials.getUserId()) + .actionType(ActionType.CREDENTIALS_UPDATED).build()); + return result; } @Override @@ -237,6 +256,9 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic userDao.removeById(tenantId, userId.getId()); eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(userId)); countService.publishCountEntityEvictEvent(tenantId, EntityType.USER); + eventPublisher.publishEvent(DeleteEntityEvent.builder() + .tenantId(tenantId) + .entityId(userId).build()); } @Override @@ -340,7 +362,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic log.trace("Executing onUserLoginSuccessful [{}]", userId); User user = findUserById(tenantId, userId); resetFailedLoginAttempts(user); - saveUser(user); + saveUser(tenantId, user); } private void resetFailedLoginAttempts(User user) { @@ -361,7 +383,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic } ((ObjectNode) additionalInfo).put(LAST_LOGIN_TS, System.currentTimeMillis()); user.setAdditionalInfo(additionalInfo); - saveUser(user); + saveUser(tenantId, user); } @Override @@ -369,7 +391,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic log.trace("Executing onUserLoginIncorrectCredentials [{}]", userId); User user = findUserById(tenantId, userId); int failedLoginAttempts = increaseFailedLoginAttempts(user); - saveUser(user); + saveUser(tenantId, user); return failedLoginAttempts; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index 1ac099b075..d121d18924 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.widget; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; @@ -27,6 +28,8 @@ import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.Validator; @@ -40,12 +43,16 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId "; public static final String INCORRECT_BUNDLE_ALIAS = "Incorrect bundleAlias "; + @Autowired private WidgetTypeDao widgetTypeDao; @Autowired private DataValidator widgetTypeValidator; + @Autowired + protected ApplicationEventPublisher eventPublisher; + @Override public WidgetType findWidgetTypeById(TenantId tenantId, WidgetTypeId widgetTypeId) { log.trace("Executing findWidgetTypeById [{}]", widgetTypeId); @@ -64,7 +71,10 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { public WidgetTypeDetails saveWidgetType(WidgetTypeDetails widgetTypeDetails) { log.trace("Executing saveWidgetType [{}]", widgetTypeDetails); widgetTypeValidator.validate(widgetTypeDetails, WidgetType::getTenantId); - return widgetTypeDao.save(widgetTypeDetails.getTenantId(), widgetTypeDetails); + WidgetTypeDetails result = widgetTypeDao.save(widgetTypeDetails.getTenantId(), widgetTypeDetails); + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(result.getTenantId()) + .entityId(result.getId()).added(widgetTypeDetails.getId() == null).build()); + return result; } @Override @@ -72,6 +82,7 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { log.trace("Executing deleteWidgetType [{}]", widgetTypeId); Validator.validateId(widgetTypeId, "Incorrect widgetTypeId " + widgetTypeId); widgetTypeDao.removeById(tenantId, widgetTypeId.getId()); + eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(widgetTypeId).build()); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index 63a4ce0a77..6becfb460f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.widget; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; @@ -27,6 +28,8 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; +import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -53,6 +56,9 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { @Autowired private DataValidator widgetsBundleValidator; + @Autowired + protected ApplicationEventPublisher eventPublisher; + @Override public WidgetsBundle findWidgetsBundleById(TenantId tenantId, WidgetsBundleId widgetsBundleId) { log.trace("Executing findWidgetsBundleById [{}]", widgetsBundleId); @@ -65,7 +71,10 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { log.trace("Executing saveWidgetsBundle [{}]", widgetsBundle); widgetsBundleValidator.validate(widgetsBundle, WidgetsBundle::getTenantId); try { - return widgetsBundleDao.save(widgetsBundle.getTenantId(), widgetsBundle); + WidgetsBundle result = widgetsBundleDao.save(widgetsBundle.getTenantId(), widgetsBundle); + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(result.getTenantId()) + .entityId(result.getId()).added(widgetsBundle.getId() == null).build()); + return result; } catch (Exception e) { AbstractCachedEntityService.checkConstraintViolation(e, "widgets_bundle_external_id_unq_key", "Widget Bundle with such external id already exists!"); throw e; @@ -81,6 +90,7 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { throw new IncorrectParameterException("Unable to delete non-existent widgets bundle."); } widgetTypeService.deleteWidgetTypesByTenantIdAndBundleAlias(widgetsBundle.getTenantId(), widgetsBundle.getAlias()); + eventPublisher.publishEvent(DeleteEntityEvent.builder().tenantId(tenantId).entityId(widgetsBundleId).build()); widgetsBundleDao.removeById(tenantId, widgetsBundleId.getId()); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AlarmCommentServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AlarmCommentServiceTest.java index 22257242f5..8aa3eeb125 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AlarmCommentServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AlarmCommentServiceTest.java @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.alarm.AlarmCommentInfo; import org.thingsboard.server.common.data.alarm.AlarmCommentType; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -71,7 +72,7 @@ public class AlarmCommentServiceTest extends AbstractServiceTest { user.setEmail("tenant@thingsboard.org"); user.setFirstName("John"); user.setLastName("Brown"); - user = userService.saveUser(user); + user = userService.saveUser(TenantId.SYS_TENANT_ID, user); } @After diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java index 5b0981b44a..412056855e 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AlarmServiceTest.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmUpdateRequest; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.SortOrder; import org.thingsboard.server.common.data.page.TimePageLink; @@ -358,7 +359,7 @@ public class AlarmServiceTest extends AbstractServiceTest { tenantUser.setEmail(TEST_TENANT_EMAIL); tenantUser.setFirstName(TEST_TENANT_FIRST_NAME); tenantUser.setLastName(TEST_TENANT_LAST_NAME); - tenantUser = userService.saveUser(tenantUser); + tenantUser = userService.saveUser(TenantId.SYS_TENANT_ID, tenantUser); Assert.assertNotNull(tenantUser); @@ -392,7 +393,7 @@ public class AlarmServiceTest extends AbstractServiceTest { tenantUser2.setEmail(2 + TEST_TENANT_EMAIL); tenantUser2.setFirstName(TEST_TENANT_FIRST_NAME); tenantUser2.setLastName(TEST_TENANT_LAST_NAME); - tenantUser2 = userService.saveUser(tenantUser2); + tenantUser2 = userService.saveUser(TenantId.SYS_TENANT_ID, tenantUser2); Assert.assertNotNull(tenantUser2); pageLink.setAssigneeId(tenantUser2.getId()); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/EntityServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/EntityServiceTest.java index 22d6bfcd9c..f41e92a305 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/EntityServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/EntityServiceTest.java @@ -260,7 +260,7 @@ public class EntityServiceTest extends AbstractServiceTest { user.setAuthority(Authority.TENANT_ADMIN); user.setEmail(StringUtils.randomAlphabetic(10) + "@gmail.com"); user.setPhone(StringUtils.randomNumeric(10)); - user = userService.saveUser(user); + user = userService.saveUser(tenantId, user); users.add(user); createRelation(tenantId, "Contains", tenantId, user.getId()); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/TenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/TenantServiceTest.java index 5872a5846b..ce1a83514a 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/TenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/TenantServiceTest.java @@ -716,7 +716,7 @@ public class TenantServiceTest extends AbstractServiceTest { user.setFirstName("tenantAdmin"); user.setLastName("tenantAdmin"); user.setTenantId(tenant.getId()); - return userService.saveUser(user); + return userService.saveUser(TenantId.SYS_TENANT_ID, user); } private Tenant createAndSaveTenant(TenantProfile tenantProfile) { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/UserServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/UserServiceTest.java index fcd57e5b3a..c423147474 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/UserServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/UserServiceTest.java @@ -58,7 +58,7 @@ public class UserServiceTest extends AbstractServiceTest { tenantAdmin.setAuthority(Authority.TENANT_ADMIN); tenantAdmin.setTenantId(tenantId); tenantAdmin.setEmail("tenant@thingsboard.org"); - userService.saveUser(tenantAdmin); + userService.saveUser(TenantId.SYS_TENANT_ID, tenantAdmin); Customer customer = new Customer(); customer.setTenantId(tenantId); @@ -70,7 +70,7 @@ public class UserServiceTest extends AbstractServiceTest { customerUser.setTenantId(tenantId); customerUser.setCustomerId(savedCustomer.getId()); customerUser.setEmail("customer@thingsboard.org"); - customerUser = userService.saveUser(customerUser); + customerUser = userService.saveUser(tenantId, customerUser); userSettings = createUserSettings(customerUser.getId()); } @@ -114,7 +114,7 @@ public class UserServiceTest extends AbstractServiceTest { user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(tenantAdminUser.getTenantId()); user.setEmail("tenant2@thingsboard.org"); - User savedUser = userService.saveUser(user); + User savedUser = userService.saveUser(TenantId.SYS_TENANT_ID, user); Assert.assertNotNull(savedUser); Assert.assertNotNull(savedUser.getId()); Assert.assertTrue(savedUser.getCreatedTime() > 0); @@ -130,7 +130,7 @@ public class UserServiceTest extends AbstractServiceTest { savedUser.setFirstName("Joe"); savedUser.setLastName("Downs"); - userService.saveUser(savedUser); + userService.saveUser(TenantId.SYS_TENANT_ID, savedUser); savedUser = userService.findUserById(tenantId, savedUser.getId()); Assert.assertEquals("Joe", savedUser.getFirstName()); Assert.assertEquals("Downs", savedUser.getLastName()); @@ -143,7 +143,7 @@ public class UserServiceTest extends AbstractServiceTest { User tenantAdminUser = userService.findUserByEmail(tenantId, "tenant@thingsboard.org"); tenantAdminUser.setEmail("sysadmin@thingsboard.org"); Assertions.assertThrows(DataValidationException.class, () -> { - userService.saveUser(tenantAdminUser); + userService.saveUser(tenantId, tenantAdminUser); }); } @@ -152,7 +152,7 @@ public class UserServiceTest extends AbstractServiceTest { User tenantAdminUser = userService.findUserByEmail(tenantId, "tenant@thingsboard.org"); tenantAdminUser.setEmail("tenant_thingsboard.org"); Assertions.assertThrows(DataValidationException.class, () -> { - userService.saveUser(tenantAdminUser); + userService.saveUser(tenantId, tenantAdminUser); }); } @@ -161,7 +161,7 @@ public class UserServiceTest extends AbstractServiceTest { User tenantAdminUser = userService.findUserByEmail(tenantId, "tenant@thingsboard.org"); tenantAdminUser.setEmail(null); Assertions.assertThrows(DataValidationException.class, () -> { - userService.saveUser(tenantAdminUser); + userService.saveUser(tenantId, tenantAdminUser); }); } @@ -170,7 +170,7 @@ public class UserServiceTest extends AbstractServiceTest { User tenantAdminUser = userService.findUserByEmail(tenantId, "tenant@thingsboard.org"); tenantAdminUser.setTenantId(null); Assertions.assertThrows(DataValidationException.class, () -> { - userService.saveUser(tenantAdminUser); + userService.saveUser(tenantId, tenantAdminUser); }); } @@ -181,7 +181,7 @@ public class UserServiceTest extends AbstractServiceTest { user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(tenantAdminUser.getTenantId()); user.setEmail("tenant2@thingsboard.org"); - User savedUser = userService.saveUser(user); + User savedUser = userService.saveUser(TenantId.SYS_TENANT_ID, user); Assert.assertNotNull(savedUser); Assert.assertNotNull(savedUser.getId()); User foundUser = userService.findUserById(tenantId, savedUser.getId()); @@ -212,7 +212,7 @@ public class UserServiceTest extends AbstractServiceTest { user.setAuthority(Authority.TENANT_ADMIN); user.setTenantId(secondTenantId); user.setEmail("testTenant" + i + "@thingsboard.org"); - tenantAdmins.add(userService.saveUser(user)); + tenantAdmins.add(userService.saveUser(TenantId.SYS_TENANT_ID, user)); } List loadedTenantAdmins = new ArrayList<>(); @@ -252,7 +252,7 @@ public class UserServiceTest extends AbstractServiceTest { String email = email1 + suffix + "@thingsboard.org"; email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); user.setEmail(email); - tenantAdminsEmail1.add(userService.saveUser(user)); + tenantAdminsEmail1.add(userService.saveUser(TenantId.SYS_TENANT_ID, user)); } String email2 = "testEmail2"; @@ -266,7 +266,7 @@ public class UserServiceTest extends AbstractServiceTest { String email = email2 + suffix + "@thingsboard.org"; email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); user.setEmail(email); - tenantAdminsEmail2.add(userService.saveUser(user)); + tenantAdminsEmail2.add(userService.saveUser(TenantId.SYS_TENANT_ID, user)); } List loadedTenantAdminsEmail1 = new ArrayList<>(); @@ -343,7 +343,7 @@ public class UserServiceTest extends AbstractServiceTest { user.setTenantId(tenantId); user.setCustomerId(customerId); user.setEmail("testCustomer" + i + "@thingsboard.org"); - customerUsers.add(userService.saveUser(user)); + customerUsers.add(userService.saveUser(tenantId, user)); } List loadedCustomerUsers = new ArrayList<>(); @@ -390,7 +390,7 @@ public class UserServiceTest extends AbstractServiceTest { String email = email1 + suffix + "@thingsboard.org"; email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); user.setEmail(email); - customerUsersEmail1.add(userService.saveUser(user)); + customerUsersEmail1.add(userService.saveUser(tenantId, user)); } String email2 = "testEmail2"; @@ -405,7 +405,7 @@ public class UserServiceTest extends AbstractServiceTest { String email = email2 + suffix + "@thingsboard.org"; email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); user.setEmail(email); - customerUsersEmail2.add(userService.saveUser(user)); + customerUsersEmail2.add(userService.saveUser(tenantId, user)); } List loadedCustomerUsersEmail1 = new ArrayList<>(); From dd19109034ddaa14380e1b0d156eb6e0318e25fe Mon Sep 17 00:00:00 2001 From: rusikv Date: Mon, 7 Aug 2023 16:11:14 +0300 Subject: [PATCH 388/421] Add delete button to selection in alarm table --- ui-ngx/src/app/core/http/alarm.service.ts | 12 ++-- .../components/alarm/alarm-table-config.ts | 65 +++++++++++++++---- .../lib/alarms-table-widget.component.ts | 4 +- .../assets/locale/locale.constant-en_US.json | 3 + 4 files changed, 63 insertions(+), 21 deletions(-) diff --git a/ui-ngx/src/app/core/http/alarm.service.ts b/ui-ngx/src/app/core/http/alarm.service.ts index e03e9ab783..f0ce187341 100644 --- a/ui-ngx/src/app/core/http/alarm.service.ts +++ b/ui-ngx/src/app/core/http/alarm.service.ts @@ -52,12 +52,12 @@ export class AlarmService { return this.http.post('/api/alarm', alarm, defaultHttpOptionsFromConfig(config)); } - public ackAlarm(alarmId: string, config?: RequestConfig): Observable { - return this.http.post(`/api/alarm/${alarmId}/ack`, null, defaultHttpOptionsFromConfig(config)); + public ackAlarm(alarmId: string, config?: RequestConfig): Observable { + return this.http.post(`/api/alarm/${alarmId}/ack`, null, defaultHttpOptionsFromConfig(config)); } - public clearAlarm(alarmId: string, config?: RequestConfig): Observable { - return this.http.post(`/api/alarm/${alarmId}/clear`, null, defaultHttpOptionsFromConfig(config)); + public clearAlarm(alarmId: string, config?: RequestConfig): Observable { + return this.http.post(`/api/alarm/${alarmId}/clear`, null, defaultHttpOptionsFromConfig(config)); } public assignAlarm(alarmId: string, assigneeId: string, config?: RequestConfig): Observable { @@ -68,8 +68,8 @@ export class AlarmService { return this.http.delete(`/api/alarm/${alarmId}/assign`, defaultHttpOptionsFromConfig(config)); } - public deleteAlarm(alarmId: string, config?: RequestConfig): Observable { - return this.http.delete(`/api/alarm/${alarmId}`, defaultHttpOptionsFromConfig(config)); + public deleteAlarm(alarmId: string, config?: RequestConfig): Observable { + return this.http.delete(`/api/alarm/${alarmId}`, defaultHttpOptionsFromConfig(config)); } public getAlarms(query: AlarmQuery, diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts index 646e05511f..15e3fb1952 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts @@ -162,14 +162,18 @@ export class AlarmTableConfig extends EntityTableConfig icon: 'done', isEnabled: true, onAction: ($event, entities) => this.ackAlarms($event, entities) - } - ) - this.groupActionDescriptors.push( + }, { name: this.translate.instant('alarm.clear'), icon: 'clear', isEnabled: true, onAction: ($event, entities) => this.clearAlarms($event, entities) + }, + { + name: this.translate.instant('alarm.delete'), + icon: 'delete', + isEnabled: true, + onAction: ($event, entities) => this.deleteAlarms($event, entities) } ) } @@ -318,12 +322,17 @@ export class AlarmTableConfig extends EntityTableConfig const unacknowledgedAlarms = alarms.filter(alarm => { return alarm.status === AlarmStatus.CLEARED_UNACK || alarm.status === AlarmStatus.ACTIVE_UNACK; }) + let title = ''; + let content = ''; if (!unacknowledgedAlarms.length) { - this.dialogService.alert(this.translate.instant('alarm.selected-alarms', {count: alarms.length}), - this.translate.instant('alarm.selected-alarms-are-acknowledged')).subscribe(); + title = this.translate.instant('alarm.selected-alarms', {count: alarms.length}); + content = this.translate.instant('alarm.selected-alarms-are-acknowledged'); + this.dialogService.alert( + title, + content).subscribe(); } else { - const title = this.translate.instant('alarm.aknowledge-alarms-title', {count: unacknowledgedAlarms.length}); - const content = this.translate.instant('alarm.aknowledge-alarms-text', {count: unacknowledgedAlarms.length}); + title = this.translate.instant('alarm.aknowledge-alarms-title', {count: unacknowledgedAlarms.length}); + content = this.translate.instant('alarm.aknowledge-alarms-text', {count: unacknowledgedAlarms.length}); this.dialogService.confirm( title, content, @@ -331,7 +340,7 @@ export class AlarmTableConfig extends EntityTableConfig this.translate.instant('action.yes') ).subscribe((res) => { if (res) { - const tasks: Observable[] = []; + const tasks: Observable[] = []; for (const alarm of unacknowledgedAlarms) { tasks.push(this.alarmService.ackAlarm(alarm.id.id)); } @@ -350,12 +359,18 @@ export class AlarmTableConfig extends EntityTableConfig const activeAlarms = alarms.filter(alarm => { return alarm.status === AlarmStatus.ACTIVE_ACK || alarm.status === AlarmStatus.ACTIVE_UNACK; }) + let title = ''; + let content = ''; if (!activeAlarms.length) { - this.dialogService.alert(this.translate.instant('alarm.selected-alarms', {count: alarms.length}), - this.translate.instant('alarm.selected-alarms-are-cleared')).subscribe(); + title = this.translate.instant('alarm.selected-alarms', {count: alarms.length}); + content = this.translate.instant('alarm.selected-alarms-are-cleared'); + this.dialogService.alert( + title, + content + ).subscribe(); } else { - const title = this.translate.instant('alarm.clear-alarms-title', {count: activeAlarms.length}); - const content = this.translate.instant('alarm.clear-alarms-text', {count: activeAlarms.length}); + title = this.translate.instant('alarm.clear-alarms-title', {count: activeAlarms.length}); + content = this.translate.instant('alarm.clear-alarms-text', {count: activeAlarms.length}); this.dialogService.confirm( title, content, @@ -363,7 +378,7 @@ export class AlarmTableConfig extends EntityTableConfig this.translate.instant('action.yes') ).subscribe((res) => { if (res) { - const tasks: Observable[] = []; + const tasks: Observable[] = []; for (const alarm of activeAlarms) { tasks.push(this.alarmService.clearAlarm(alarm.id.id)); } @@ -375,4 +390,28 @@ export class AlarmTableConfig extends EntityTableConfig } } + deleteAlarms($event: Event, alarms: Array) { + if ($event) { + $event.stopPropagation(); + } + const title = this.translate.instant('alarm.delete-alarms-title', {count: alarms.length}); + const content = this.translate.instant('alarm.delete-alarms-text', {count: alarms.length}); + this.dialogService.confirm( + title, + content, + this.translate.instant('action.no'), + this.translate.instant('action.yes') + ).subscribe((res) => { + if (res) { + const tasks: Observable[] = []; + for (const alarm of alarms) { + tasks.push(this.alarmService.deleteAlarm(alarm.id.id)); + } + forkJoin(tasks).subscribe(() => { + this.updateData(); + }); + } + }); + } + } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index f799ed43ff..57e8db694c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -927,7 +927,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, ).subscribe((res) => { if (res) { if (res) { - const tasks: Observable[] = []; + const tasks: Observable[] = []; for (const alarmId of alarmIds) { tasks.push(this.alarmService.ackAlarm(alarmId)); } @@ -983,7 +983,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, ).subscribe((res) => { if (res) { if (res) { - const tasks: Observable[] = []; + const tasks: Observable[] = []; for (const alarmId of alarmIds) { tasks.push(this.alarmService.clearAlarm(alarmId)); } 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 756cbb3ab6..ce134c1fd4 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -512,6 +512,7 @@ "severity-indeterminate": "Indeterminate", "acknowledge": "Acknowledge", "clear": "Clear", + "delete": "Delete", "search": "Search alarms", "selected-alarms": "{ count, plural, =1 {1 alarm} other {# alarms} } selected", "no-data": "No data to display", @@ -527,6 +528,8 @@ "clear-alarms-text": "Are you sure you want to clear { count, plural, =1 {1 alarm} other {# alarms} }?", "clear-alarm-title": "Clear Alarm", "clear-alarm-text": "Are you sure you want to clear Alarm?", + "delete-alarms-title": "Delete { count, plural, =1 {1 alarm} other {# alarms} }", + "delete-alarms-text": "Are you sure you want to delete { count, plural, =1 {1 alarm} other {# alarms} }?", "selected-alarms-are-cleared": "Selected alarms are already cleared", "alarm-status-filter": "Alarm Status Filter", "alarm-filter-title": "Alarm Filter", From d3710b411fdec58a2472ef01fb3d692fd7a14b7c Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Mon, 7 Aug 2023 16:50:10 +0300 Subject: [PATCH 389/421] Check user's additionalInfo for nullity --- .../notification/DefaultNotificationSettingsService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java index cec5a91db5..805cc31571 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java @@ -54,8 +54,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import static java.util.function.Predicate.not; - @Service @RequiredArgsConstructor public class DefaultNotificationSettingsService implements NotificationSettingsService { @@ -107,8 +105,8 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS @Override public UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user, boolean format) { - UserNotificationSettings settings = Optional.ofNullable(user.getAdditionalInfo().get(USER_SETTINGS_KEY)) - .filter(not(JsonNode::isNull)) + UserNotificationSettings settings = Optional.ofNullable(user.getAdditionalInfo()) + .filter(JsonNode::isObject).map(info -> info.get(USER_SETTINGS_KEY)).filter(JsonNode::isObject) .map(json -> JacksonUtil.treeToValue(json, UserNotificationSettings.class)) .orElse(UserNotificationSettings.DEFAULT); if (format) { From fe7846d1520ae4d06311ebcf6b54161a814f024b Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 19 Aug 2021 15:23:16 +0200 Subject: [PATCH 390/421] ui: event table: default interval is 15 minutes --- .../src/app/modules/home/components/event/event-table-config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index a9816a130c..8b0ea62abb 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -40,6 +40,7 @@ import { EventContentDialogData } from '@home/components/event/event-content-dialog.component'; import { isEqual, sortObjectKeys } from '@core/utils'; +import {historyInterval, MINUTE} from '@shared/models/time/time.models'; import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { ChangeDetectorRef, Injector, StaticProvider, ViewContainerRef } from '@angular/core'; import { ComponentPortal } from '@angular/cdk/portal'; @@ -89,6 +90,7 @@ export class EventTableConfig extends EntityTableConfig { this.loadDataOnInit = false; this.tableTitle = ''; this.useTimePageLink = true; + this.defaultTimewindowInterval = historyInterval(MINUTE * 15); this.detailsPanelEnabled = false; this.selectionEnabled = false; this.searchEnabled = false; From 33bab60954e67220e278bf4399daf440d464efca Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 19 Aug 2021 15:22:46 +0200 Subject: [PATCH 391/421] ui: event table: ts with ms --- .../src/app/modules/home/components/event/event-table-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 8b0ea62abb..a07967f9c3 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -178,7 +178,7 @@ export class EventTableConfig extends EntityTableConfig { updateColumns(updateTableColumns: boolean = false): void { this.columns = []; this.columns.push( - new DateEntityTableColumn('createdTime', 'event.event-time', this.datePipe, '120px'), + new DateEntityTableColumn('createdTime', 'event.event-time', this.datePipe, '120px', 'yyyy-MM-dd HH:mm:ss.SSS'), new EntityTableColumn('server', 'event.server', '100px', (entity) => entity.body.server, entity => ({}), false)); switch (this.eventType) { From b7d522295810b59201614f3df28fc59eabc18e0d Mon Sep 17 00:00:00 2001 From: Vladyslav Date: Tue, 8 Aug 2023 17:16:02 +0300 Subject: [PATCH 392/421] UI: Updated code style --- .../src/app/modules/home/components/event/event-table-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index a07967f9c3..eb3edb0baf 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -40,7 +40,7 @@ import { EventContentDialogData } from '@home/components/event/event-content-dialog.component'; import { isEqual, sortObjectKeys } from '@core/utils'; -import {historyInterval, MINUTE} from '@shared/models/time/time.models'; +import { historyInterval, MINUTE } from '@shared/models/time/time.models'; import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { ChangeDetectorRef, Injector, StaticProvider, ViewContainerRef } from '@angular/core'; import { ComponentPortal } from '@angular/cdk/portal'; From a1fb657b0c1835faab0a3a786f66cdf00c1d91b6 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 8 Aug 2023 18:54:07 +0300 Subject: [PATCH 393/421] UI: Introduce timewindow style. Ability to embed widget title panel into widget template. Add pattern support for widget title, etc. --- .../json/system/widget_bundles/cards.json | 16 +-- .../src/app/core/services/dialog.service.ts | 15 +-- .../dynamic-component-factory.service.ts | 32 ++++-- ui-ngx/src/app/core/utils.ts | 20 ++-- .../dashboard-page.component.html | 4 - .../alarms-table-basic-config.component.html | 1 + .../alarms-table-basic-config.component.ts | 9 +- ...entities-table-basic-config.component.html | 1 + .../entities-table-basic-config.component.ts | 9 +- .../simple-card-basic-config.component.ts | 9 +- ...meseries-table-basic-config.component.html | 1 + ...timeseries-table-basic-config.component.ts | 9 +- .../value-card-basic-config.component.html | 1 + .../value-card-basic-config.component.ts | 9 +- .../chart/flot-basic-config.component.html | 1 + .../chart/flot-basic-config.component.ts | 9 +- .../timewindow-config-panel.component.html | 23 ++-- .../timewindow-config-panel.component.ts | 25 +++- .../timewindow-style-panel.component.html | 97 ++++++++++++++++ .../timewindow-style-panel.component.scss | 54 +++++++++ .../timewindow-style-panel.component.ts | 108 ++++++++++++++++++ .../config/timewindow-style.component.html | 25 ++++ .../config/timewindow-style.component.ts | 97 ++++++++++++++++ .../config/widget-config-components.module.ts | 6 + .../custom-dialog-container.component.ts | 11 +- .../widget/dialog/custom-dialog.service.ts | 11 +- .../widget/dynamic-widget.component.ts | 5 +- .../lib/alarms-table-widget.component.ts | 30 +---- .../cards/value-card-widget.component.html | 5 +- .../cards/value-card-widget.component.scss | 7 ++ .../lib/cards/value-card-widget.component.ts | 17 ++- .../lib/cards/value-card-widget.models.ts | 9 +- .../lib/entities-table-widget.component.ts | 38 ++---- .../widget/lib/json-input-widget.component.ts | 6 +- .../lib/multiple-input-widget.component.ts | 5 +- .../value-card-widget-settings.component.html | 1 + .../common/font-settings-panel.component.html | 6 + .../common/font-settings-panel.component.ts | 5 +- .../widget/widget-component.service.ts | 13 ++- .../widget/widget-config.component.html | 1 + .../widget/widget-config.component.ts | 6 +- .../widget/widget-container.component.html | 62 +++++----- .../widget/widget-container.component.scss | 28 ++--- .../widget/widget-preview.component.ts | 16 +-- .../components/widget/widget.component.ts | 23 ++-- .../home/models/dashboard-component.models.ts | 37 +++--- .../home/models/widget-component.models.ts | 75 +++++++++++- .../components/color-input.component.ts | 6 +- .../dialog/color-picker-dialog.component.ts | 13 ++- .../material-icons-dialog.component.html | 1 + .../dialog/material-icons-dialog.component.ts | 16 ++- .../app/shared/components/icon.component.ts | 2 +- .../json-form/json-form.component.ts | 12 +- .../shared/components/markdown.component.ts | 18 +-- .../material-icon-select.component.ts | 24 ++-- .../components/material-icons.component.html | 9 ++ .../components/material-icons.component.scss | 8 ++ .../components/material-icons.component.ts | 9 ++ .../components/time/timewindow.component.html | 32 ++---- .../components/time/timewindow.component.scss | 17 ++- .../components/time/timewindow.component.ts | 55 ++++++++- .../shared/models/widget-settings.models.ts | 28 ++++- ui-ngx/src/app/shared/models/widget.models.ts | 5 +- .../assets/locale/locale.constant-en_US.json | 13 ++- 64 files changed, 928 insertions(+), 338 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.ts diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 1289923667..b87f2c7b83 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -229,43 +229,43 @@ { "alias": "value_card", "name": "Value card", - "image": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyNyIgZmlsbD0ibm9uZSIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgMTI4IDEyNyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2RfMTE0Ml8yMDM5NTQpIj4KICA8cmVjdCB4PSI1LjUiIHk9IjIuNSIgd2lkdGg9IjExNyIgaGVpZ2h0PSIxMTciIHJ4PSIyLjI5NDEiIGZpbGw9IiNmZmYiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPgogIDxwYXRoIGQ9Im0zMy42MDMgMjkuMjIxdi03LjY0NzFjMC0xLjU4NjgtMS4yODA4LTIuODY3Ni0yLjg2NzYtMi44Njc2cy0yLjg2NzcgMS4yODA4LTIuODY3NyAyLjg2NzZ2Ny42NDcxYy0xLjE1NjYgMC44Njk4LTEuOTExNyAyLjI2NTQtMS45MTE3IDMuODIzNSAwIDIuNjM4MiAyLjE0MTIgNC43Nzk0IDQuNzc5NCA0Ljc3OTRzNC43Nzk0LTIuMTQxMiA0Ljc3OTQtNC43Nzk0YzAtMS41NTgxLTAuNzU1MS0yLjk1MzctMS45MTE4LTMuODIzNXptLTMuODIzNS03LjY0NzFjMC0wLjUyNTcgMC40MzAyLTAuOTU1OSAwLjk1NTktMC45NTU5czAuOTU1OSAwLjQzMDIgMC45NTU5IDAuOTU1OWgtMC45NTU5djAuOTU1OWgwLjk1NTl2MS45MTE3aC0wLjk1NTl2MC45NTU5aDAuOTU1OXYxLjkxMThoLTEuOTExOHYtNS43MzUzeiIgZmlsbD0iIzU0NjlGRiIvPgogIDxnIGZpbGw9IiMwMDAiPgogICA8cGF0aCBkPSJtNTAuMTQxIDE5Ljc0MXY2LjUyMzhoLTEuMTE1N3YtNi41MjM4aDEuMTE1N3ptMi4wNDc3IDB2MC44OTYxaC01LjE5MzJ2LTAuODk2MWg1LjE5MzJ6bTIuNjAzMyA2LjYxMzVjLTAuMzU4NSAwLTAuNjgyNi0wLjA1ODMtMC45NzIzLTAuMTc0OC0wLjI4NjgtMC4xMTk1LTAuNTMxOC0wLjI4NTMtMC43MzQ5LTAuNDk3My0wLjIwMDEtMC4yMTIxLTAuMzU0LTAuNDYxNi0wLjQ2MTUtMC43NDgzLTAuMTA3NS0wLjI4NjgtMC4xNjEzLTAuNTk2LTAuMTYxMy0wLjkyNzV2LTAuMTc5M2MwLTAuMzc5MyAwLjA1NTMtMC43MjI4IDAuMTY1OC0xLjAzMDVzMC4yNjQzLTAuNTcwNiAwLjQ2MTUtMC43ODg2YzAuMTk3MS0wLjIyMTEgMC40MzAxLTAuMzg5OCAwLjY5OS0wLjUwNjMgMC4yNjg4LTAuMTE2NSAwLjU2MDEtMC4xNzQ4IDAuODczNy0wLjE3NDggMC4zNDY1IDAgMC42NDk3IDAuMDU4MyAwLjkwOTYgMC4xNzQ4czAuNDc1IDAuMjgwOCAwLjY0NTIgMC40OTI4YzAuMTczMyAwLjIwOTEgMC4zMDE3IDAuNDU4NiAwLjM4NTQgMC43NDgzIDAuMDg2NiAwLjI4OTggMC4xMjk5IDAuNjA5NCAwLjEyOTkgMC45NTg5djAuNDYxNWgtMy43NDU5di0wLjc3NTJoMi42Nzk1di0wLjA4NTFjLTZlLTMgLTAuMTk0Mi0wLjA0NDgtMC4zNzY0LTAuMTE2NS0wLjU0NjYtMC4wNjg3LTAuMTcwMy0wLjE3NDctMC4zMDc3LTAuMzE4MS0wLjQxMjMtMC4xNDM0LTAuMTA0NS0wLjMzNDYtMC4xNTY4LTAuNTczNi0wLjE1NjgtMC4xNzkyIDAtMC4zMzkgMC4wMzg4LTAuNDc5NCAwLjExNjUtMC4xMzc0IDAuMDc0Ny0wLjI1MjQgMC4xODM3LTAuMzQ1IDAuMzI3MXMtMC4xNjQzIDAuMzE2Ni0wLjIxNTEgMC41MTk4Yy0wLjA0NzggMC4yMDAxLTAuMDcxNyAwLjQyNTYtMC4wNzE3IDAuNjc2NXYwLjE3OTNjMCAwLjIxMjEgMC4wMjg0IDAuNDA5MiAwLjA4NTIgMC41OTE0IDAuMDU5NyAwLjE3OTMgMC4xNDYzIDAuMzM2MSAwLjI1OTggMC40NzA1IDAuMTEzNiAwLjEzNDQgMC4yNTEgMC4yNDA1IDAuNDEyMyAwLjMxODEgMC4xNjEzIDAuMDc0NyAwLjM0NSAwLjExMiAwLjU1MTEgMC4xMTIgMC4yNTk5IDAgMC40OTE0LTAuMDUyMiAwLjY5NDUtMC4xNTY4IDAuMjAzMS0wLjEwNDUgMC4zNzk0LTAuMjUyNCAwLjUyODctMC40NDM2bDAuNTY5MSAwLjU1MTJjLTAuMTA0NiAwLjE1MjMtMC4yNDA1IDAuMjk4Ny0wLjQwNzggMC40MzkxLTAuMTY3MyAwLjEzNzQtMC4zNzE5IDAuMjQ5NC0wLjYxMzggMC4zMzYtMC4yMzkgMC4wODY2LTAuNTE2OCAwLjEzLTAuODMzNCAwLjEzem00LjAwNTctMy45NTJ2My44NjIzaC0xLjA3OTh2LTQuODQ4MWgxLjAxNzFsMC4wNjI3IDAuOTg1OHptLTAuMTc0NyAxLjI1OTEtMC4zNjc1LTAuMDA0NWMwLTAuMzM0NiAwLjA0MTktMC42NDM3IDAuMTI1NS0wLjkyNzVzMC4yMDYxLTAuNTMwMiAwLjM2NzQtMC43MzkzYzAuMTYxMy0wLjIxMjEgMC4zNjE1LTAuMzc0OSAwLjYwMDQtMC40ODg0IDAuMjQyLTAuMTE2NSAwLjUyMTMtMC4xNzQ4IDAuODM3OS0wLjE3NDggMC4yMjExIDAgMC40MjI3IDAuMDMyOSAwLjYwNDkgMC4wOTg2IDAuMTg1MiAwLjA2MjcgMC4zNDUgMC4xNjI4IDAuNDc5NSAwLjMwMDIgMC4xMzc0IDAuMTM3NCAwLjI0MTkgMC4zMTM2IDAuMzEzNiAwLjUyODcgMC4wNzQ3IDAuMjE1MSAwLjExMiAwLjQ3NSAwLjExMiAwLjc3OTd2My4yMzA1aC0xLjA3OTh2LTMuMTM2NGMwLTAuMjM2LTAuMDM1OS0wLjQyMTItMC4xMDc2LTAuNTU1Ni0wLjA2ODctMC4xMzQ1LTAuMTY4Ny0wLjIzMDEtMC4zMDAyLTAuMjg2OC0wLjEyODQtMC4wNTk4LTAuMjgyMy0wLjA4OTYtMC40NjE1LTAuMDg5Ni0wLjIwMzEgMC0wLjM3NjQgMC4wMzg4LTAuNTE5NyAwLjExNjUtMC4xNDA0IDAuMDc3Ni0wLjI1NTQgMC4xODM3LTAuMzQ1MSAwLjMxODEtMC4wODk2IDAuMTM0NC0wLjE1NTMgMC4yODk4LTAuMTk3MSAwLjQ2NnMtMC4wNjI3IDAuMzY0NC0wLjA2MjcgMC41NjQ2em0zLjAwNjUtMC4yODY4LTAuNTA2MyAwLjExMmMwLTAuMjkyNyAwLjA0MDMtMC41NjkgMC4xMjEtMC44Mjg5IDAuMDgzNi0wLjI2MjkgMC4yMDQ2LTAuNDkyOSAwLjM2MjktMC42OSAwLjE2MTMtMC4yMDAyIDAuMzYtMC4zNTcgMC41OTU5LTAuNDcwNSAwLjIzNi0wLjExMzUgMC41MDY0LTAuMTcwMyAwLjgxMS0wLjE3MDMgMC4yNDggMCAwLjQ2OSAwLjAzNDQgMC42NjMyIDAuMTAzMSAwLjE5NzEgMC4wNjU3IDAuMzY0NCAwLjE3MDIgMC41MDE4IDAuMzEzNnMwLjI0MiAwLjMzMDEgMC4zMTM3IDAuNTYwMWMwLjA3MTcgMC4yMjcgMC4xMDc1IDAuNTAxOCAwLjEwNzUgMC44MjQ1djMuMTM2NGgtMS4wODQzdi0zLjE0MDljMC0wLjI0NS0wLjAzNTktMC40MzQ2LTAuMTA3Ni0wLjU2OTEtMC4wNjg3LTAuMTM0NC0wLjE2NzItMC4yMjctMC4yOTU3LTAuMjc3OC0wLjEyODQtMC4wNTM3LTAuMjgyMy0wLjA4MDYtMC40NjE1LTAuMDgwNi0wLjE2NzMgMC0wLjMxNTEgMC4wMzEzLTAuNDQzNiAwLjA5NDEtMC4xMjU0IDAuMDU5Ny0wLjIzMTUgMC4xNDQ4LTAuMzE4MSAwLjI1NTQtMC4wODY2IDAuMTA3NS0wLjE1MjQgMC4yMzE1LTAuMTk3MiAwLjM3MTktMC4wNDE4IDAuMTQwNC0wLjA2MjcgMC4yOTI3LTAuMDYyNyAwLjQ1N3ptNS4zMDk2LTEuMDI2MXY1Ljc4MDFoLTEuMDc5OHYtNi43MTIxaDAuOTk0N2wwLjA4NTEgMC45MzJ6bTMuMTU4OSAxLjQ0NzN2MC4wOTQxYzAgMC4zNTI1LTAuMDQxOCAwLjY3OTYtMC4xMjU0IDAuOTgxMy0wLjA4MDcgMC4yOTg3LTAuMjAxNyAwLjU2LTAuMzYzIDAuNzg0MS0wLjE1ODMgMC4yMjEtMC4zNTM5IDAuMzkyOC0wLjU4NjkgMC41MTUzLTAuMjMzIDAuMTIyNC0wLjUwMTkgMC4xODM3LTAuODA2NiAwLjE4MzctMC4zMDE3IDAtMC41NjYtMC4wNTUzLTAuNzkzLTAuMTY1OC0wLjIyNDEtMC4xMTM1LTAuNDEzOC0wLjI3MzMtMC41NjkxLTAuNDc5NS0wLjE1NTMtMC4yMDYxLTAuMjgwOC0wLjQ0OC0wLjM3NjQtMC43MjU4LTAuMDkyNi0wLjI4MDgtMC4xNTgzLTAuNTg4NS0wLjE5NzEtMC45MjMxdi0wLjM2MjljMC4wMzg4LTAuMzU1NSAwLjEwNDUtMC42NzgxIDAuMTk3MS0wLjk2NzggMC4wOTU2LTAuMjg5OCAwLjIyMTEtMC41MzkyIDAuMzc2NC0wLjc0ODNzMC4zNDUtMC4zNzA0IDAuNTY5MS0wLjQ4MzljMC4yMjQtMC4xMTM1IDAuNDg1NC0wLjE3MDMgMC43ODQxLTAuMTcwMyAwLjMwNDcgMCAwLjU3NSAwLjA1OTggMC44MTEgMC4xNzkyIDAuMjM2IDAuMTE2NSAwLjQzNDYgMC4yODM4IDAuNTk1OSAwLjUwMTkgMC4xNjEzIDAuMjE1MSAwLjI4MjMgMC40NzQ5IDAuMzYyOSAwLjc3OTYgMC4wODA3IDAuMzAxNyAwLjEyMSAwLjYzNzggMC4xMjEgMS4wMDgyem0tMS4wNzk4IDAuMDk0MXYtMC4wOTQxYzAtMC4yMjQxLTAuMDIwOS0wLjQzMTctMC4wNjI3LTAuNjIyOC0wLjA0MTktMC4xOTQyLTAuMTA3Ni0wLjM2NDUtMC4xOTcyLTAuNTEwOC0wLjA4OTYtMC4xNDY0LTAuMjA0Ni0wLjI1OTktMC4zNDUtMC4zNDA2LTAuMTM3NC0wLjA4MzYtMC4zMDMyLTAuMTI1NC0wLjQ5NzQtMC4xMjU0LTAuMTkxMSAwLTAuMzU1NCAwLjAzMjgtMC40OTI4IDAuMDk4NS0wLjEzNzUgMC4wNjI4LTAuMjUyNSAwLjE1MDktMC4zNDUxIDAuMjY0NHMtMC4xNjQzIDAuMjQ2NC0wLjIxNSAwLjM5ODhjLTAuMDUwOCAwLjE0OTMtMC4wODY3IDAuMzEyMS0wLjEwNzYgMC40ODg0djAuODY5MmMwLjAzNTkgMC4yMTUxIDAuMDk3MSAwLjQxMjMgMC4xODM3IDAuNTkxNSAwLjA4NjcgMC4xNzkyIDAuMjA5MSAwLjMyMjYgMC4zNjc1IDAuNDMwMSAwLjE2MTMgMC4xMDQ2IDAuMzY3NCAwLjE1NjkgMC42MTgzIDAuMTU2OSAwLjE5NDIgMCAwLjM1OTktMC4wNDE5IDAuNDk3My0wLjEyNTUgMC4xMzc1LTAuMDgzNiAwLjI0OTUtMC4xOTg2IDAuMzM2MS0wLjM0NSAwLjA4OTYtMC4xNDk0IDAuMTU1My0wLjMyMTEgMC4xOTcyLTAuNTE1MyAwLjA0MTgtMC4xOTQxIDAuMDYyNy0wLjQwMDMgMC4wNjI3LTAuNjE4M3ptNC4yNzkgMi40NjQ0Yy0wLjM1ODQgMC0wLjY4MjUtMC4wNTgzLTAuOTcyMy0wLjE3NDgtMC4yODY3LTAuMTE5NS0wLjUzMTctMC4yODUzLTAuNzM0OC0wLjQ5NzMtMC4yMDAxLTAuMjEyMS0wLjM1NC0wLjQ2MTYtMC40NjE1LTAuNzQ4My0wLjEwNzUtMC4yODY4LTAuMTYxMy0wLjU5Ni0wLjE2MTMtMC45Mjc1di0wLjE3OTNjMC0wLjM3OTMgMC4wNTUyLTAuNzIyOCAwLjE2NTgtMS4wMzA1IDAuMTEwNS0wLjMwNzcgMC4yNjQzLTAuNTcwNiAwLjQ2MTUtMC43ODg2IDAuMTk3MS0wLjIyMTEgMC40MzAxLTAuMzg5OCAwLjY5OS0wLjUwNjMgMC4yNjg4LTAuMTE2NSAwLjU2MDEtMC4xNzQ4IDAuODczNy0wLjE3NDggMC4zNDY1IDAgMC42NDk3IDAuMDU4MyAwLjkwOTYgMC4xNzQ4czAuNDc0OSAwLjI4MDggMC42NDUyIDAuNDkyOGMwLjE3MzMgMC4yMDkxIDAuMzAxNyAwLjQ1ODYgMC4zODUzIDAuNzQ4MyAwLjA4NjcgMC4yODk4IDAuMTMgMC42MDk0IDAuMTMgMC45NTg5djAuNDYxNWgtMy43NDU5di0wLjc3NTJoMi42Nzk1di0wLjA4NTFjLTZlLTMgLTAuMTk0Mi0wLjA0NDgtMC4zNzY0LTAuMTE2NS0wLjU0NjYtMC4wNjg3LTAuMTcwMy0wLjE3NDgtMC4zMDc3LTAuMzE4MS0wLjQxMjMtMC4xNDM0LTAuMTA0NS0wLjMzNDYtMC4xNTY4LTAuNTczNi0wLjE1NjgtMC4xNzkyIDAtMC4zMzkgMC4wMzg4LTAuNDc5NCAwLjExNjUtMC4xMzc0IDAuMDc0Ny0wLjI1MjQgMC4xODM3LTAuMzQ1IDAuMzI3MXMtMC4xNjQzIDAuMzE2Ni0wLjIxNTEgMC41MTk4Yy0wLjA0NzggMC4yMDAxLTAuMDcxNyAwLjQyNTYtMC4wNzE3IDAuNjc2NXYwLjE3OTNjMCAwLjIxMjEgMC4wMjg0IDAuNDA5MiAwLjA4NTEgMC41OTE0IDAuMDU5OCAwLjE3OTMgMC4xNDY0IDAuMzM2MSAwLjI1OTkgMC40NzA1czAuMjUwOSAwLjI0MDUgMC40MTIzIDAuMzE4MWMwLjE2MTMgMC4wNzQ3IDAuMzQ1IDAuMTEyIDAuNTUxMSAwLjExMiAwLjI1OTkgMCAwLjQ5MTQtMC4wNTIyIDAuNjk0NS0wLjE1NjggMC4yMDMxLTAuMTA0NSAwLjM3OTQtMC4yNTI0IDAuNTI4Ny0wLjQ0MzZsMC41NjkxIDAuNTUxMmMtMC4xMDQ2IDAuMTUyMy0wLjI0MDUgMC4yOTg3LTAuNDA3OCAwLjQzOTEtMC4xNjczIDAuMTM3NC0wLjM3MTkgMC4yNDk0LTAuNjEzOCAwLjMzNi0wLjIzOSAwLjA4NjYtMC41MTY4IDAuMTMtMC44MzM1IDAuMTN6bTQuMDEwMy00LjAxNDd2My45MjVoLTEuMDc5OXYtNC44NDgxaDEuMDMwNmwwLjA0OTMgMC45MjMxem0xLjQ4MzEtMC45NTQ0LTllLTMgMS4wMDM2Yy0wLjA2NTctMC4wMTE5LTAuMTM3NC0wLjAyMDktMC4yMTUxLTAuMDI2OC0wLjA3NDYtNmUtMyAtMC4xNDkzLTllLTMgLTAuMjI0LTllLTMgLTAuMTg1MiAwLTAuMzQ4IDAuMDI2OS0wLjQ4ODQgMC4wODA3LTAuMTQwNCAwLjA1MDctMC4yNTg0IDAuMTI1NC0wLjM1NCAwLjIyNC0wLjA5MjYgMC4wOTU2LTAuMTY0MyAwLjIxMjEtMC4yMTUgMC4zNDk1LTAuMDUwOCAwLjEzNzQtMC4wODA3IDAuMjkxMi0wLjA4OTYgMC40NjE1bC0wLjI0NjUgMC4wMTc5YzAtMC4zMDQ3IDAuMDI5OS0wLjU4NyAwLjA4OTYtMC44NDY4IDAuMDU5OC0wLjI1OTkgMC4xNDk0LTAuNDg4NCAwLjI2ODktMC42ODU2IDAuMTIyNC0wLjE5NzEgMC4yNzQ4LTAuMzUxIDAuNDU3LTAuNDYxNSAwLjE4NTItMC4xMTA1IDAuMzk4OC0wLjE2NTggMC42NDA3LTAuMTY1OCAwLjA2NTggMCAwLjEzNiA2ZS0zIDAuMjEwNiAwLjAxNzkgMC4wNzc3IDAuMDEyIDAuMTM2IDAuMDI1NCAwLjE3NDggMC4wNDA0em0zLjM5MTkgMy45MDcxdi0yLjMxMmMwLTAuMTczMy0wLjAzMTQtMC4zMjI2LTAuMDk0MS0wLjQ0ODEtMC4wNjI4LTAuMTI1NC0wLjE1ODMtMC4yMjI1LTAuMjg2OC0wLjI5MTItMC4xMjU0LTAuMDY4Ny0wLjI4MzgtMC4xMDMxLTAuNDc0OS0wLjEwMzEtMC4xNzYzIDAtMC4zMjg2IDAuMDI5OS0wLjQ1NzEgMC4wODk2LTAuMTI4NCAwLjA1OTgtMC4yMjg1IDAuMTQwNC0wLjMwMDIgMC4yNDJzLTAuMTA3NSAwLjIxNjYtMC4xMDc1IDAuMzQ1aC0xLjA3NTRjMC0wLjE5MTIgMC4wNDYzLTAuMzc2NCAwLjEzODktMC41NTU2czAuMjI3LTAuMzM5IDAuNDAzMy0wLjQ3OTRjMC4xNzYyLTAuMTQwNCAwLjM4NjgtMC4yNTA5IDAuNjMxOC0wLjMzMTYgMC4yNDQ5LTAuMDgwNyAwLjUxOTctMC4xMjEgMC44MjQ0LTAuMTIxIDAuMzY0NCAwIDAuNjg3IDAuMDYxMyAwLjk2NzggMC4xODM3IDAuMjgzOCAwLjEyMjUgMC41MDY0IDAuMzA3NyAwLjY2NzcgMC41NTU2IDAuMTY0MyAwLjI0NSAwLjI0NjQgMC41NTI3IDAuMjQ2NCAwLjkyMzF2Mi4xNTUyYzAgMC4yMjEgMC4wMTQ5IDAuNDE5NyAwLjA0NDggMC41OTU5IDAuMDMyOSAwLjE3MzMgMC4wNzkyIDAuMzI0MSAwLjEzODkgMC40NTI2djAuMDcxNmgtMS4xMDY3Yy0wLjA1MDgtMC4xMTY0LTAuMDkxMS0wLjI2NDMtMC4xMjEtMC40NDM1LTAuMDI2OS0wLjE4MjMtMC4wNDAzLTAuMzU4NS0wLjA0MDMtMC41Mjg4em0wLjE1NjgtMS45NzYgOWUtMyAwLjY2NzdoLTAuNzc1MmMtMC4yMDAxIDAtMC4zNzY0IDAuMDE5NC0wLjUyODcgMC4wNTgyLTAuMTUyNCAwLjAzNTktMC4yNzkzIDAuMDg5Ni0wLjM4MDkgMC4xNjEzLTAuMTAxNSAwLjA3MTctMC4xNzc3IDAuMTU4My0wLjIyODUgMC4yNTk5cy0wLjA3NjIgMC4yMTY2LTAuMDc2MiAwLjM0NWMwIDAuMTI4NSAwLjAyOTkgMC4yNDY1IDAuMDg5NiAwLjM1NCAwLjA1OTggMC4xMDQ1IDAuMTQ2NCAwLjE4NjcgMC4yNTk5IDAuMjQ2NCAwLjExNjUgMC4wNTk4IDAuMjU2OSAwLjA4OTYgMC40MjEyIDAuMDg5NiAwLjIyMTEgMCAwLjQxMzctMC4wNDQ4IDAuNTc4LTAuMTM0NCAwLjE2NzMtMC4wOTI2IDAuMjk4Ny0wLjIwNDYgMC4zOTQzLTAuMzM2IDAuMDk1Ni0wLjEzNDQgMC4xNDY0LTAuMjYxNCAwLjE1MjQtMC4zODA5bDAuMzQ5NSAwLjQ3OTVjLTAuMDM1OSAwLjEyMjQtMC4wOTcxIDAuMjUzOS0wLjE4MzggMC4zOTQzLTAuMDg2NiAwLjE0MDMtMC4yMDAxIDAuMjc0OC0wLjM0MDUgMC40MDMyLTAuMTM3NCAwLjEyNTUtMC4zMDMyIDAuMjI4NS0wLjQ5NzMgMC4zMDkyLTAuMTkxMiAwLjA4MDYtMC40MTIzIDAuMTIxLTAuNjYzMiAwLjEyMS0wLjMxNjYgMC0wLjU5ODktMC4wNjI4LTAuODQ2OC0wLjE4ODItMC4yNDgtMC4xMjg1LTAuNDQyMS0wLjMwMDItMC41ODI1LTAuNTE1My0wLjE0MDQtMC4yMTgxLTAuMjEwNi0wLjQ2NDUtMC4yMTA2LTAuNzM5MyAwLTAuMjU2OSAwLjA0NzgtMC40ODM5IDAuMTQzNC0wLjY4MTEgMC4wOTg1LTAuMjAwMSAwLjI0MTktMC4zNjc0IDAuNDMwMS0wLjUwMTggMC4xOTEyLTAuMTM0NCAwLjQyNDItMC4yMzYgMC42OTktMC4zMDQ3IDAuMjc0OC0wLjA3MTcgMC41ODg1LTAuMTA3NiAwLjk0MDktMC4xMDc2aDAuODQ2OXptNC40MjI0LTEuODk5OHYwLjc4ODZoLTIuNzMzMnYtMC43ODg2aDIuNzMzMnptLTEuOTQ0Ni0xLjE4NzRoMS4wNzk5djQuNjk1OGMwIDAuMTQ5NCAwLjAyMDkgMC4yNjQ0IDAuMDYyNyAwLjM0NSAwLjA0NDggMC4wNzc3IDAuMTA2IDAuMTMgMC4xODM3IDAuMTU2OSAwLjA3NzcgMC4wMjY4IDAuMTY4OCAwLjA0MDMgMC4yNzMzIDAuMDQwMyAwLjA3NDcgMCAwLjE0NjQtMC4wMDQ1IDAuMjE1MS0wLjAxMzUgMC4wNjg3LTAuMDA4OSAwLjEyNC0wLjAxNzkgMC4xNjU4LTAuMDI2OGwwLjAwNDUgMC44MjQ0Yy0wLjA4OTYgMC4wMjY5LTAuMTk0MiAwLjA1MDgtMC4zMTM3IDAuMDcxNy0wLjExNjUgMC4wMjA5LTAuMjUwOSAwLjAzMTQtMC40MDMyIDAuMDMxNC0wLjI0OCAwLTAuNDY3NS0wLjA0MzQtMC42NTg3LTAuMTMtMC4xOTEyLTAuMDg5Ni0wLjM0MDUtMC4yMzQ1LTAuNDQ4MS0wLjQzNDYtMC4xMDc1LTAuMjAwMS0wLjE2MTMtMC40NjYtMC4xNjEzLTAuNzk3NnYtNC43NjN6bTUuODM4NCA0Ljg5M3YtMy43MDU2aDEuMDg0M3Y0Ljg0ODFoLTEuMDIxNmwtMC4wNjI3LTEuMTQyNXptMC4xNTIzLTEuMDA4MiAwLjM2My0wLjAwODljMCAwLjMyNTUtMC4wMzU5IDAuNjI1OC0wLjEwNzYgMC45MDA2LTAuMDcxNyAwLjI3MTgtMC4xODIyIDAuNTA5My0wLjMzMTYgMC43MTI0LTAuMTQ5MyAwLjIwMDEtMC4zNDA1IDAuMzU3LTAuNTczNSAwLjQ3MDUtMC4yMzMgMC4xMTA1LTAuNTEyMyAwLjE2NTgtMC44Mzc5IDAuMTY1OC0wLjIzNiAwLTAuNDUyNS0wLjAzNDQtMC42NDk3LTAuMTAzMS0wLjE5NzEtMC4wNjg3LTAuMzY3NC0wLjE3NDctMC41MTA4LTAuMzE4MS0wLjE0MDQtMC4xNDM0LTAuMjQ5NC0wLjMzMDEtMC4zMjcxLTAuNTYwMS0wLjA3NzYtMC4yMy0wLjExNjUtMC41MDQ4LTAuMTE2NS0wLjgyNDV2LTMuMTMyaDEuMDc5OXYzLjE0MWMwIDAuMTc2MiAwLjAyMDkgMC4zMjQxIDAuMDYyNyAwLjQ0MzYgMC4wNDE4IDAuMTE2NSAwLjA5ODYgMC4yMTA2IDAuMTcwMyAwLjI4MjNzMC4xNTUzIDAuMTIyNCAwLjI1MDkgMC4xNTIzIDAuMTk3MSAwLjA0NDggMC4zMDQ3IDAuMDQ0OGMwLjMwNzcgMCAwLjU0OTYtMC4wNTk3IDAuNzI1OS0wLjE3OTIgMC4xNzkyLTAuMTIyNSAwLjMwNjEtMC4yODY4IDAuMzgwOC0wLjQ5MjkgMC4wNzc3LTAuMjA2MSAwLjExNjUtMC40Mzc2IDAuMTE2NS0wLjY5NDV6bTMuMjY2NC0xLjc3NDN2My45MjVoLTEuMDc5OHYtNC44NDgxaDEuMDMwNmwwLjA0OTIgMC45MjMxem0xLjQ4MzItMC45NTQ0LTllLTMgMS4wMDM2Yy0wLjA2NTctMC4wMTE5LTAuMTM3NC0wLjAyMDktMC4yMTUxLTAuMDI2OC0wLjA3NDctNmUtMyAtMC4xNDkzLTllLTMgLTAuMjI0LTllLTMgLTAuMTg1MiAwLTAuMzQ4IDAuMDI2OS0wLjQ4ODQgMC4wODA3LTAuMTQwNCAwLjA1MDctMC4yNTg0IDAuMTI1NC0wLjM1NCAwLjIyNC0wLjA5MjYgMC4wOTU2LTAuMTY0MyAwLjIxMjEtMC4yMTUxIDAuMzQ5NS0wLjA1MDcgMC4xMzc0LTAuMDgwNiAwLjI5MTItMC4wODk2IDAuNDYxNWwtMC4yNDY0IDAuMDE3OWMwLTAuMzA0NyAwLjAyOTktMC41ODcgMC4wODk2LTAuODQ2OCAwLjA1OTctMC4yNTk5IDAuMTQ5NC0wLjQ4ODQgMC4yNjg4LTAuNjg1NiAwLjEyMjUtMC4xOTcxIDAuMjc0OS0wLjM1MSAwLjQ1NzEtMC40NjE1IDAuMTg1Mi0wLjExMDUgMC4zOTg4LTAuMTY1OCAwLjY0MDctMC4xNjU4IDAuMDY1NyAwIDAuMTM1OSA2ZS0zIDAuMjEwNiAwLjAxNzkgMC4wNzc3IDAuMDEyIDAuMTM1OSAwLjAyNTQgMC4xNzQ4IDAuMDQwNHptMi44Njc2IDQuOTY5MWMtMC4zNTg1IDAtMC42ODI2LTAuMDU4My0wLjk3MjMtMC4xNzQ4LTAuMjg2OC0wLjExOTUtMC41MzE3LTAuMjg1My0wLjczNDgtMC40OTczLTAuMjAwMi0wLjIxMjEtMC4zNTQtMC40NjE2LTAuNDYxNi0wLjc0ODMtMC4xMDc1LTAuMjg2OC0wLjE2MTMtMC41OTYtMC4xNjEzLTAuOTI3NXYtMC4xNzkzYzAtMC4zNzkzIDAuMDU1My0wLjcyMjggMC4xNjU4LTEuMDMwNSAwLjExMDYtMC4zMDc3IDAuMjY0NC0wLjU3MDYgMC40NjE1LTAuNzg4NiAwLjE5NzItMC4yMjExIDAuNDMwMi0wLjM4OTggMC42OTktMC41MDYzIDAuMjY4OS0wLjExNjUgMC41NjAxLTAuMTc0OCAwLjg3MzgtMC4xNzQ4IDAuMzQ2NSAwIDAuNjQ5NyAwLjA1ODMgMC45MDk1IDAuMTc0OCAwLjI1OTkgMC4xMTY1IDAuNDc1IDAuMjgwOCAwLjY0NTMgMC40OTI4IDAuMTcyOSAwLjIwOTEgMC4zMDE5IDAuNDU4NiAwLjM4NDkgMC43NDgzIDAuMDg3IDAuMjg5OCAwLjEzIDAuNjA5NCAwLjEzIDAuOTU4OXYwLjQ2MTVoLTMuNzQ1NXYtMC43NzUyaDIuNjc5NHYtMC4wODUxYy0wLjAwNTktMC4xOTQyLTAuMDQ0OC0wLjM3NjQtMC4xMTY1LTAuNTQ2Ni0wLjA2ODctMC4xNzAzLTAuMTc0Ny0wLjMwNzctMC4zMTgxLTAuNDEyMy0wLjE0MzQtMC4xMDQ1LTAuMzM0NS0wLjE1NjgtMC41NzM1LTAuMTU2OC0wLjE3OTIgMC0wLjMzOTEgMC4wMzg4LTAuNDc5NSAwLjExNjUtMC4xMzc0IDAuMDc0Ny0wLjI1MjQgMC4xODM3LTAuMzQ1IDAuMzI3MXMtMC4xNjQzIDAuMzE2Ni0wLjIxNSAwLjUxOThjLTAuMDQ3OCAwLjIwMDEtMC4wNzE3IDAuNDI1Ni0wLjA3MTcgMC42NzY1djAuMTc5M2MwIDAuMjEyMSAwLjAyODMgMC40MDkyIDAuMDg1MSAwLjU5MTQgMC4wNTk3IDAuMTc5MyAwLjE0NjQgMC4zMzYxIDAuMjU5OSAwLjQ3MDVzMC4yNTA5IDAuMjQwNSAwLjQxMjIgMC4zMTgxYzAuMTYxMyAwLjA3NDcgMC4zNDUgMC4xMTIgMC41NTExIDAuMTEyIDAuMjU5OSAwIDAuNDkxNC0wLjA1MjIgMC42OTQ1LTAuMTU2OCAwLjIwMzItMC4xMDQ1IDAuMzc5NC0wLjI1MjQgMC41Mjg4LTAuNDQzNmwwLjU2ODggMC41NTEyYy0wLjEwNCAwLjE1MjMtMC4yNCAwLjI5ODctMC40MDc1IDAuNDM5MS0wLjE2NzMgMC4xMzc0LTAuMzcxOSAwLjI0OTQtMC42MTM5IDAuMzM2LTAuMjM5IDAuMDg2Ni0wLjUxNjggMC4xMy0wLjgzMzQgMC4xM3oiIGZpbGwtb3BhY2l0eT0iLjg3Ii8+CiAgIDxwYXRoIGQ9Im01MC4zNTYgMzYuNTk2djAuNjY4N2gtMi40NTY2di0wLjY2ODdoMi40NTY2em0tMi4yMjEzLTQuMjI0MnY0Ljg5MjloLTAuODQzNXYtNC44OTI5aDAuODQzNXptNC45ODU5IDQuMTYzN3YtMS43MzRjMC0wLjEzLTAuMDIzNi0wLjI0Mi0wLjA3MDYtMC4zMzYxLTAuMDQ3MS0wLjA5NDEtMC4xMTg3LTAuMTY2OS0wLjIxNTEtMC4yMTg0LTAuMDk0MS0wLjA1MTUtMC4yMTI4LTAuMDc3My0wLjM1NjItMC4wNzczLTAuMTMyMiAwLTAuMjQ2NCAwLjAyMjQtMC4zNDI4IDAuMDY3Mi0wLjA5NjMgMC4wNDQ4LTAuMTcxNCAwLjEwNTMtMC4yMjUxIDAuMTgxNS0wLjA1MzggMC4wNzYyLTAuMDgwNyAwLjE2MjQtMC4wODA3IDAuMjU4N2gtMC44MDY1YzAtMC4xNDMzIDAuMDM0Ny0wLjI4MjIgMC4xMDQyLTAuNDE2NyAwLjA2OTQtMC4xMzQ0IDAuMTcwMi0wLjI1NDIgMC4zMDI0LTAuMzU5NXMwLjI5MDEtMC4xODgyIDAuNDczOS0wLjI0ODdjMC4xODM3LTAuMDYwNSAwLjM4OTgtMC4wOTA3IDAuNjE4My0wLjA5MDcgMC4yNzMzIDAgMC41MTUzIDAuMDQ1OSAwLjcyNTkgMC4xMzc3IDAuMjEyOCAwLjA5MTkgMC4zNzk3IDAuMjMwOCAwLjUwMDcgMC40MTY3IDAuMTIzMiAwLjE4MzcgMC4xODQ4IDAuNDE0NSAwLjE4NDggMC42OTIzdjEuNjE2NGMwIDAuMTY1OCAwLjAxMTIgMC4zMTQ4IDAuMDMzNiAwLjQ0NyAwLjAyNDcgMC4xMjk5IDAuMDU5NCAwLjI0MyAwLjEwNDIgMC4zMzk0djAuMDUzN2gtMC44MzAxYy0wLjAzOC0wLjA4NzMtMC4wNjgzLTAuMTk4Mi0wLjA5MDctMC4zMzI2LTAuMDIwMi0wLjEzNjctMC4wMzAyLTAuMjY4OS0wLjAzMDItMC4zOTY2em0wLjExNzYtMS40ODIgMC4wMDY3IDAuNTAwN2gtMC41ODE0Yy0wLjE1MDEgMC0wLjI4MjMgMC4wMTQ2LTAuMzk2NSAwLjA0MzctMC4xMTQzIDAuMDI2OS0wLjIwOTUgMC4wNjcyLTAuMjg1NyAwLjEyMS0wLjA3NjEgMC4wNTM4LTAuMTMzMyAwLjExODctMC4xNzEzIDAuMTk0OS0wLjAzODEgMC4wNzYyLTAuMDU3MiAwLjE2MjQtMC4wNTcyIDAuMjU4OCAwIDAuMDk2MyAwLjAyMjQgMC4xODQ4IDAuMDY3MiAwLjI2NTUgMC4wNDQ4IDAuMDc4NCAwLjEwOTggMC4xNCAwLjE5NDkgMC4xODQ4IDAuMDg3NCAwLjA0NDggMC4xOTI3IDAuMDY3MiAwLjMxNTkgMC4wNjcyIDAuMTY1OCAwIDAuMzEwMy0wLjAzMzYgMC40MzM1LTAuMTAwOCAwLjEyNTUtMC4wNjk1IDAuMjI0MS0wLjE1MzUgMC4yOTU4LTAuMjUyMSAwLjA3MTctMC4xMDA4IDAuMTA5Ny0wLjE5NiAwLjExNDItMC4yODU2bDAuMjYyMiAwLjM1OTZjLTAuMDI2OSAwLjA5MTgtMC4wNzI5IDAuMTkwNC0wLjEzNzggMC4yOTU3LTAuMDY1IDAuMTA1My0wLjE1MDEgMC4yMDYxLTAuMjU1NCAwLjMwMjQtMC4xMDMxIDAuMDk0MS0wLjIyNzQgMC4xNzE0LTAuMzczIDAuMjMxOS0wLjE0MzQgMC4wNjA1LTAuMzA5MiAwLjA5MDgtMC40OTc0IDAuMDkwOC0wLjIzNzUgMC0wLjQ0OTItMC4wNDcxLTAuNjM1MS0wLjE0MTItMC4xODYtMC4wOTYzLTAuMzMxNi0wLjIyNTEtMC40MzY5LTAuMzg2NC0wLjEwNTMtMC4xNjM2LTAuMTU4LTAuMzQ4NC0wLjE1OC0wLjU1NDUgMC0wLjE5MjcgMC4wMzU5LTAuMzYzIDAuMTA3Ni0wLjUxMDggMC4wNzM5LTAuMTUwMSAwLjE4MTQtMC4yNzU2IDAuMzIyNi0wLjM3NjQgMC4xNDM0LTAuMTAwOCAwLjMxODEtMC4xNzcgMC41MjQyLTAuMjI4NSAwLjIwNjEtMC4wNTM4IDAuNDQxNC0wLjA4MDcgMC43MDU3LTAuMDgwN2gwLjYzNTJ6bTMuNzI1NyAxLjIyNjZjMC0wLjA4MDYtMC4wMjAyLTAuMTUzNC0wLjA2MDUtMC4yMTg0LTAuMDQwMy0wLjA2NzItMC4xMTc2LTAuMTI3Ny0wLjIzMTktMC4xODE1LTAuMTEyLTAuMDUzOC0wLjI3NzgtMC4xMDMtMC40OTczLTAuMTQ3OS0wLjE5MjctMC4wNDI1LTAuMzY5Ny0wLjA5MjktMC41MzEtMC4xNTEyLTAuMTU5MS0wLjA2MDUtMC4yOTU3LTAuMTMzMy0wLjQxLTAuMjE4NC0wLjExNDItMC4wODUxLTAuMjAyNy0wLjE4Ni0wLjI2NTUtMC4zMDI1LTAuMDYyNy0wLjExNjUtMC4wOTQxLTAuMjUwOS0wLjA5NDEtMC40MDMyIDAtMC4xNDc5IDAuMDMyNS0wLjI4NzkgMC4wOTc1LTAuNDIwMXMwLjE1NzktMC4yNDg3IDAuMjc4OS0wLjM0OTUgMC4yNjc3LTAuMTgwMyAwLjQ0MDItMC4yMzg2YzAuMTc0OC0wLjA1ODIgMC4zNjk3LTAuMDg3MyAwLjU4NDgtMC4wODczIDAuMzA0NyAwIDAuNTY1NyAwLjA1MTUgMC43ODMgMC4xNTQ1IDAuMjE5NSAwLjEwMDkgMC4zODc2IDAuMjM4NiAwLjUwNDEgMC40MTM0IDAuMTE2NSAwLjE3MjUgMC4xNzQ3IDAuMzY3NCAwLjE3NDcgMC41ODQ3aC0wLjgwOTljMC0wLjA5NjMtMC4wMjQ2LTAuMTg1OS0wLjA3MzktMC4yNjg4LTAuMDQ3MS0wLjA4NTItMC4xMTg4LTAuMTUzNS0wLjIxNTEtMC4yMDUtMC4wOTYzLTAuMDUzOC0wLjIxNzMtMC4wODA3LTAuMzYyOS0wLjA4MDctMC4xMzg5IDAtMC4yNTQzIDAuMDIyNC0wLjM0NjIgMC4wNjcyLTAuMDg5NiAwLjA0MjYtMC4xNTY4IDAuMDk4Ni0wLjIwMTYgMC4xNjgxLTAuMDQyNiAwLjA2OTQtMC4wNjM4IDAuMTQ1Ni0wLjA2MzggMC4yMjg1IDAgMC4wNjA1IDAuMDExMiAwLjExNTQgMC4wMzM2IDAuMTY0NiAwLjAyNDYgMC4wNDcxIDAuMDY0OSAwLjA5MDggMC4xMjA5IDAuMTMxMSAwLjA1NjEgMC4wMzgxIDAuMTMyMiAwLjA3MzkgMC4yMjg2IDAuMTA3NSAwLjA5ODUgMC4wMzM2IDAuMjIxOCAwLjA2NjEgMC4zNjk2IDAuMDk3NSAwLjI3NzggMC4wNTgyIDAuNTE2NCAwLjEzMzMgMC43MTU4IDAuMjI1MSAwLjIwMTYgMC4wODk3IDAuMzU2MiAwLjIwNjIgMC40NjM4IDAuMzQ5NSAwLjEwNzUgMC4xNDEyIDAuMTYxMyAwLjMyMDQgMC4xNjEzIDAuNTM3NyAwIDAuMTYxMy0wLjAzNDggMC4zMDkyLTAuMTA0MiAwLjQ0MzYtMC4wNjcyIDAuMTMyMi0wLjE2NTggMC4yNDc2LTAuMjk1NyAwLjM0NjItMC4xMyAwLjA5NjMtMC4yODU3IDAuMTcxMy0wLjQ2NzIgMC4yMjUxLTAuMTc5MiAwLjA1MzgtMC4zODA4IDAuMDgwNy0wLjYwNDggMC4wODA3LTAuMzI5NCAwLTAuNjA4My0wLjA1ODMtMC44MzY4LTAuMTc0OC0wLjIyODUtMC4xMTg3LTAuNDAyMi0wLjI3LTAuNTIwOS0wLjQ1MzctMC4xMTY1LTAuMTg1OS0wLjE3NDctMC4zNzg2LTAuMTc0Ny0wLjU3OGgwLjc4M2MwLjAwODkgMC4xNTAxIDAuMDUwNCAwLjI3IDAuMTI0MyAwLjM1OTYgMC4wNzYyIDAuMDg3NCAwLjE3MDMgMC4xNTEyIDAuMjgyMyAwLjE5MTYgMC4xMTQyIDAuMDM4IDAuMjMxOSAwLjA1NzEgMC4zNTI4IDAuMDU3MSAwLjE0NTcgMCAwLjI2NzgtMC4wMTkxIDAuMzY2My0wLjA1NzEgMC4wOTg2LTAuMDQwNCAwLjE3MzctMC4wOTQxIDAuMjI1Mi0wLjE2MTMgMC4wNTE1LTAuMDY5NSAwLjA3NzMtMC4xNDc5IDAuMDc3My0wLjIzNTN6bTMuMzEyMy0yLjY1MTR2MC41OTE0aC0yLjA0OTl2LTAuNTkxNGgyLjA0OTl6bS0xLjQ1ODQtMC44OTA2aDAuODA5OXYzLjUyMTljMCAwLjExMiAwLjAxNTYgMC4xOTgyIDAuMDQ3IDAuMjU4NyAwLjAzMzYgMC4wNTgzIDAuMDc5NSAwLjA5NzUgMC4xMzc4IDAuMTE3NiAwLjA1ODIgMC4wMjAyIDAuMTI2NiAwLjAzMDMgMC4yMDUgMC4wMzAzIDAuMDU2IDAgMC4xMDk4LTAuMDAzNCAwLjE2MTMtMC4wMTAxczAuMDkzLTAuMDEzNCAwLjEyNDMtMC4wMjAybDAuMDAzNCAwLjYxODRjLTAuMDY3MiAwLjAyMDEtMC4xNDU2IDAuMDM4MS0wLjIzNTMgMC4wNTM3LTAuMDg3MyAwLjAxNTctMC4xODgxIDAuMDIzNi0wLjMwMjQgMC4wMjM2LTAuMTg2IDAtMC4zNTA2LTAuMDMyNS0wLjQ5NC0wLjA5NzUtMC4xNDM0LTAuMDY3Mi0wLjI1NTQtMC4xNzU5LTAuMzM2MS0wLjMyNi0wLjA4MDYtMC4xNTAxLTAuMTIwOS0wLjM0OTUtMC4xMjA5LTAuNTk4MXYtMy41NzIzem02LjI3MTggMy42Njk3di0yLjc3OTFoMC44MTMzdjMuNjM2aC0wLjc2NjJsLTAuMDQ3MS0wLjg1Njl6bTAuMTE0My0wLjc1NjEgMC4yNzIyLTAuMDA2N2MwIDAuMjQ0Mi0wLjAyNjkgMC40NjkzLTAuMDgwNyAwLjY3NTQtMC4wNTM3IDAuMjAzOS0wLjEzNjYgMC4zODItMC4yNDg2IDAuNTM0NC0wLjExMjEgMC4xNTAxLTAuMjU1NCAwLjI2NzctMC40MzAyIDAuMzUyOC0wLjE3NDcgMC4wODI5LTAuMzg0MiAwLjEyNDQtMC42Mjg0IDAuMTI0NC0wLjE3NyAwLTAuMzM5NC0wLjAyNTgtMC40ODczLTAuMDc3My0wLjE0NzgtMC4wNTE2LTAuMjc1NS0wLjEzMTEtMC4zODMxLTAuMjM4Ni0wLjEwNTMtMC4xMDc2LTAuMTg3MS0wLjI0NzYtMC4yNDUzLTAuNDIwMS0wLjA1ODMtMC4xNzI1LTAuMDg3NC0wLjM3ODYtMC4wODc0LTAuNjE4M3YtMi4zNDloMC44MDk5djIuMzU1N2MwIDAuMTMyMiAwLjAxNTcgMC4yNDMxIDAuMDQ3MSAwLjMzMjcgMC4wMzEzIDAuMDg3NCAwLjA3MzkgMC4xNTc5IDAuMTI3NyAwLjIxMTcgMC4wNTM3IDAuMDUzOCAwLjExNjUgMC4wOTE4IDAuMTg4MSAwLjExNDMgMC4wNzE3IDAuMDIyNCAwLjE0NzkgMC4wMzM2IDAuMjI4NiAwLjAzMzYgMC4yMzA3IDAgMC40MTIyLTAuMDQ0OSAwLjU0NDQtMC4xMzQ1IDAuMTM0NC0wLjA5MTggMC4yMjk2LTAuMjE1IDAuMjg1Ni0wLjM2OTYgMC4wNTgzLTAuMTU0NiAwLjA4NzQtMC4zMjgyIDAuMDg3NC0wLjUyMDl6bTIuNDg1Ny0xLjMyNHY0LjMzNWgtMC44MDk5di01LjAzNGgwLjc0NmwwLjA2MzkgMC42OTl6bTIuMzY5MSAxLjA4NTR2MC4wNzA2YzAgMC4yNjQzLTAuMDMxMyAwLjUwOTctMC4wOTQxIDAuNzM1OS0wLjA2MDUgMC4yMjQxLTAuMTUxMiAwLjQyMDEtMC4yNzIyIDAuNTg4MS0wLjExODcgMC4xNjU4LTAuMjY1NSAwLjI5NDYtMC40NDAyIDAuMzg2NS0wLjE3NDggMC4wOTE4LTAuMzc2NCAwLjEzNzgtMC42MDQ5IDAuMTM3OC0wLjIyNjMgMC0wLjQyNDUtMC4wNDE1LTAuNTk0OC0wLjEyNDQtMC4xNjgtMC4wODUxLTAuMzEwMy0wLjIwNS0wLjQyNjgtMC4zNTk2LTAuMTE2NS0wLjE1NDUtMC4yMTA2LTAuMzM2LTAuMjgyMy0wLjU0NDQtMC4wNjk0LTAuMjEwNi0wLjExODctMC40NDEzLTAuMTQ3OC0wLjY5MjJ2LTAuMjcyMmMwLjAyOTEtMC4yNjY2IDAuMDc4NC0wLjUwODYgMC4xNDc4LTAuNzI1OSAwLjA3MTctMC4yMTczIDAuMTY1OC0wLjQwNDQgMC4yODIzLTAuNTYxMnMwLjI1ODgtMC4yNzc4IDAuNDI2OC0wLjM2MjljMC4xNjgtMC4wODUyIDAuMzY0LTAuMTI3NyAwLjU4ODEtMC4xMjc3IDAuMjI4NSAwIDAuNDMxMiAwLjA0NDggMC42MDgyIDAuMTM0NCAwLjE3NyAwLjA4NzMgMC4zMjYgMC4yMTI4IDAuNDQ3IDAuMzc2NCAwLjEyMSAwLjE2MTMgMC4yMTE3IDAuMzU2MiAwLjI3MjIgMC41ODQ3IDAuMDYwNSAwLjIyNjMgMC4wOTA3IDAuNDc4MyAwLjA5MDcgMC43NTYxem0tMC44MDk5IDAuMDcwNnYtMC4wNzA2YzAtMC4xNjgtMC4wMTU2LTAuMzIzNy0wLjA0Ny0wLjQ2NzEtMC4wMzE0LTAuMTQ1Ni0wLjA4MDctMC4yNzMzLTAuMTQ3OS0wLjM4MzFzLTAuMTUzNC0wLjE5NDktMC4yNTg3LTAuMjU1NGMtMC4xMDMxLTAuMDYyNy0wLjIyNzQtMC4wOTQxLTAuMzczMS0wLjA5NDEtMC4xNDMzIDAtMC4yNjY2IDAuMDI0Ni0wLjM2OTYgMC4wNzM5LTAuMTAzMSAwLjA0NzEtMC4xODkzIDAuMTEzMi0wLjI1ODggMC4xOTgzLTAuMDY5NCAwLjA4NTEtMC4xMjMyIDAuMTg0OC0wLjE2MTMgMC4yOTkxLTAuMDM4MSAwLjExMi0wLjA2NDkgMC4yMzQxLTAuMDgwNiAwLjM2NjN2MC42NTE5YzAuMDI2OSAwLjE2MTMgMC4wNzI4IDAuMzA5MiAwLjEzNzggMC40NDM2IDAuMDY0OSAwLjEzNDQgMC4xNTY4IDAuMjQyIDAuMjc1NSAwLjMyMjYgMC4xMjEgMC4wNzg0IDAuMjc1NiAwLjExNzYgMC40NjM4IDAuMTE3NiAwLjE0NTYgMCAwLjI2OTktMC4wMzEzIDAuMzczLTAuMDk0MSAwLjEwMy0wLjA2MjcgMC4xODcxLTAuMTQ4OSAwLjI1Mi0wLjI1ODcgMC4wNjcyLTAuMTEyIDAuMTE2NS0wLjI0MDkgMC4xNDc5LTAuMzg2NXMwLjA0Ny0wLjMwMDIgMC4wNDctMC40NjM3em0zLjg2MDIgMS4wMjgzdi00LjQwOWgwLjgxMzJ2NS4xNjE3aC0wLjczNTlsLTAuMDc3My0wLjc1Mjd6bS0yLjM2NTktMS4wMjV2LTAuMDcwNWMwLTAuMjc1NiAwLjAzMjUtMC41MjY1IDAuMDk3NS0wLjc1MjggMC4wNjUtMC4yMjg1IDAuMTU5MS0wLjQyNDUgMC4yODIzLTAuNTg4MSAwLjEyMzItMC4xNjU4IDAuMjczMy0wLjI5MjQgMC40NTAzLTAuMzc5NyAwLjE3Ny0wLjA4OTYgMC4zNzY0LTAuMTM0NCAwLjU5ODItMC4xMzQ0IDAuMjE5NSAwIDAuNDEyMiAwLjA0MjUgMC41NzggMC4xMjc3IDAuMTY1OCAwLjA4NTEgMC4zMDY5IDAuMjA3MiAwLjQyMzQgMC4zNjYyIDAuMTE2NSAwLjE1NjkgMC4yMDk1IDAuMzQ1MSAwLjI3ODkgMC41NjQ2IDAuMDY5NSAwLjIxNzMgMC4xMTg4IDAuNDU5MyAwLjE0NzkgMC43MjU5djAuMjI1MWMtMC4wMjkxIDAuMjU5OS0wLjA3ODQgMC40OTc0LTAuMTQ3OSAwLjcxMjUtMC4wNjk0IDAuMjE1LTAuMTYyNCAwLjQwMS0wLjI3ODkgMC41NTc4cy0wLjI1ODggMC4yNzc4LTAuNDI2OCAwLjM2M2MtMC4xNjU4IDAuMDg1MS0wLjM1OTYgMC4xMjc3LTAuNTgxMyAwLjEyNzctMC4yMTk2IDAtMC40MTc5LTAuMDQ2LTAuNTk0OS0wLjEzNzgtMC4xNzQ3LTAuMDkxOS0wLjMyMzctMC4yMjA3LTAuNDQ2OS0wLjM4NjVzLTAuMjE3My0wLjM2MDctMC4yODIzLTAuNTg0N2MtMC4wNjUtMC4yMjYzLTAuMDk3NS0wLjQ3MTYtMC4wOTc1LTAuNzM2em0wLjgwOTktMC4wNzA1djAuMDcwNWMwIDAuMTY1OCAwLjAxNDYgMC4zMjA0IDAuMDQzNyAwLjQ2MzggMC4wMzE0IDAuMTQzNCAwLjA3OTYgMC4yNjk5IDAuMTQ0NSAwLjM3OTcgMC4wNjUgMC4xMDc2IDAuMTQ5IDAuMTkyNyAwLjI1MjEgMC4yNTU0IDAuMTA1MyAwLjA2MDUgMC4yMzA3IDAuMDkwOCAwLjM3NjMgMC4wOTA4IDAuMTgzOCAwIDAuMzM1LTAuMDQwNCAwLjQ1MzctMC4xMjEgMC4xMTg4LTAuMDgwNyAwLjIxMTctMC4xODkzIDAuMjc4OS0wLjMyNiAwLjA2OTUtMC4xMzg5IDAuMTE2NS0wLjI5MzUgMC4xNDEyLTAuNDYzN3YtMC42MDgzYy0wLjAxMzUtMC4xMzIyLTAuMDQxNS0wLjI1NTQtMC4wODQtMC4zNjk3LTAuMDQwNC0wLjExNDItMC4wOTUyLTAuMjEzOS0wLjE2NDctMC4yOTktMC4wNjk1LTAuMDg3NC0wLjE1NTctMC4xNTQ2LTAuMjU4OC0wLjIwMTctMC4xMDA4LTAuMDQ5My0wLjIyMDYtMC4wNzM5LTAuMzU5NS0wLjA3MzktMC4xNDc5IDAtMC4yNzM0IDAuMDMxNC0wLjM3NjQgMC4wOTQxLTAuMTAzMSAwLjA2MjctMC4xODgyIDAuMTQ5LTAuMjU1NCAwLjI1ODctMC4wNjUgMC4xMDk4LTAuMTEzMiAwLjIzNzUtMC4xNDQ1IDAuMzgzMS0wLjAzMTQgMC4xNDU3LTAuMDQ3MSAwLjMwMTQtMC4wNDcxIDAuNDY3MnptNS40MDk0IDEuMTE5di0xLjczNGMwLTAuMTMtMC4wMjM2LTAuMjQyLTAuMDcwNi0wLjMzNjEtMC4wNDcxLTAuMDk0MS0wLjExODgtMC4xNjY5LTAuMjE1MS0wLjIxODQtMC4wOTQxLTAuMDUxNS0wLjIxMjgtMC4wNzczLTAuMzU2Mi0wLjA3NzMtMC4xMzIyIDAtMC4yNDY0IDAuMDIyNC0wLjM0MjggMC4wNjcyLTAuMDk2MyAwLjA0NDgtMC4xNzE0IDAuMTA1My0wLjIyNTEgMC4xODE1LTAuMDUzOCAwLjA3NjItMC4wODA3IDAuMTYyNC0wLjA4MDcgMC4yNTg3aC0wLjgwNjVjMC0wLjE0MzMgMC4wMzQ3LTAuMjgyMiAwLjEwNDItMC40MTY3IDAuMDY5NC0wLjEzNDQgMC4xNzAyLTAuMjU0MiAwLjMwMjQtMC4zNTk1czAuMjkwMS0wLjE4ODIgMC40NzM4LTAuMjQ4N2MwLjE4MzgtMC4wNjA1IDAuMzg5OS0wLjA5MDcgMC42MTg0LTAuMDkwNyAwLjI3MzMgMCAwLjUxNTMgMC4wNDU5IDAuNzI1OSAwLjEzNzcgMC4yMTI4IDAuMDkxOSAwLjM3OTcgMC4yMzA4IDAuNTAwNyAwLjQxNjcgMC4xMjMyIDAuMTgzNyAwLjE4NDggMC40MTQ1IDAuMTg0OCAwLjY5MjN2MS42MTY0YzAgMC4xNjU4IDAuMDExMiAwLjMxNDggMC4wMzM2IDAuNDQ3IDAuMDI0NyAwLjEyOTkgMC4wNTk0IDAuMjQzIDAuMTA0MiAwLjMzOTR2MC4wNTM3aC0wLjgzMDFjLTAuMDM4LTAuMDg3My0wLjA2ODMtMC4xOTgyLTAuMDkwNy0wLjMzMjYtMC4wMjAyLTAuMTM2Ny0wLjAzMDItMC4yNjg5LTAuMDMwMi0wLjM5NjZ6bTAuMTE3Ni0xLjQ4MiAwLjAwNjcgMC41MDA3aC0wLjU4MTRjLTAuMTUwMSAwLTAuMjgyMyAwLjAxNDYtMC4zOTY1IDAuMDQzNy0wLjExNDMgMC4wMjY5LTAuMjA5NSAwLjA2NzItMC4yODU3IDAuMTIxLTAuMDc2MSAwLjA1MzgtMC4xMzMzIDAuMTE4Ny0wLjE3MTMgMC4xOTQ5LTAuMDM4MSAwLjA3NjItMC4wNTcyIDAuMTYyNC0wLjA1NzIgMC4yNTg4IDAgMC4wOTYzIDAuMDIyNCAwLjE4NDggMC4wNjcyIDAuMjY1NSAwLjA0NDggMC4wNzg0IDAuMTA5OCAwLjE0IDAuMTk0OSAwLjE4NDggMC4wODc0IDAuMDQ0OCAwLjE5MjcgMC4wNjcyIDAuMzE1OSAwLjA2NzIgMC4xNjU4IDAgMC4zMTAzLTAuMDMzNiAwLjQzMzUtMC4xMDA4IDAuMTI1NS0wLjA2OTUgMC4yMjQxLTAuMTUzNSAwLjI5NTgtMC4yNTIxIDAuMDcxNy0wLjEwMDggMC4xMDk3LTAuMTk2IDAuMTE0Mi0wLjI4NTZsMC4yNjIxIDAuMzU5NmMtMC4wMjY4IDAuMDkxOC0wLjA3MjggMC4xOTA0LTAuMTM3NyAwLjI5NTctMC4wNjUgMC4xMDUzLTAuMTUwMSAwLjIwNjEtMC4yNTU0IDAuMzAyNC0wLjEwMzEgMC4wOTQxLTAuMjI3NCAwLjE3MTQtMC4zNzMxIDAuMjMxOS0wLjE0MzMgMC4wNjA1LTAuMzA5MSAwLjA5MDgtMC40OTczIDAuMDkwOC0wLjIzNzUgMC0wLjQ0OTItMC4wNDcxLTAuNjM1MS0wLjE0MTItMC4xODYtMC4wOTYzLTAuMzMxNi0wLjIyNTEtMC40MzY5LTAuMzg2NC0wLjEwNTMtMC4xNjM2LTAuMTU4LTAuMzQ4NC0wLjE1OC0wLjU1NDUgMC0wLjE5MjcgMC4wMzU5LTAuMzYzIDAuMTA3Ni0wLjUxMDggMC4wNzM5LTAuMTUwMSAwLjE4MTQtMC4yNzU2IDAuMzIyNi0wLjM3NjQgMC4xNDM0LTAuMTAwOCAwLjMxODEtMC4xNzcgMC41MjQyLTAuMjI4NSAwLjIwNjEtMC4wNTM4IDAuNDQxNC0wLjA4MDcgMC43MDU3LTAuMDgwN2gwLjYzNTJ6bTMuMzUyNy0xLjQyNDh2MC41OTE0aC0yLjA1di0wLjU5MTRoMi4wNXptLTEuNDU4NS0wLjg5MDZoMC44MDk5djMuNTIxOWMwIDAuMTEyIDAuMDE1NyAwLjE5ODIgMC4wNDcgMC4yNTg3IDAuMDMzNiAwLjA1ODMgMC4wNzk2IDAuMDk3NSAwLjEzNzggMC4xMTc2IDAuMDU4MyAwLjAyMDIgMC4xMjY2IDAuMDMwMyAwLjIwNSAwLjAzMDMgMC4wNTYgMCAwLjEwOTgtMC4wMDM0IDAuMTYxMy0wLjAxMDFzMC4wOTMtMC4wMTM0IDAuMTI0My0wLjAyMDJsMC4wMDM0IDAuNjE4NGMtMC4wNjcyIDAuMDIwMS0wLjE0NTYgMC4wMzgxLTAuMjM1MiAwLjA1MzctMC4wODc0IDAuMDE1Ny0wLjE4ODIgMC4wMjM2LTAuMzAyNSAwLjAyMzYtMC4xODU5IDAtMC4zNTA2LTAuMDMyNS0wLjQ5NC0wLjA5NzUtMC4xNDM0LTAuMDY3Mi0wLjI1NTQtMC4xNzU5LTAuMzM2LTAuMzI2LTAuMDgwNy0wLjE1MDEtMC4xMjEtMC4zNDk1LTAuMTIxLTAuNTk4MXYtMy41NzIzem0zLjgyOTkgNC41OTM5Yy0wLjI2ODkgMC0wLjUxMi0wLjA0MzctMC43MjkzLTAuMTMxMS0wLjIxNS0wLjA4OTYtMC4zOTg3LTAuMjE0LTAuNTUxMS0wLjM3My0wLjE1MDEtMC4xNTkxLTAuMjY1NS0wLjM0NjItMC4zNDYxLTAuNTYxMi0wLjA4MDctMC4yMTUxLTAuMTIxLTAuNDQ3LTAuMTIxLTAuNjk1N3YtMC4xMzQ0YzAtMC4yODQ1IDAuMDQxNC0wLjU0MjEgMC4xMjQzLTAuNzcyOXMwLjE5ODMtMC40Mjc5IDAuMzQ2Mi0wLjU5MTRjMC4xNDc4LTAuMTY1OCAwLjMyMjYtMC4yOTI0IDAuNTI0Mi0wLjM3OThzMC40MjAxLTAuMTMxIDAuNjU1My0wLjEzMWMwLjI1OTkgMCAwLjQ4NzMgMC4wNDM2IDAuNjgyMiAwLjEzMXMwLjM1NjIgMC4yMTA2IDAuNDgzOSAwLjM2OTdjMC4xMyAwLjE1NjggMC4yMjYzIDAuMzQzOSAwLjI4OSAwLjU2MTIgMC4wNjUgMC4yMTczIDAuMDk3NSAwLjQ1NyAwLjA5NzUgMC43MTkxdjAuMzQ2MmgtMi44MDk0di0wLjU4MTRoMi4wMDk2di0wLjA2MzljLTAuMDA0NS0wLjE0NTYtMC4wMzM2LTAuMjgyMi0wLjA4NzQtMC40MDk5LTAuMDUxNS0wLjEyNzctMC4xMzExLTAuMjMwOC0wLjIzODYtMC4zMDkycy0wLjI1MDktMC4xMTc2LTAuNDMwMS0wLjExNzZjLTAuMTM0NSAwLTAuMjU0MyAwLjAyOTEtMC4zNTk2IDAuMDg3My0wLjEwMzEgMC4wNTYxLTAuMTg5MyAwLjEzNzgtMC4yNTg4IDAuMjQ1NC0wLjA2OTQgMC4xMDc1LTAuMTIzMiAwLjIzNzQtMC4xNjEzIDAuMzg5OC0wLjAzNTggMC4xNTAxLTAuMDUzOCAwLjMxOTItMC4wNTM4IDAuNTA3NHYwLjEzNDRjMCAwLjE1OTEgMC4wMjEzIDAuMzA3IDAuMDYzOSAwLjQ0MzYgMC4wNDQ4IDAuMTM0NSAwLjEwOTggMC4yNTIxIDAuMTk0OSAwLjM1MjlzMC4xODgyIDAuMTgwMyAwLjMwOTIgMC4yMzg2YzAuMTIwOSAwLjA1NiAwLjI1ODcgMC4wODQgMC40MTMzIDAuMDg0IDAuMTk0OSAwIDAuMzY4Ni0wLjAzOTIgMC41MjA5LTAuMTE3NnMwLjI4NDUtMC4xODkzIDAuMzk2NS0wLjMzMjdsMC40MjY4IDAuNDEzM2MtMC4wNzg0IDAuMTE0My0wLjE4MDMgMC4yMjQxLTAuMzA1OCAwLjMyOTQtMC4xMjU0IDAuMTAzLTAuMjc4OSAwLjE4Ny0wLjQ2MDQgMC4yNTItMC4xNzkyIDAuMDY1LTAuMzg3NiAwLjA5NzUtMC42MjUgMC4wOTc1em02LjI1MTctNC45Nzd2NC45MDk3aC0wLjgwOTl2LTMuOTQ4NmwtMS4xOTk3IDAuNDA2N3YtMC42Njg4bDEuOTEyMS0wLjY5OWgwLjA5NzV6bTQuMTA4OCA0LjE1N3YtNC40MDloMC44MTMydjUuMTYxN2gtMC43MzU5bC0wLjA3NzMtMC43NTI3em0tMi4zNjU4LTEuMDI1di0wLjA3MDVjMC0wLjI3NTYgMC4wMzI0LTAuNTI2NSAwLjA5NzQtMC43NTI4IDAuMDY1LTAuMjI4NSAwLjE1OTEtMC40MjQ1IDAuMjgyMy0wLjU4ODEgMC4xMjMyLTAuMTY1OCAwLjI3MzMtMC4yOTI0IDAuNDUwMy0wLjM3OTcgMC4xNzctMC4wODk2IDAuMzc2NC0wLjEzNDQgMC41OTgyLTAuMTM0NCAwLjIxOTUgMCAwLjQxMjIgMC4wNDI1IDAuNTc4IDAuMTI3NyAwLjE2NTggMC4wODUxIDAuMzA2OSAwLjIwNzIgMC40MjM0IDAuMzY2MiAwLjExNjUgMC4xNTY5IDAuMjA5NSAwLjM0NTEgMC4yNzg5IDAuNTY0NiAwLjA2OTUgMC4yMTczIDAuMTE4OCAwLjQ1OTMgMC4xNDc5IDAuNzI1OXYwLjIyNTFjLTAuMDI5MSAwLjI1OTktMC4wNzg0IDAuNDk3NC0wLjE0NzkgMC43MTI1LTAuMDY5NCAwLjIxNS0wLjE2MjQgMC40MDEtMC4yNzg5IDAuNTU3OHMtMC4yNTg3IDAuMjc3OC0wLjQyNjggMC4zNjNjLTAuMTY1OCAwLjA4NTEtMC4zNTk1IDAuMTI3Ny0wLjU4MTMgMC4xMjc3LTAuMjE5NiAwLTAuNDE3OS0wLjA0Ni0wLjU5NDktMC4xMzc4LTAuMTc0Ny0wLjA5MTktMC4zMjM3LTAuMjIwNy0wLjQ0NjktMC4zODY1cy0wLjIxNzMtMC4zNjA3LTAuMjgyMy0wLjU4NDdjLTAuMDY1LTAuMjI2My0wLjA5NzQtMC40NzE2LTAuMDk3NC0wLjczNnptMC44MDk4LTAuMDcwNXYwLjA3MDVjMCAwLjE2NTggMC4wMTQ2IDAuMzIwNCAwLjA0MzcgMC40NjM4IDAuMDMxNCAwLjE0MzQgMC4wNzk2IDAuMjY5OSAwLjE0NDUgMC4zNzk3IDAuMDY1IDAuMTA3NiAwLjE0OSAwLjE5MjcgMC4yNTIxIDAuMjU1NCAwLjEwNTMgMC4wNjA1IDAuMjMwNyAwLjA5MDggMC4zNzYzIDAuMDkwOCAwLjE4MzggMCAwLjMzNS0wLjA0MDQgMC40NTM3LTAuMTIxIDAuMTE4OC0wLjA4MDcgMC4yMTE3LTAuMTg5MyAwLjI3ODktMC4zMjYgMC4wNjk1LTAuMTM4OSAwLjExNjUtMC4yOTM1IDAuMTQxMi0wLjQ2Mzd2LTAuNjA4M2MtMC4wMTM1LTAuMTMyMi0wLjA0MTUtMC4yNTU0LTAuMDg0LTAuMzY5Ny0wLjA0MDQtMC4xMTQyLTAuMDk1Mi0wLjIxMzktMC4xNjQ3LTAuMjk5LTAuMDY5NC0wLjA4NzQtMC4xNTU3LTAuMTU0Ni0wLjI1ODgtMC4yMDE3LTAuMTAwOC0wLjA0OTMtMC4yMjA2LTAuMDczOS0wLjM1OTUtMC4wNzM5LTAuMTQ3OSAwLTAuMjczNCAwLjAzMTQtMC4zNzY0IDAuMDk0MS0wLjEwMzEgMC4wNjI3LTAuMTg4MiAwLjE0OS0wLjI1NTQgMC4yNTg3LTAuMDY1IDAuMTA5OC0wLjExMzEgMC4yMzc1LTAuMTQ0NSAwLjM4MzEtMC4wMzE0IDAuMTQ1Ny0wLjA0NzEgMC4zMDE0LTAuMDQ3MSAwLjQ2NzJ6bTcuMjY2NiAxLjExOXYtMS43MzRjMC0wLjEzLTAuMDIzNS0wLjI0Mi0wLjA3MDYtMC4zMzYxLTAuMDQ3LTAuMDk0MS0wLjExODctMC4xNjY5LTAuMjE1LTAuMjE4NC0wLjA5NDEtMC4wNTE1LTAuMjEyOS0wLjA3NzMtMC4zNTYyLTAuMDc3My0wLjEzMjIgMC0wLjI0NjUgMC4wMjI0LTAuMzQyOCAwLjA2NzItMC4wOTY0IDAuMDQ0OC0wLjE3MTQgMC4xMDUzLTAuMjI1MiAwLjE4MTUtMC4wNTM3IDAuMDc2Mi0wLjA4MDYgMC4xNjI0LTAuMDgwNiAwLjI1ODdoLTAuODA2NmMwLTAuMTQzMyAwLjAzNDgtMC4yODIyIDAuMTA0Mi0wLjQxNjcgMC4wNjk1LTAuMTM0NCAwLjE3MDMtMC4yNTQyIDAuMzAyNS0wLjM1OTUgMC4xMzIxLTAuMTA1MyAwLjI5MDEtMC4xODgyIDAuNDczOC0wLjI0ODdzMC4zODk4LTAuMDkwNyAwLjYxODMtMC4wOTA3YzAuMjczNCAwIDAuNTE1MyAwLjA0NTkgMC43MjU5IDAuMTM3NyAwLjIxMjggMC4wOTE5IDAuMzc5OCAwLjIzMDggMC41MDA3IDAuNDE2NyAwLjEyMzIgMC4xODM3IDAuMTg0OSAwLjQxNDUgMC4xODQ5IDAuNjkyM3YxLjYxNjRjMCAwLjE2NTggMC4wMTEyIDAuMzE0OCAwLjAzMzYgMC40NDcgMC4wMjQ2IDAuMTI5OSAwLjA1OTMgMC4yNDMgMC4xMDQxIDAuMzM5NHYwLjA1MzdoLTAuODNjLTAuMDM4MS0wLjA4NzMtMC4wNjgzLTAuMTk4Mi0wLjA5MDctMC4zMzI2LTAuMDIwMi0wLjEzNjctMC4wMzAzLTAuMjY4OS0wLjAzMDMtMC4zOTY2em0wLjExNzYtMS40ODIgMC4wMDY4IDAuNTAwN2gtMC41ODE0Yy0wLjE1MDEgMC0wLjI4MjMgMC4wMTQ2LTAuMzk2NiAwLjA0MzctMC4xMTQyIDAuMDI2OS0wLjIwOTQgMC4wNjcyLTAuMjg1NiAwLjEyMXMtMC4xMzMzIDAuMTE4Ny0wLjE3MTQgMC4xOTQ5LTAuMDU3MSAwLjE2MjQtMC4wNTcxIDAuMjU4OGMwIDAuMDk2MyAwLjAyMjQgMC4xODQ4IDAuMDY3MiAwLjI2NTUgMC4wNDQ4IDAuMDc4NCAwLjEwOTggMC4xNCAwLjE5NDkgMC4xODQ4IDAuMDg3NCAwLjA0NDggMC4xOTI3IDAuMDY3MiAwLjMxNTkgMC4wNjcyIDAuMTY1OCAwIDAuMzEwMy0wLjAzMzYgMC40MzM1LTAuMTAwOCAwLjEyNTUtMC4wNjk1IDAuMjI0LTAuMTUzNSAwLjI5NTctMC4yNTIxIDAuMDcxNy0wLjEwMDggMC4xMDk4LTAuMTk2IDAuMTE0My0wLjI4NTZsMC4yNjIxIDAuMzU5NmMtMC4wMjY5IDAuMDkxOC0wLjA3MjggMC4xOTA0LTAuMTM3OCAwLjI5NTdzLTAuMTUwMSAwLjIwNjEtMC4yNTU0IDAuMzAyNGMtMC4xMDMgMC4wOTQxLTAuMjI3NCAwLjE3MTQtMC4zNzMgMC4yMzE5LTAuMTQzNCAwLjA2MDUtMC4zMDkyIDAuMDkwOC0wLjQ5NzQgMC4wOTA4LTAuMjM3NCAwLTAuNDQ5MS0wLjA0NzEtMC42MzUxLTAuMTQxMi0wLjE4NTktMC4wOTYzLTAuMzMxNi0wLjIyNTEtMC40MzY5LTAuMzg2NC0wLjEwNTMtMC4xNjM2LTAuMTU3OS0wLjM0ODQtMC4xNTc5LTAuNTU0NSAwLTAuMTkyNyAwLjAzNTgtMC4zNjMgMC4xMDc1LTAuNTEwOCAwLjA3NC0wLjE1MDEgMC4xODE1LTAuMjc1NiAwLjMyMjYtMC4zNzY0IDAuMTQzNC0wLjEwMDggMC4zMTgyLTAuMTc3IDAuNTI0My0wLjIyODUgMC4yMDYxLTAuMDUzOCAwLjQ0MTMtMC4wODA3IDAuNzA1Ny0wLjA4MDdoMC42MzUxem00LjAxNDktMS40MjQ4aDAuNzM2djMuNTM1MmMwIDAuMzI3MS0wLjA3IDAuNjA0OS0wLjIwOSAwLjgzMzQtMC4xMzggMC4yMjg2LTAuMzMyIDAuNDAyMi0wLjU4MSAwLjUyMDktMC4yNDkgMC4xMjEtMC41MzYgMC4xODE1LTAuODY0IDAuMTgxNS0wLjEzOCAwLTAuMjkzLTAuMDIwMi0wLjQ2My0wLjA2MDUtMC4xNjgtMC4wNDAzLTAuMzMyLTAuMTA1My0wLjQ5MS0wLjE5NDktMC4xNTctMC4wODc0LTAuMjg4LTAuMjAyOC0wLjM5My0wLjM0NjFsMC4zOC0wLjQ3NzJjMC4xMyAwLjE1NDUgMC4yNzMgMC4yNjc3IDAuNDMgMC4zMzk0czAuMzIxIDAuMTA3NSAwLjQ5NCAwLjEwNzVjMC4xODYgMCAwLjM0NC0wLjAzNDcgMC40NzQtMC4xMDQyIDAuMTMyLTAuMDY3MiAwLjIzNC0wLjE2NjkgMC4zMDUtMC4yOTkgMC4wNzItMC4xMzIyIDAuMTA4LTAuMjkzNSAwLjEwOC0wLjQ4NHYtMi43Mjg3bDAuMDc0LTAuODIzM3ptLTIuNDcgMS44NTgzdi0wLjA3MDVjMC0wLjI3NTYgMC4wMzMtMC41MjY1IDAuMTAxLTAuNzUyOCAwLjA2Ny0wLjIyODUgMC4xNjMtMC40MjQ1IDAuMjg5LTAuNTg4MSAwLjEyNS0wLjE2NTggMC4yNzctMC4yOTI0IDAuNDU3LTAuMzc5NyAwLjE3OS0wLjA4OTYgMC4zODItMC4xMzQ0IDAuNjA4LTAuMTM0NCAwLjIzNSAwIDAuNDM2IDAuMDQyNSAwLjYwMSAwLjEyNzcgMC4xNjkgMC4wODUxIDAuMzA5IDAuMjA3MiAwLjQyMSAwLjM2NjIgMC4xMTIgMC4xNTY5IDAuMTk5IDAuMzQ1MSAwLjI2MiAwLjU2NDYgMC4wNjUgMC4yMTczIDAuMTEzIDAuNDU5MyAwLjE0NCAwLjcyNTl2MC4yMjUxYy0wLjAyOSAwLjI1OTktMC4wNzggMC40OTc0LTAuMTQ4IDAuNzEyNS0wLjA2OSAwLjIxNS0wLjE2MSAwLjQwMS0wLjI3NSAwLjU1NzgtMC4xMTUgMC4xNTY4LTAuMjU2IDAuMjc3OC0wLjQyNCAwLjM2My0wLjE2NSAwLjA4NTEtMC4zNjEgMC4xMjc3LTAuNTg4IDAuMTI3Ny0wLjIyMiAwLTAuNDIyLTAuMDQ2LTAuNjAxLTAuMTM3OC0wLjE3Ny0wLjA5MTktMC4zMy0wLjIyMDctMC40NTctMC4zODY1LTAuMTI2LTAuMTY1OC0wLjIyMi0wLjM2MDctMC4yODktMC41ODQ3LTAuMDY4LTAuMjI2My0wLjEwMS0wLjQ3MTYtMC4xMDEtMC43MzZ6bTAuODEtMC4wNzA1djAuMDcwNWMwIDAuMTY1OCAwLjAxNSAwLjMyMDQgMC4wNDcgMC40NjM4IDAuMDMzIDAuMTQzNCAwLjA4NCAwLjI2OTkgMC4xNTEgMC4zNzk3IDAuMDY5IDAuMTA3NiAwLjE1NyAwLjE5MjcgMC4yNjIgMC4yNTU0IDAuMTA4IDAuMDYwNSAwLjIzNCAwLjA5MDggMC4zOCAwLjA5MDggMC4xOSAwIDAuMzQ2LTAuMDQwNCAwLjQ2Ny0wLjEyMSAwLjEyMy0wLjA4MDcgMC4yMTctMC4xODkzIDAuMjgyLTAuMzI2IDAuMDY3LTAuMTM4OSAwLjExNS0wLjI5MzUgMC4xNDEtMC40NjM3di0wLjYwODNjLTAuMDEzLTAuMTMyMi0wLjA0MS0wLjI1NTQtMC4wODQtMC4zNjk3LTAuMDQtMC4xMTQyLTAuMDk1LTAuMjEzOS0wLjE2NC0wLjI5OS0wLjA3LTAuMDg3NC0wLjE1Ny0wLjE1NDYtMC4yNjItMC4yMDE3LTAuMTA2LTAuMDQ5My0wLjIzLTAuMDczOS0wLjM3My0wLjA3MzktMC4xNDYgMC0wLjI3MyAwLjAzMTQtMC4zOCAwLjA5NDEtMC4xMDggMC4wNjI3LTAuMTk2IDAuMTQ5LTAuMjY2IDAuMjU4Ny0wLjA2NyAwLjEwOTgtMC4xMTcgMC4yMzc1LTAuMTUxIDAuMzgzMS0wLjAzMyAwLjE0NTctMC4wNSAwLjMwMTQtMC4wNSAwLjQ2NzJ6bTMuMjI1IDAuMDcwNXYtMC4wNzczYzAtMC4yNjIxIDAuMDM4LTAuNTA1MiAwLjExNC0wLjcyOTIgMC4wNzYtMC4yMjYzIDAuMTg2LTAuNDIyMyAwLjMyOS0wLjU4ODEgMC4xNDYtMC4xNjggMC4zMjMtMC4yOTggMC41MzEtMC4zODk4IDAuMjExLTAuMDk0MSAwLjQ0OC0wLjE0MTEgMC43MTMtMC4xNDExIDAuMjY2IDAgMC41MDQgMC4wNDcgMC43MTIgMC4xNDExIDAuMjExIDAuMDkxOCAwLjM4OSAwLjIyMTggMC41MzQgMC4zODk4IDAuMTQ2IDAuMTY1OCAwLjI1NyAwLjM2MTggMC4zMzMgMC41ODgxIDAuMDc2IDAuMjI0IDAuMTE0IDAuNDY3MSAwLjExNCAwLjcyOTJ2MC4wNzczYzAgMC4yNjIyLTAuMDM4IDAuNTA1Mi0wLjExNCAwLjcyOTMtMC4wNzYgMC4yMjQtMC4xODcgMC40Mi0wLjMzMyAwLjU4ODEtMC4xNDUgMC4xNjU3LTAuMzIyIDAuMjk1Ny0wLjUzMSAwLjM4OTgtMC4yMDggMC4wOTE4LTAuNDQ0IDAuMTM3OC0wLjcwOSAwLjEzNzgtMC4yNjYgMC0wLjUwNS0wLjA0Ni0wLjcxNS0wLjEzNzgtMC4yMDktMC4wOTQxLTAuMzg2LTAuMjI0MS0wLjUzMS0wLjM4OTgtMC4xNDYtMC4xNjgxLTAuMjU3LTAuMzY0MS0wLjMzMy0wLjU4ODEtMC4wNzYtMC4yMjQxLTAuMTE0LTAuNDY3MS0wLjExNC0wLjcyOTN6bTAuODEtMC4wNzczdjAuMDc3M2MwIDAuMTYzNiAwLjAxNiAwLjMxODIgMC4wNSAwLjQ2MzhzMC4wODYgMC4yNzMzIDAuMTU4IDAuMzgzMSAwLjE2NCAwLjE5NiAwLjI3NiAwLjI1ODdjMC4xMTIgMC4wNjI4IDAuMjQ1IDAuMDk0MSAwLjM5OSAwLjA5NDEgMC4xNTEgMCAwLjI4LTAuMDMxMyAwLjM5LTAuMDk0MSAwLjExMi0wLjA2MjcgMC4yMDQtMC4xNDg5IDAuMjc2LTAuMjU4N3MwLjEyNC0wLjIzNzUgMC4xNTgtMC4zODMxYzAuMDM2LTAuMTQ1NiAwLjA1NC0wLjMwMDIgMC4wNTQtMC40NjM4di0wLjA3NzNjMC0wLjE2MTMtMC4wMTgtMC4zMTM2LTAuMDU0LTAuNDU3LTAuMDM0LTAuMTQ1Ni0wLjA4OC0wLjI3NDQtMC4xNjItMC4zODY1LTAuMDcxLTAuMTEyLTAuMTYzLTAuMTk5My0wLjI3NS0wLjI2MjEtMC4xMS0wLjA2NDktMC4yNDEtMC4wOTc0LTAuMzkzLTAuMDk3NC0wLjE1MyAwLTAuMjg1IDAuMDMyNS0wLjM5NyAwLjA5NzQtMC4xMSAwLjA2MjgtMC4yIDAuMTUwMS0wLjI3MiAwLjI2MjEtMC4wNzIgMC4xMTIxLTAuMTI0IDAuMjQwOS0wLjE1OCAwLjM4NjUtMC4wMzQgMC4xNDM0LTAuMDUgMC4yOTU3LTAuMDUgMC40NTd6IiBmaWxsLW9wYWNpdHk9Ii4zOCIvPgogICA8cGF0aCBkPSJtNDguMTk2IDgwLjQ2OXYyLjc5NTloLTE0LjIxM3YtMi40MDI3bDYuOTAyNS03LjUyODdjMC43NTcyLTAuODU0MyAxLjM1NDMtMS41OTIyIDEuNzkxMS0yLjIxMzUgMC40MzY5LTAuNjIxMyAwLjc0MjctMS4xNzk1IDAuOTE3NS0xLjY3NDYgMC4xODQ0LTAuNTA0OSAwLjI3NjYtMC45OTUxIDAuMjc2Ni0xLjQ3MDggMC0wLjY2OTktMC4xMjYyLTEuMjU3Mi0wLjM3ODYtMS43NjIxLTAuMjQyNy0wLjUxNDUtMC42MDE5LTAuOTE3NC0xLjA3NzYtMS4yMDg2LTAuNDc1Ny0wLjMwMS0xLjA1MzMtMC40NTE1LTEuNzMyOS0wLjQ1MTUtMC43ODY0IDAtMS40NDY1IDAuMTY5OS0xLjk4MDUgMC41MDk3LTAuNTMzOSAwLjMzOTgtMC45MzY4IDAuODEwNi0xLjIwODYgMS40MTI2LTAuMjcxOSAwLjU5MjEtMC40MDc4IDEuMjcxNy0wLjQwNzggMi4wMzg3aC0zLjUwOTVjMC0xLjIzMyAwLjI4MTYtMi4zNTkxIDAuODQ0Ni0zLjM3ODUgMC41NjMxLTEuMDI5IDEuMzc4Ni0xLjg0NDUgMi40NDY1LTIuNDQ2NCAxLjA2NzktMC42MTE3IDIuMzU0Mi0wLjkxNzUgMy44NTktMC45MTc1IDEuNDE3NCAwIDIuNjIxMiAwLjIzNzkgMy42MTE0IDAuNzEzNiAwLjk5MDMgMC40NzU3IDEuNzQyNyAxLjE1MDQgMi4yNTcyIDIuMDI0MSAwLjUyNDIgMC44NzM4IDAuNzg2NCAxLjkwNzcgMC43ODY0IDMuMTAxOCAwIDAuNjYwMi0wLjEwNjggMS4zMTU1LTAuMzIwNCAxLjk2NTktMC4yMTM2IDAuNjUwNS0wLjUxOTQgMS4zMDA5LTAuOTE3NCAxLjk1MTQtMC4zODg0IDAuNjQwNy0wLjg0OTUgMS4yODYzLTEuMzgzNSAxLjkzNjctMC41MzM5IDAuNjQwOC0xLjEyMTIgMS4yOTEyLTEuNzYyIDEuOTUxNGwtNC41ODcxIDUuMDUzMWg5Ljc4NTh6bTE2LjQyOSAwdjIuNzk1OWgtMTQuMjEzdi0yLjQwMjdsNi45MDI2LTcuNTI4N2MwLjc1NzItMC44NTQzIDEuMzU0Mi0xLjU5MjIgMS43OTExLTIuMjEzNXMwLjc0MjctMS4xNzk1IDAuOTE3NC0xLjY3NDZjMC4xODQ1LTAuNTA0OSAwLjI3NjctMC45OTUxIDAuMjc2Ny0xLjQ3MDggMC0wLjY2OTktMC4xMjYyLTEuMjU3Mi0wLjM3ODYtMS43NjIxLTAuMjQyNy0wLjUxNDUtMC42MDE5LTAuOTE3NC0xLjA3NzYtMS4yMDg2LTAuNDc1Ny0wLjMwMS0xLjA1MzMtMC40NTE1LTEuNzMyOS0wLjQ1MTUtMC43ODY0IDAtMS40NDY1IDAuMTY5OS0xLjk4MDUgMC41MDk3LTAuNTMzOSAwLjMzOTgtMC45MzY4IDAuODEwNi0xLjIwODcgMS40MTI2LTAuMjcxOCAwLjU5MjEtMC40MDc3IDEuMjcxNy0wLjQwNzcgMi4wMzg3aC0zLjUwOTVjMC0xLjIzMyAwLjI4MTUtMi4zNTkxIDAuODQ0Ni0zLjM3ODUgMC41NjMxLTEuMDI5IDEuMzc4Ni0xLjg0NDUgMi40NDY1LTIuNDQ2NCAxLjA2NzktMC42MTE3IDIuMzU0Mi0wLjkxNzUgMy44NTktMC45MTc1IDEuNDE3NCAwIDIuNjIxMiAwLjIzNzkgMy42MTE0IDAuNzEzNnMxLjc0MjYgMS4xNTA0IDIuMjU3MiAyLjAyNDFjMC41MjQyIDAuODczOCAwLjc4NjMgMS45MDc3IDAuNzg2MyAzLjEwMTggMCAwLjY2MDItMC4xMDY4IDEuMzE1NS0wLjMyMDMgMS45NjU5LTAuMjEzNiAwLjY1MDUtMC41MTk0IDEuMzAwOS0wLjkxNzUgMS45NTE0LTAuMzg4MyAwLjY0MDctMC44NDk0IDEuMjg2My0xLjM4MzQgMS45MzY3LTAuNTMzOSAwLjY0MDgtMS4xMjEzIDEuMjkxMi0xLjc2MiAxLjk1MTRsLTQuNTg3MSA1LjA1MzFoOS43ODU4em0yLjQ5MjUtMTQuODFjMC0wLjcwODcgMC4xNzQ3LTEuMzU5MiAwLjUyNDItMS45NTE0czAuODE1NS0xLjA2MyAxLjM5OC0xLjQxMjVjMC41OTIyLTAuMzU5MiAxLjIzMjktMC41Mzg4IDEuOTIyMi0wLjUzODggMC42OTkgMCAxLjMzNDkgMC4xNzk2IDEuOTA3NyAwLjUzODggMC41NzI4IDAuMzQ5NSAxLjAyOTEgMC44MjAzIDEuMzY4OCAxLjQxMjUgMC4zNDk1IDAuNTkyMiAwLjUyNDMgMS4yNDI3IDAuNTI0MyAxLjk1MTRzLTAuMTc0OCAxLjM1OTEtMC41MjQzIDEuOTUxM2MtMC4zMzk3IDAuNTgyNS0wLjc5NiAxLjA0MzYtMS4zNjg4IDEuMzgzNHMtMS4yMDg3IDAuNTA5Ny0xLjkwNzcgMC41MDk3Yy0wLjY4OTMgMC0xLjMzLTAuMTY5OS0xLjkyMjItMC41MDk3LTAuNTgyNS0wLjMzOTgtMS4wNDg1LTAuODAwOS0xLjM5OC0xLjM4MzQtMC4zNDk1LTAuNTkyMi0wLjUyNDItMS4yNDI2LTAuNTI0Mi0xLjk1MTN6bTEuOTY1OSAwYzAgMC41MjQyIDAuMTg0NSAwLjk2NTkgMC41NTM0IDEuMzI1MSAwLjM2ODkgMC4zNDk1IDAuODEwNiAwLjUyNDMgMS4zMjUxIDAuNTI0MyAwLjUxNDYgMCAwLjk0NjYtMC4xNzQ4IDEuMjk2MS0wLjUyNDNzMC41MjQyLTAuNzkxMiAwLjUyNDItMS4zMjUxYzAtMC41NDM3LTAuMTc0Ny0wLjk5NTEtMC41MjQyLTEuMzU0M3MtMC43ODE1LTAuNTM4OC0xLjI5NjEtMC41Mzg4Yy0wLjUxNDUgMC0wLjk1NjIgMC4xNzk2LTEuMzI1MSAwLjUzODhzLTAuNTUzNCAwLjgxMDYtMC41NTM0IDEuMzU0M3ptMjEuNzI5IDEwLjcwM2gzLjY0MDZjLTAuMTE2NSAxLjM4ODMtMC41MDQ4IDIuNjI2MS0xLjE2NSAzLjcxMzQtMC42NjAxIDEuMDc3Ni0xLjU4NzMgMS45MjcxLTIuNzgxNCAyLjU0ODRzLTIuNjQ1NCAwLjkzMi00LjM1NDEgMC45MzJjLTEuMzEwNiAwLTIuNDkwMS0wLjIzMy0zLjUzODYtMC42OTktMS4wNDg1LTAuNDc1Ny0xLjk0NjUtMS4xNDU2LTIuNjk0LTIuMDA5Ni0wLjc0NzYtMC44NzM3LTEuMzIwNC0xLjkyNzEtMS43MTg0LTMuMTYtMC4zODgzLTEuMjMyOS0wLjU4MjUtMi42MTE1LTAuNTgyNS00LjEzNTd2LTEuNzYyYzAtMS41MjQyIDAuMTk5LTIuOTAyOCAwLjU5NzEtNC4xMzU3IDAuNDA3Ny0xLjIzMjkgMC45OTAyLTIuMjg2MyAxLjc0NzQtMy4xNiAwLjc1NzMtMC44ODM1IDEuNjY1LTEuNTU4MiAyLjcyMzItMi4wMjQyIDEuMDY3OS0wLjQ2NiAyLjI2NjktMC42OTkgMy41OTY5LTAuNjk5IDEuNjg5MiAwIDMuMTE2MyAwLjMxMDcgNC4yODEzIDAuOTMyczIuMDY3OCAxLjQ4MDUgMi43MDg2IDIuNTc3NWMwLjY1MDQgMS4wOTcxIDEuMDQ4NCAyLjM1NDMgMS4xOTQxIDMuNzcxN2gtMy42NDA2Yy0wLjA5NzEtMC45MTI2LTAuMzEwNy0xLjY5NDEtMC42NDA3LTIuMzQ0Ni0wLjMyMDQtMC42NTA0LTAuNzk2MS0xLjE0NTUtMS40MjcxLTEuNDg1My0wLjYzMTEtMC4zNDk1LTEuNDU2My0wLjUyNDItMi40NzU2LTAuNTI0Mi0wLjgzNDkgMC0xLjU2MyAwLjE1NTMtMi4xODQ0IDAuNDY1OS0wLjYyMTMgMC4zMTA3LTEuMTQwNyAwLjc2Ny0xLjU1ODEgMS4zNjg5LTAuNDE3NSAwLjYwMTktMC43MzMgMS4zNDQ2LTAuOTQ2NiAyLjIyOC0wLjIwMzkgMC44NzM4LTAuMzA1OCAxLjg3MzctMC4zMDU4IDIuOTk5OXYxLjc5MTFjMCAxLjA2NzkgMC4wOTIyIDIuMDM4NyAwLjI3NjcgMi45MTI1IDAuMTk0MiAwLjg2NCAwLjQ4NTQgMS42MDY3IDAuODczNyAyLjIyOCAwLjM5ODEgMC42MjEzIDAuOTAyOSAxLjEwMTkgMS41MTQ1IDEuNDQxNyAwLjYxMTYgMC4zMzk3IDEuMzQ0NiAwLjUwOTYgMi4xOTg5IDAuNTA5NiAxLjAzODggMCAxLjg3ODUtMC4xNjUgMi41MTkzLTAuNDk1MSAwLjY1MDQtMC4zMzAxIDEuMTQwNy0wLjgxMDYgMS40NzA4LTEuNDQxNiAwLjMzOTgtMC42NDA4IDAuNTYzLTEuNDIyMyAwLjY2OTgtMi4zNDQ2eiIgZmlsbC1vcGFjaXR5PSIuODciLz4KICA8L2c+CiA8L2c+CiA8ZGVmcz4KICA8ZmlsdGVyIGlkPSJmaWx0ZXIwX2RfMTE0Ml8yMDM5NTQiIHg9Ii45MTE3NiIgeT0iLjIwNTg4IiB3aWR0aD0iMTI2LjE4IiBoZWlnaHQ9IjEyNi4xOCIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiPgogICA8ZmVGbG9vZCBmbG9vZC1vcGFjaXR5PSIwIiByZXN1bHQ9IkJhY2tncm91bmRJbWFnZUZpeCIvPgogICA8ZmVDb2xvck1hdHJpeCBpbj0iU291cmNlQWxwaGEiIHJlc3VsdD0iaGFyZEFscGhhIiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDEyNyAwIi8+CiAgIDxmZU9mZnNldCBkeT0iMi4yOTQxMiIvPgogICA8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIyLjI5NDEyIi8+CiAgIDxmZUNvbXBvc2l0ZSBpbjI9ImhhcmRBbHBoYSIgb3BlcmF0b3I9Im91dCIvPgogICA8ZmVDb2xvck1hdHJpeCB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAuMDQgMCIvPgogICA8ZmVCbGVuZCBpbjI9IkJhY2tncm91bmRJbWFnZUZpeCIgcmVzdWx0PSJlZmZlY3QxX2Ryb3BTaGFkb3dfMTE0Ml8yMDM5NTQiLz4KICAgPGZlQmxlbmQgaW49IlNvdXJjZUdyYXBoaWMiIGluMj0iZWZmZWN0MV9kcm9wU2hhZG93XzExNDJfMjAzOTU0IiByZXN1bHQ9InNoYXBlIi8+CiAgPC9maWx0ZXI+CiA8L2RlZnM+Cjwvc3ZnPgo=", + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAYAAABJ/yOpAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAJFzSURBVHgBrb0HoCRHdSh6qmdu3qjNq7CrsCuJoAiSAGFyEtgWyOSc/J4fBgw48s0zD9vYxvAMziaDyLYJxiQRJFBCoCyiskDSBkmbbr53puvXSVWnqnvuXfm5pdmZ211d4dTJdeqUg3Cddv5fv935zhudgzX4tw//Ofwv3KDLh7+riv724Tde+Ds+l7/B0csAFf7Df2gZW9b+nb4reof/9vKx7dTyvAKPTYXHvnJZGe9rqCrXaCP1r5J7pm3vU9/NmLk/PvubipV1hvYQXlWAj/f90ISDiuqBCMM6vq9t23Z86j+1p+9p+1QofuuF7bX/lnoLOJT9bpuXRjmtw/FcVBZuwP3FW3jfEyh9MR8e2q66rrN2tBx+6yv0u8ZPnzEh/I3v4XN81u/XNN++z/f7/T7UvfAJ373w3V/sweLiPMxNz8ADd98Bnan74C1veC6cc9ZDGuNXfI/9B7gz/P7Y8ccf+/buGee/5+117f/EuzCNnl90kCOzToz3JcLXDDYBRkXIGwbvEWAeymqk8VhfTjT8uw5IVjlFIgEcCML6Zp/kaQBSL0MUfuITogETIMPASxtekC8RM9VWRRIy/STKh8Z4PCMSThaWq7hKZQ+mr4kw0xAE0byP7eMceBlT1QH6W5lDeof/1Hki2Mexu4jQWn5Jpjbgm5HfZwzFaxnHcNTy2pr2IYKrlVA8dDo6F7WBC7elxEOE4Gim+H2DgwFfqY5QNECmZoZSh0+454RJ1uF31a8i4wWqjwm5iszICbPlMfE8Uhvbw99/cscdd0E3NPLypShe7+skKJFwWRfxNEkbbhSaZJaAXE6GaZY7z/V6qYPQ1qe+MB4pUKtscmy/BaIGN7XPiv5MEIzcFYAVXqbzCQGZw9m2fOyTz4iW55RkSwEJ1wLjKtIQw6Yj7boEqwK5GSQ+49Y0wQFhKldlMCgJw/a/IUkqrjybI+1YVt4yDikl804ErYiosIGSIeh8MiP0wggQ8RUfGIEF//r4rEMExLABqYsZWqcjYAk/qhrnqxa4VhnsXETAiqQ/T6iLMKXhK6EAvLEbvrbbDpWAs1KjJKBcAkQ4gWsySwMQnxcGiEg+8EW5vHClOvLmhJAJu5ttxvdt3S7VgOqjVM4wA9fyfmIGESaVEmmiKGfK0cQ0+ucacOP6pA/OIC+oFOaJ9DAA5gCZFGx7VhJJ/k7F0kL6DGU7rokbSUgkIrDqaM5UU0VKWJbBJmlUJQboKxkzayOqWlWi6jOhpL72+W1utxPmESVKxUSQGAyr5SIweAyqNQBLEG7TE451wK3plrpgG2HkAG0CT7+8qAKqxrSWz9qKeMn3uFOxDPfXZ43QRAjnZ8RULgoZ52mbbIO3OitSVhBTxHp5JU6ZI0mUpqD9MmoOJFXVi3o3iPgtEWr/EgJ5sa3aub5F/AyJG3VDlDLNMVnpV9SvHYrP9M8kZXLGl5hA7JuDXMdvwStlEqRiCRx9/M8R0tNvsktqqdtDA7VwKFimQmLqZzYpMUDh4KUmo+1V5hl+d22HLXcfxKnykeU8PKkxh/l+vGoSsWwX1FGxqqnDRYPSWq6iNY1DJ+pg9nbF9UaOJUiiYj4itkU4pU1DENQD/R25X3hPiC6poZDKVO3MoslsVN1oEqNKJGtzeFEhq4JILDlnCO9d1pfEEAzDyPqUE5QlLCsNlpRSURC69nmDJLU7pF46EZrMHFRzoL8D4iPXr9F+iQSSVG0qXKOa1ScYJbuI1VjvIFNby74Kbyd41qGubgQyLI3UpN/WBYJETg6kvDkScnV6XtSX7iUgAyQ9OwGae6nCIz6L5quMoqUd6xHJ1YIqNtkcZS4dsie1H4jcceykmnk29gRx+CGLpKRB5kiv44qTGOHS7JOd0Ka64xojiGUMByfGLISWpGVOGBbZyysnEhgoycorSr/GnJjf7OojeNvn3id8ixLEM6yrQCx1n9tFLxbbqh0aUgeJBI12UckUfg2pKzBSlTD2C+twRoJogUEDtcSRAYdtVwG4cP8BdJa4u4tSIqpXxN2i/AFn7AzbNyIcGoAfOCEll8+QBQzqqYHmc/Rqeusgc1KAcN4KDLF65oJORKlytMgjCybUdIh4SMQhcAXrEClK27EVzDDNjUwO2gTUC/O7EjrxAwjO9LdyLko3VxBTZSW1UVtLGFpG0DqWjpTpJC4ukIwEwTeYSbLLlz2nSBxaFtAaIUKrodvpQSe4AhlG4izxCaY4LqtpxP7qcEL5rgW2HUzJHfJKfASsVTVADCowtkAJCAWkh1ytAaMHu1h/4tJUwkHGRVkkDtZr43i40shnM4JRbJEybXXppS5IlxoRMLrYXxWQ6W9poxrUP6pZ+iX9NG7akjbKeQE32DDnulQ6CQJl7VrXrK3XlvWGAB00VUz+xnrs+kabV9E16IPno4oqFd+rIHk2WRALfKldZkJYn3q0tP1+1Rfm2wM/1IWqFz7i3qpch1piBqGwNhIzsjoPlsF3G11ukSJ4b3x0CM4+bRsctWl1PryELdmXlQUJFDJpWs6nCbOdcvmfueTQ2iyi6oABcqIBSBirUikjmITgqWNanwOr5jgHxe+8XYgEbwlMv6t8fC5xQ2fglppQjmCIDowCJshfueLdOH7IiaZyGUxziWHHldfnI8xSYQd5eWJ13sxr1hlQwSO6v8/GltrXOg1XBMsZzLx7yIiH/65FqvCiYU2LhnVYMFyExfl5mH3kFhjyi7BjxzbododCmX5iXrFmw+hNH4yR3lQz9Bl+Xv+yc+HIQBwWcbWTAxguQAbOJQs2CKT5VwOi8c+kJvjm2669k5GQfI4kZacGdbmdaxtGkFcDtv7mq4KObf1w2ZtZfa7RxoC+xdfcEnDOO+ba6i1eZvLxzWctlbeCMdJEMcftWFb89pl0VemjC4k1rrQHQgD0AMJmGApMYnioEz5VULsczM7Pynu5QEhqNI+p0kJtQ9AXzzrlaCKOQWPMiN2wj2aNviycP8reb3Sm9VECUgtx6PNWLLfEoe8vVX/zvvfQmCS3RF0wqCtRrLeP3cjDlvtQEAdEpG1Un73U1pAf1PjA+1YylTdc23PpZGnjDajN3C9/qy3Et1RliipilBDGVS0wxgXHoaGh2H5pV9mravY97zi+cMK29Y1uZpMTRVL2pDlRg64IlwGILMjcTsSDJYCHgeSWbBxfEllb235wv8DLOH2slz9tdYE4HAZUV7ZvOX/7C827filu7jPkzQswIAche1k8EWJeyEFb/elGsuF8+7iWohfX9mH7IfFP/TsRCsTfLuJKR6IVlIhiE4ZY8Bpog7S5aQeNI2dR/4VrkGS1rUVRZQcDS16H26VcNSrFOU+lxWpX/vBJX7f3Y03GA6PtLd+p/2KR5d7zy5c5nO41qnFLV0bQcb79BUO0S9u1A1p33pCbZ5tLKxKCTITgDOFVRj3HT130TbxYuYhuFzVtF3sYYABwfOOXW2pyXFFvs6XGb5+ZJQXxgG3Xt2KlvR2BC23cX7wlWsrSa3q56K7jdu1zfTEu8BTvFUDIBHMDKm4JXDdPDGeNtXkzhvbWi7u5M4G/3MAXm/jtmu+YMqlnbkmic4MeNHBDmHtBIFGKUKkKSvc2hrfwd/Iqdl0r4gyWHqkLA/qaddrnRZZknXb4dsCDyzWrNMQDzYlqq8o3BqRVqfRIY2A+Jf1zZftJBhV43N6wW4aVO4ClWVQ7kTWQMBJDk4Es135qZ8CjtnuZGGhRo+R5qRY7t3T9zfeTkyW+I0RQ1y4RSJXcwvnHVOkGs4psodAdluwvKi65ZNGQxb0W1DXXIEwdVK69vQf1ni++430fgR9jxoCRjIErxJAxVUV6KIhESUubcq3dGQR7S5gle31ws1VUGjsBsJzO13BFt9YFLUzDtXwVzMFIkNa6fQt+WslU5UNpLKCCSpBymE3DXD1YVZWCKbtWnViOSCwKO35hGZzONfvlkdu3/AbzTpu0U+TyrbW5lv4MvjxEpqTGtMYCAceF0YYoZ4AOdmxgnBxaI7dZ+6SSemehMgDRMxwqiapFUkFqr6zRZZWWLTpoVJVxcwcDC9gv16y5WTQTHy29gBKLExNSYGfvmXkviJLNCqSeOmGPM8qegjTa3KmMXQSPKhZHMlamUHvYSUN1aSWONPm59BhwMbVB4pd+iQkzZGQE2EBSaHS2rUfFILyGV9fcAEXTMlyQSDqO44BUgvpYRc69ABJsMdYIiaSGcoKX4J6QiM8V/WXHATS4ehucB5hgsa6kEg143lZrQRxL2Rd21gYyYDeYUNvIfRBBZe24PJ4vSQ2twWVeroRMaczdcqk9tSuT5/3ACRgMeN8cyFJXxFnfUr4FMR7MZepu1tcsG1224q+lzVSCRPgmSo8ubjPoKHxAxLGW4chSDa0QIUSqgK9VbXPLaTXZlRP6MuXa7rulygzkcjlOWLuhQNxByl6GAW4JlbAkBJdLWPusSct5/5VpRc+UUxsEGvaq3qtrUatsHfKduXnbXLxsDNlqDWCWHPEgCdLCkdzgSSpabLbkAAZyucYT11LWQwlkL4TilUiEOphAeN93R4xEDLvGwDgKv/YqZVgdqyR0uxbiqCHJyIbEa9Gx28cAjRENLpcL5+hcyAqWxpCtL0mucq6bbKutjjSettlZyu4qfzWI0uVsO86g93G3aRrrQMjQN29tNkKB/qlzAmmoUn6JSNLiR3OcTbQc8EgbG4DfMsIldATvAZZdr0nQG1gP+OJb/pDtOiyQRcVidYs37hBx1P0UUUqcsiOcq5IwLJeMez+4OxHRBtO76aQ7/OfO1N/w7xbSzBKTlshZe6PekjhSCIofQFktfXdWVliJUL5cRJWXTx2A3f3soa29gvn7gukTDNjcGLgfZDnP1qBxNgZY/kg9gLJQszo/6AE/jcSxhPrU0lwuNfL+8p8+L9qoMHWAM2r0iEDYA8Lh1RXFADFC2umMdpPPNx8tdUUpUDRvpUNjaPbBwDItdcjEthn7+m5EiSW6rtLKtT+xf7b80S61LHGUryVhoQuS0n4xvfGVzJniTP0g7JCTmEQJEm0Na3u0dSZWBQMYsm/81ZxgB+2FlrpaFI0liDgOubWPyzYGMFCx9FKvpx1nmnKm32MC8R3RZ+tO5iLWd713Rlh5yHRtUe1AuCBYkQ9pf0x6GxoSp6m1wyAGCkwIS89hJj1arqb0WOKydkjGFIt5LW61SoyW952BiXN1k6c4yOAUuZWxT2uvPNI1VSzV4do8V23X0jbIUle7Vn1YdJK1nVCtfNO3/dHQJRolB97mez5rjgiC1CwfN/DgVXfq6AHj9ZQc0eX/JKzMWEzAxAA9LP3NMOO/nW8bnxvM3ZYBdOxHyWAMYvrGO/kf+d/LE0cuUJtSpJ3OUznefWjJosQxvqe4owJBFx11l6zta7dNvdJr2cXDwwI0FMz3wZCBrcVn7+rELdU91/hRAi9XrUpzy3vzToaAaXsma0se7JZNDUhkka/luUL1erGbVgbgE5yi+xbMPeVqRrHm2CYt5wx5GcRIiy4tgGlhSYfB8BJMU6t5ne2vN+eiRN7ih8tVPNdWF5Qr4vzts26leY63RTV3pbbkIGNQOEvLhpr4Ft+waafB4PKy/J3b4C1AXI5evF96AparoCFBtH8u62tBMktUlOpSP3r0pavLvASKuIx1aYXg4tLClSXd+Equn2UlonoFkGwx74SIHDg3YHtrptY1HmZIwuNrISRYmnnmEse10kRWxN5wOheu9flyqMIDSBxmKZVTsBPKB2k/SJVvuR1omP2XuP6gN1vqGsDouM/CQiM7dg+qJa1CWH0L9yyQZXkqAeXZ7NWqsuwZaH9UNlEAGAlTK4GkCSjQMdf5c1YY97tnY8pmG39XAJI8g/JTmTl18cW29qAB2lyNhVZubSHSVkd5Ndfb8j9KZG7vnhuoOTjIhFDWTvbMJbaooSXK65hsPL0/MBYr/9tiTfl70GXUIdOp8hksV5Nfhqf7NKi2yzX+aOeIrUSREUv+DhEHEkanAx3audahEnyvikSinUTpUYu9EhdnK8m7WDHHd+CbnLIxrIJz+7QbRXVw3j7aAbYnTRZIrC4zKjTlkR2yxYGlYdt6tfGww369gLF5tyEF8lLQNoFZjjOfl0hS10MWbqW1OmYy3eWDFD00iWMAcrm2d5tcIx+UVRNg8NXC3XyGvC2F9Km3T9pURmHPPm9MOQwkPI+6qZdwaSSETqcb36G/g6u3MoNRb5eumzCSVyR9OhVzsE6lLM4NxKc2ZGXCqDlPree2+IGkSo3piCDHOLnhisq8a9MijKo8EEdbHupYWlW3Zh2tNkf5u6X9yPUNokfdwLXXk0niDK95HJoxJVsH4RcGITMYTMv1tohqbdyjfE63liG4gVcbd7PXMnVlj7VtaL4jiJqSeTNRKJKQK7CWDpCK1YFkkzDRaHod9nBJMoG6n9acwlPM4TzUrSgfrVXTWked9TsxCCa+8B1g2qsBkudMiCN/DXI1WgBi4NKOmIczP+X6Rts7vlkOmjjXwgcGvpdpoa5lYdvLm85WDpkqq2EpydTgdyhY0VY++PJZ5e3P3QB8V1PITEyDYgAeHHJLUz4faJJ2bvDrDalT/NahiuHtDVchDi0ID5UIHao4Jah28o4ljj5l2qhTLqeKV+S74Z9uII5ut0sShNQszTPWyipLpJX6+5jopp95z+JAPAy276AkmKWgtxyONN9pSoQ2KnRNO8k+bv3DtQutgjYOu6fZwrCLiJKtgyy91bZEbHtfp0NFeVOvtT2P6VXKFh4E8DNmECWjN6zHttfsRUnH3r6Vvy7GsIuk18d2+gHJMfNlS/4qJ3/U8gLGaOFZFj2K1xKKEviweoYEUlEiARfVjFxC5185nGonmSyB48JcpBCvRgeUUmL5bQ1pA7HLIAbNfh3OZRmba3tUEIcdsrrBi4eDeEhjclu7bplZKVEhcl682x2UByu7PAygTl/8xY01uXt6Hl8rCOiwIlxb3L2xKmfvpK+9e3fB3t27csAZgYfXw045A1IVPtk3InrpmYROswlRU5bwksDiX07HZNSrPqtClTTEAkpsmKoSCaJS2DW5pfawhWPimSQVzWOd4G8LFGjgYGlJneOCMgLXcP8nJwSA7guXXh7W1eo5dW39Kd+DJaWFW7YHfmDZ3P/hcwmSCrmBFZZIZhvyWcPLdDAzHPmet+rNMpclRq0y1udTfZ+58EPwnW9+NX/ZNL1x0xb44Mf/rXg3XOQEQkpJuVWJXCQSLjLqNuEambgTIoEoUbxFfJeIO+1TMBXomoAeAmN5uiKXSzq0lpmamoIrLr8MNm3ZCqeccVaTd7g8aNEKmlSsgC8okUDqd8lp4PCJY5BENI8avwcWerBXwQRcwyaGXIJYbpC2G2o51/S0+mZvfRtJtxCTa1TyIEcaZzNJJGeTIRgpiX886/znwhOe9HS696ObroPPfvIj8KQnPwOe/NRn0NgmVqwI3Nv0xWkjpj2DfG1TOsgebQtrL//2WjYCuYZEYViWYuVlwlwau29pUK7pqUl4z1+9A57y9F+FU05/JJRIbDpo2LEDq67mod86xix3SE54Uk2W0MINHneDwbbA0Il6NbCO4kkWaTKwbC5jadhxfJb58J8NG6RuZHD3g9syAE3cx+edadHWUleKegbfaFzN+fbxzVhHuLd9+/FxHHv33EtPNm/eDKeedpoYy0m9vOgbX4Mbb7gWVqxYCU992jPguON3UEt7gor2ja9/FU477XSYDMh35eWXhjIr4NkXPI++P//v/wp79uyCU049HZ72tPMiB/74Rz4C2487HsbGxuGbF30dJsbH4Vm/dj5s2bIl6/o111wNX/3KV2DlyhVwxpmnw+N+5Vxqd3JqGj77mc/BiSeeGKTCdCh3DbzlLW+BlatW0TuXXHwxHJqchNNOPz20fRqsW78Rbr31ltDXr1G9t9/6c/jkRz8Az37ui2B3GMOVl14Mj/6VJ8DxO06kPl5x6SVw+y0/h2c//8U05i987pP03ilnPDL8/gRc8LyXwPE7T6S+fOMrX4Ibrr0aVqxcCU975q/DCTtPytQvhblbFlmaEziQoNpeWYafJtT3g/thCYnGkA7uSZTOP7t6/Fhud6QFJhsbFDm27eWSuGw0zNZyGfnqnch9lzYkTXnLqxNLjnFPrG7xPVWT0MXa7aRV7//9x38Il136PThhx46AjJPwhX//HPz2698IFzz3+bDvgT3wyQs/ElS1r8Pk9CRs2bwFbrnlZvj+FZdn/fzWN74OV11xGfzZO/+KDPJPfuIj1JXxiRWwYeNGuOP22+Di71wE7/zLdxPSY5fe976/gX/73Gcj0Xz605+CV7/6VeHzSjh44AC8//3vD4SzEiYDIeD12te8Fj75qU/CB8J9fGfL1q3w5f/4D9i8ZTO8/4MfD8S8OxDw96gsEsVFX/sPeMozfpWI5RMf+RdSu4474USCwxWXfge++dUvw1Of8WtEIJ8PBDId2vEf+Wf6PjUQChLIW173KrjhuqsDYZ0UYHMI/v2zn4DX/c4fwAUveEmaD5nGVga4xGWRvsCCQsIsLT30O7XvlimtdaYE2MlNnNRd2hRKOUwJqfiMBT60pC+xQyzyy+QOjJQeIrWlVbTi8pAZ5+anqbCp1Zh2yoozj5EZti/q4HFwiAfve1VgQCSQofD51kVfhcsDcbzq1a+Bj37sQvrs3LkDPvbRD8Fw8DBhOXxn54k74RsXfQs++vEL4ZnPfBbsDlLjmc96Fvzb579In5WrVsINN1wHQ0OdsL7RoUlCCfMP//QBeN/f/Qv86Tv/Gqanp+GD7/8n6sf1118H//rZz8J5z3wmfP4LoY5//3eSUh/84Idh//6DFEKPg1oxMQH/+A//AF/4/Bdg44YNcM/d98DjHvc4+NJ//Cf88z+/H17z2t+EXbt2waWXfhce/ZjHwl/937+n+h997uPgo5/9MmzcvLUEOEBzmuhC5vCyV/5P+OLXL4PHnPsElhyBOF726v8J//Kxz8H7P/6vRGQf++A/mrlQfIDIhHT+YnYYaL/8gN85ereo+ZAUX/t+jjttNdsK9KQqPYyoLt4IRrqve6BhCdxA3+holZwP18Tq1BEwRo4t5wpG0BQhye+RKouHc0Ke96jhuvC5B6QhVmOfC2KWNjnxAuZpdUQcWP2RW7fAjQFpscDWwJlvveWW4AXbTV4mfGfnzp20boG14HO894gzH0F14LVjx0647tpriKBqGdhEUJs2B06/sNCDhz3sFNi4cRPcfvvt9Ozyyy7l907YAVdffTUR8gknnBDquDaoUNfCzvAb2zo9qIOnnfJwchpgxvK3vvWtMDMzAxdf/B0yyHftuhfK4etFSGQRtAVvvGVi4Xr2814sIA+q1Vf/g36jWnbDtT+kClG9uvy734Hd994LmwMcohIgNgh4GOiRbOj7RV9BZj5VoHYBNMbVxCjz3C2l6mlflMRqs1ioY5F1EMajfhabwl4aF8Vf4hLNduIwG71Nepy3A9d3rSuRu5ZVrMQTiaiQ3aWumbRgn9SsKOE8uKL/fMgph3hMTU/RvT//sz+F8tqzZ7c5YcqcQ25ksHqgFMi8Il5HHuHkXXyOBPKjH91I/ULkxut973tv5L7KjCYPHaQFRiyHbuLe4mIk73/7/Ofhox/9GFWMRDmF6ldGAQnOHBjpoRSvvo3bFTCyXPhP/vBN0Ly8WT8TRumTdy1WGYnHOoLb0TvhSKK6JXe1LnO5Je5UcVXWnoAFkRbwu4s+SOt6xKtWL4buJ5DcUHHXQdmqwe2M4dM9g8rOElSisIyXGGL0toF47E8mlopu+Az0SUUDKCqMSIs/Vgb9G69vffs7pO9nhQDIOE6Dsu0L13HmnnxyN2Kqcu/ePTARbBIQ9Quvv//7f4Azzjg9SIdeIIQF6PV7BJ+9e/YKkuM6So9cxZNBRfu7v/1b2BGkGaqCGOby1a/+J/zpO96RhlkMuylZa2jo6FbNTf52sk3w/he+ERwTK1dl40nh9gp35f6QuexzA1jLp1y9pSMn48yGaR/OlbAtjXzpdREXtae0DVfecl6y99b5x8k3nbFAh5MwUBkEwo0oHY6kxAHV8XOureXid63Gch1nMW02snaCj23RUZ7yzMmH3w+qoO/Lb37PqSEufau0v2D71rwe9/jH0fcHP/ABKeWJKD7w/g/kBRNjjlK1llXz2ifEtLg2HaTEnj176PdV37+CCORRj3o0/X3uuY+l788FI505pYc9QaX7QpAQqd/STrAT8XPo0CF6gkSmsLv22mtSFw3XR49blCIysttu/RnBZzpIqBuDbcFXDbmEkUEE5nn8CTvp1oUf+ucIa1S1Pv6hf0pzpjjizU5KqSP7W+dfpbov8aTO8EXYD5TX4ZEKLEcWESbgXCGlEpl11WpvII9KEVk5dj5VyAtFBgtAjSjXTBTdIGmXSxItkimxsTB9qqwtSCqX4Uppj4yPHIHe9YzEDfXP/ESD+9qg93/mM5+G7373ErqNRu/pZ5wBr6lfM4iuIgrXvlADzaBRjfqt//HqoFpthNtuuy0g9gQ8/4UvpWdokL/61a+GD3/4Q8E9/DTYvGkT3BzsHvz+jQvOB6ul8MndAJs2b4RTTz2VDPzn/sYFweifiriNHia8Nm3cHBZAN8P3L/suvPwFvwrv+pt/gUcF431T8L598d8+DVdedgn1iyUYMkRhNtoa/ebGX/qK18JtwRWMHq7Lg5sYn+8JsHnqeb8KUbNwMq8ASVJ4kA1haW+FbhDzqWCcFo16i/dSUBoc7tWCxY23MzIohFRWTvCxs/7Yx75dOaz3PuM26iY9/SFHwVFb1oCG4VWRu8ewPBm4cmrDsU19+T2GlFKyy/QCrsMZSaJ/O9Ltk/Sib6/STb5Vupm2yX4Id9etW0eIeWQwLjmKlrkHeoV2BM/V0PAwbNu2DV76spfB/3rd6yJEUfU648wzg1t1S+wVGt+nnXEmrQ0Qc6jQ03ViKMehKyiRNoU1l7f+8Z/A3Ox8qP9keP0b30LrMGj7DA114RGPeET4nAEjI8O0DnLeM54Kb37zG+hvxCr8Pv20U+GYbUczpwsq1XnnnQdbjzyKbKMnP+Vp8MY3vokWPI86+ujw2UbS7JxHP54Q8uhjtsGZjzwneMJWBA/XrwR1coJ+v/CFL4bHP+HJoX9htT04AYaHhmmsJz/kYYEAT4ekEQA8/olPITfyiomVoR/b4QUveTm84MUvz+K+ojSIl49MNc6jnWMp6yR+zFkNwUGmkokB10DwQRd3hWPfKDgU+MRaDenRxfDa10atsk35WI876Yn/nx/UkL78it94FDzmzOMzwqg0SC6qHU7cevqyfiW9Mz2QATt5XnQSwBl7R8RxFIcGCpbFas2OpYYWQWSJZ6Bi9Gxwv44Md2F4eIgQtNupsjPHdfO+jSyKmRJlolTFqsGnnLvgKF8WEiEdnBvUk3POeiRsCtLgY5/4LMzPLwYbgyNucZKGQx/GRoe5H110FmC0b49tjRrTCPkETzMewMMoq6FA3EO8D8WxltwL6vDiYg8W8Gw+0lIq4dgcdlwRY6s5HVE8jRilOYexeGtfmcmIM2GlNdiiDnJcdskGa51XiM91C0wlTFffd7JdACoZnx7JC8sTSB7/1qfvyvO613CYewwMxS0G5Pio+7FfeQCnEnLAFz0pNMElhZrEgas+Se4wlQJ1qitTgXz6ikD3lJs2yQcnel8FuTvPGkkidulnDZl3I7aXh8XQHW88VkJPlWdEUGnlTTdTrw1xyFgZRJIAOe7MEzVBiNuZnjuwwzmMCc24iewrISnYISnJyRp9tHe40Q5JEVrgrCRGyxCQF65OGR/pvAtGEMrrSKpTTfd0DzufB11FeCamEzkcj9IwAgZsMTLLqwQQPL9QatgM1cqq2p6JWIhV1XRvtJP/6iW9hTw6OX9Cqnhl11oSpnZ1MS2+qXgvOWnZVusJhfmIoNkaRpwgyYSusFUiMVar10weomMqKTAdGpchQMalElX7NISCwyY0B7COpTRoRWgPTdeJ1BdFsy4qInerQH3mcS868NTx6rEE9iXBSM29Oiw8jo6Pw8Ar47pcNxMJzoOuQUEaM0U8d0A3aWmy8b7L54KDLFktxd9hRNCh8eAaVx8ayWpl0nQ8QhV8Lwp+Z6AIGdbbGKjIg8kdXscTdpNuITBDpiX0rTBjFawCZ85196bVHMEP/4qkkL3si2/tmxflhAt3+3U/SggqLt6DSDjg5TxqsUkgxWfFVVKvK6Y+Ii3DV0QX+IxbEmeLaowA3iVhpfPDksa6EGW4QkFJvVPgKgfzqSIPZoJ8BhBmdDkJMcfuZ7l2wXC9hs7qtZ8gdk6q69WveS3MhwXC+YVFaE6Nj44NnhjD23B3IdQR3mlumLE4kiIOUiCps2wjjTYirURHAEuQhObaJksRZ9VgwSiXd7rEMkb2OvUg3jdHfJesiB+xRHfxiGohznhMnc8lDzSJo824huKdVNY3Xm7mYGjWEdZBLIEoguehJeBL5DISIf7tk6DA34LtGYi8UaG8cnGVIfqv9WYYotBvlzWcXdmiolMOpHX6BjR9Ww0+uZ0JaJJflzY56YH2pJLohBqpAcZ2am0oJ9BcQop0AOa8mNDB2kTpNc5aElHXQaM9Li9Irm5yKB0o0nn9qTadb3ROxgUZRlrCcQX86O9KZi/X4CM7d8HmcrUhErWXwMdueDDcH5qXtwVaLqt3mH8gZ4mKk4ZBmd9yRqGdVg/Wg5EGDlGd4GqVoOy0K4FBlDLNodr9FfJtOF2Ejr4bkR2iJPIGERmJtT6AjIjjeLh0VUA5M38ME0B9vcZYtNoL9+U6nCEDV0GDfPNxQga/rN3GewAqe5yx2yA6KAAyZcOqRy0tZIgRh6djS+NMYhsMcYg0NL1zYMpFhIKWMRhFShBSx+PMc4IfceyaiII9o+XekyVxH4qiy15q++QMJRGHHyCKusi11L7wsu9AeXfkXGqwJZnNvDm66nL3cOIuaZJ5ou3UMSFGNcdbuQFJWNC3MwSnr1sUEO+ajCM36GNnloSlJQ8fjzSQfjvDcaW/Hc/eoYzzyARYu0GfNH572z2dNUZSmhPDQPIeaksp+tQVLfgCRjqPHiyRgPRV76W3UxyctOF8zMkVV5k9DEA2MySXnBj6j/5mOQgxwTd4KKnt//FKI0rw8cWT5lUSS1e5BXNYCXvHbzwIURykjY5727hvn0yaaEMskR3gP3osFvKNWrizlhFAy2EaWc7ZQu1LMZJJIrEHpI6pbpy3CJwDIlVliFZUEs1jxX2uMvxUl29HxSqYCbBVxQnJYWP/0numYwI7V7wjOrIypcJL5hs1Ccb5vA0fx5usBgKRwlufOxc1Kp4WwyDMu9kKtCmjeOUMoaRy0hMny4Nx8v9bKSS7vAGQDjfr0gB7qcs+frMarIuG5ArU5GPp5aSMGe4UJUJ6HlUCnxOJFaNOj9stRLjCT4MtNRo1SaA0FBZQRl1zSiRQgghaAWYeW/uDD8bp8x50fIjhuR0mjLrmtROEmSWS1Er+rxvUptwscLioi2ETA0kN0qX3fapHHSUekiTzuYsizrS369cQkcfZDhCN2SOTZc1EGasz9gkkKRqJyjnL9xpQEpZkPHkV/L8TSpP9OKMTqmbZtr/emfK0J72SH5VTN1pFCKInflomVIrxCBijeikTVVKx3CZxFwfWL+3TS3lDSndxbE0My1U7D8ll7cH2OLZjRuB9IvqofkhckRJJJBBVPdHFG1ystADl0gJTXrMRIB5KTU/ZOPBqruf0QOhObkmLpe7mWB9ApsIl34qPdXqfnllGFpumKeOFRK8YA1YNSazSCm92v6otVgkDUwanLu/8m951VkMAUOcMEwbIbwdVNlsAbfzk8K42AvMQ7TyQHAFa2hl1tTDWY+pRAwXWgX0tdkm7+ytXe5IEiOaKDjJTBRIX0i/LwWKVprxF8wxgmbrFheQoQGD7yB0mgMXd6pseLEVgNvI5Pgk9L506PVeunUtBABggsZQUNdsipQWSFd3aV5m0hZaqomvc828MKO33+zGYUdeiUntglnyUKXBffUx2DXGB1Zn6WdUWW0uXvYHvk3oUv4XhOYjEIixayhtmqGo32bvMGFDN7gjRDSYOD4cvWfK325SJOJQlDHS8GllN7NqGi5zYtmbUCdVl1Rku3cmJwxBFMfs2aNEVLTVT+9s3AcAZlcKZ+KuMUEpp1hyPcmOOylWp4WPSN86lC6y61bVkSORPH1k+eroqacHn9XowBnHRKLaH+z36vZoCBeuOBxdPGYYlLiN3sQ0MmcC8Wz3Ov0VhFl4XC7U5H98sv0lbcNz/ShaH09qOOG8c44ITo53alvCbFAbihFhk1kRl8gBQ8g4f1VIK1oGYhdKBQRMDBFf8vezlDq9INl8++9arcU66/ILIWV2zXtU4fKYHV2DNdQaOCE3DSUwtsSX6dqVCZMbgmuVBEVK8b1iEg0KYWHwrKy7ajlJAkL6fMiD2iThSuh4lIkLquiZiCT+oPmdVFNVrlbi0VUUYL6cY1Rw/Ff6lequ6klfd4fNJUc+0T33N3ijbGVPIkIzT6QzJmDQmy0ucFnBYihIIMQvXoUNJIw3EOp0QCYg6VcVV84jlkVhsp0E0B/VqupyJtAmKwxYeJQuwV0FwhYo16Oqm8I7EbzUqd6Bt4Cw3EG6jVBP5tIkjAFeoWpDC27M+u6zDBJeB3CNRfE7WNRhHr3BJyOJ+fDRiVXLIrj1SVzCVJ8RcVl5PhxLwIPIg8bg+Yzkhe5UcDVVklyrhoJCcjBDI6ZHrY72UScbUkYo7iGpvWZVKKOl7n/bvcA6uBBMjaVgtgLSOpU0wa8NQFPxUMtC6VlcyDRA4UpodN+ryVe6fptlFovBmCNmViRJIoQfOzncGroHEUdIdNKHUKGE70Wakl1dMXp02rCeD1SKTcmxvmIOHQZcRuSpuoUR6aNYSFz70aSZzU3mdIJe4GURC1dny5h1oTT+EH1VJen3+9OWDCIIfb2ZauX8PYYLEBE64q/TUSRohjT+qLZFUrKaJK53b5oeI4DHkwlkmIeOLO9wSHNQoj8mrffooHJK/QubSjD26BoWdVDgatUMiQTnePFex0spqJnCQpG5iEyKJue3U3vCFZIiAt/NtHwygAtVW2h9lJDEYH9veTIRhYd6iYtXZS/ImKKEoz8vGIIRi20vCHExZl1Omy7oXgaVxN6zjYpsqfSBXW7jG+L7OcfKs5ERhx0RlPGSiT0M5+rUQBnJ1IQxG3hiETf/x6k3FG/BA7B4nTx0DGEPZcRGx0u5ECeCE2yZk5WTsvJZMiGcITTmReshcoaYS+uHPugYwQaQKFJ9PT/ylc6p2Feg3eJES/JBu1dJ2rVLRge7mROOdwkUkwtvJ3nzsn+yxk6p8C+Z6w+gTfrSSyAC6yR95aJMnZZP5m+1So7lQaKgpr088WC3eothaC1dOvnH5LuwOD94QoIS0eLFW5D0Xf1eRK2WCxgHYAxtdGnOzq/KsBEWiE9G1AXNSSwZ3r/YURBVPx6JqF+GlTcwg0iN5FwrHQwsstB8KN5W8SmyVIJx+KzHG97wa9mzsqgSw6nKEtS9IxkXaBTC2pxPpFuO5tK815yMGOeOEFpHRw1UxqfPZ8MIMfD7PsU3D6lOokl0ATfaXK+Az6Eq2DECTQYIZbzulNQMWXUYk7Ua6011eEHV12xZz43YepY16ndgkBqJawMDj1Wrac+6YG1aeOTSHlKvPWg+Ccab9ss1CwoFOfBMoFoRefzj1vMnWHZfUgzhtzsWFrwxWXt5U7omH4njTX7ASU9ryiXx1lORkoB1vQhxV2u1YkQrjjDqgfWDjfBF3SPU4WhdtIyebb0p7w6rOijOG3GIJiFzfG17oWVpRkGGfYYRSBBdNw6eu+lFCR9vVG2boc97Kto8hFIFD1t8B+G7HYxlGg0s23jB3CqbbRgdxHYTdbjICnPA6X3CCrEMtwMxbFq4nO9rEiIPoRsN/NRkE++2rCLVEHM7U5woAgvRD8C3OZSlkLWdqA5VybTpn0DEMHO5i86q2QBJPLr3NVfpCYuVcit2+LiKbxblGL1zK0dWR06b0QJ1EKIlgdHLZduJ9HpzoD+hb14BK13NsNXLt1Hdv5jOF8JjxKbLXEq+HG7pcLxBkXDkB11H1GCJxOCudHGQSAp+Ri1k5tzAbSEI4i6cE0y2RtYZIyhLLX4MieAsJIkE4PnGWRBxp4SyxAMg6ktG/DkgNVfGRqzPG14yE6lr1sgc58jkNwNLgIAKeYwNQ4qF04q3JmXfLtdxT4s5B55j1kw3KZwtqSJIzGA2t4zbYzmqhSMyY7xfs+o3C1iedPNoSAi/Hyew6cmZIG5HwLkIXbRTaU12x2teXdZuq1sU3WQsRlcf23UFiNZb/+qgepj5GhLXSRuwQtsXSuleliK4SKqpYLjIrHSsTR3L0OnECKEPMPKhNAZDmsGA2h0scS5Vvhrv7ZAvQn/HbbqsFw1GbV+TiyuHwf93UIyVclLH4Mel88A5Niq6b1PK7LiS96ofK0JtSLu9Uy+D12yXERCLpyJG//IbsKjST5KCUmAnB0KkTzxoUIlFkUhXVG6lseY1XDqpqlny4PoiSJUqSqorqZ1+8bJidnolHvGFoQ+HGQcNwVGIo3ESzVKgKotfxpteDTJR3qR0k7zGhS2raIEkIapIEIalOUp3TgarkYBXLeSkbtYRBcXTNOVSc0v47GOA1gzRd2pW8Jn5oXb6Zka4DtVwx2R0+4kNUrwZIkvSL64unTWVPtM46iez4jpOFLGBOq7zcG2BE1UtB5KN0yjmjZT2+tZ/6tFIJB8xBdXHT1bxd1ZvN9MmwhAgDfH9mZhruuv12+PFNN8J9e3ZTKh5Mq7N502bYsHEzHLP9OHjkWY+CuBahVA9GP9SPU+JNBIwfzH11y803w803/xwmQ92YzBoT3m3asgUefsoZoY3jYe26DYJsypgscbj4LHFugBt/9GP45re/BXvu20vZTs49+yx42hOfJMO0XsnETLzsQIyLGLUwPEG062+4Hm6/9Va49bZbKWulphjCZNs7dpxAqVS3btmcVCmBLXuzfT5zDlrR3kXRZqd2CQni8h+MLbqtuqlqqcHeNSfbQ7YeYvGswYk9JC+FKeeEqyQhAdaoxejYmEg6LkZqlj8fQ659pYjoEmE6dUNGP1fBM5J95KTPiXiaNK0Iop6hTtxNxWFzfQcQ99gbY9NWNjM9DV/6/OfpMz0zZdowPE7oaeOGjfDIcx4N5z3rObB+wybwusfFjkLVEp/g+5WvfBk++5nPUDb5tpFguU998hME3yc/7Znwwhe/CtaFtpx6oEgQC1F4gV5A7r337YF3v/d9cONNP8rqu/z7V8HHPv1ZePdf/CVs3Lg5b865qEKD2Jia9AGJ4Atf+Hf4/Of/nRjEcteOE06A5z/vufCsZ55nBuOh4f3zkOxMA944ryLN3HJiB0qpI+MxOMRaYKoYf3fWHnXW2wEgtzWijcB7mM885TjYdtSGpJ5AWgBNRFIgkVfJwH9QXXXKGq+EGREVXDTiNEo2clcx9lQR4JjSGuYXOvCz29fCj25dC7vvG6dna1fMidhmAotSUFQ/Otc8fLryTaqL03WKxLUrwS1SdxynjeHcSnzvvr174C2vfz18/8orYHFxwUg216oiICe9+ec/gx98/wo46+xHw8TESh6v2CydaGew/TY1OQW/+5Y3wWc/+xl44IF9LdU6O+t03X7rLfCtb34V1qw9Ao47bgfYUBOCG44pMJ/ZIPHe+Lu/B7ffcQcYVhE/U9MzRChPfurToTsyFsDYoRQ8/N0JDKzDv+Vz4403wBve8Ntw9dU/hIUAC9O74nLxyb59++B7l14Gu3bvgZ07dtKZJ7yYWkFK9aMfl9Vo/0rfBVOK9p6PanC3SrYdg84JkQC46D11knqX2+0ccfTZb88HoM2kZHKPOPX4SCC5GmOIQ9WnWIP41L2mnhR9VSJObR3KxZmjJyNP27dUrwRyaHoYPv7lEwNxHAG77puAX+5eEX6vg4NTw3Ds5oMw1K0jb/YR+QMQOlVGIB01fCFJFMptBUIYTpJcO7ELwu/7A3H83lt+l1KKNqZuACPT2yh1fngVEwkmnKvE42cP85menoTXvPqVQWrcYqp0eUX2MkSysLAAV115KTzslNMpu6KFWeWYSP713/4VrggEgE8w0+Pznv8iePFLXgEPe/jpcNvttwVpOA1T4TMUiOPhp55BxEAIi1sgJKsKEgkSy4UXfgze/e6/JCbR7F9kfcWDhEm33HJrIJRLKXEfEYmc1wKGQPLNWknDZcnC0iNTpBsE4qOTg8+kl1BWFhngwOXdAg79wSKdtUggLjWhOq/IIOrsmUIgAAC59wMgIjkYCeIz/QxSzlYjOaK2YjxALkmS3ECGaNgpZ//Qlx4aiGEEymvvvnE6FvmEIw8KsFLwJLlKO3JoZjdJkKjrQzJCtR0nBKKcHgH8P177m3RQTcnRtwS9+rxnnAfnP/vZlL3xiMDJbw26eFGMiOSuO2+HJz756XHs0WEQCrz3ve+mc0ZKwsDsjuef/xx49nOeC4993BMosTTaIpSDF3I15KabroMnPeU8GBoaEumRYPeev/kbOqcE6/yb9/4jPPbxT4INm4+E407YEeyZ0+FrcuTB7YFYfuP5LyHioA+YMPfw+8orL4e/e9+7DQFY5HFwfKjvrGB7HR8kBJ4psrC4GDPaW9ihdL3m2uvggudcIHCoMgKJ3oRCiij+pL+FwXuzTOFZhVcJgvPXlcR00zMzJAa6mIDPMLeZqVmCZgfPhvES/uA0FU8MPamANxT6ovkmE1PdzWVaHghRuNi29745HGdUBUGQRF9KcCAqE7t6f/7LtZE4Vq+Yh0eevJv+/uFPN9O9G27dAL9y2j0wMtzP+hk1NukLh607ynuV+m36SJKjkkOEeBAf/vCHYXcgjvJ65ateBa961atjLXw+uocXv/Tl8OY3/Q4d42YB9uMf3RA+NwaufRorjDjG0MyNN14LF8kRat6l/jzjGc+E17/hTZxhXQKfnvzUZ8I9994Df/++98AVl34368/e4Cz49kVfg1/79QuydpEw9uzdS38ed9wJsP34HSpfqKVjjz8Rjg3q2R2330K2xO49ezNbRAMV0Rnxnne9E6Dg3vgcj6Z76SteRQTNZ79XUWW5/rpr4V3vfDvs3rWL32RGTdLyAx/8ELz2N19r5sJeTdHpI7NuE6v2vYSX+tfc3FxwrswSsY+uG4llZ2enaV/N1PQCrB9ZI4vdkPQxJ5n7MK0li6ROPB8jNWj+ir5Cw0Vo1M6OREwV0gaZSxAVd8BJojBNpaMDSdsZnJVRJBH2PDARq37kyXvgzPDZccx+Iha85ha6cIAISFWr1C/yHciaQV8/fYmGrev4LEb81pCN6+tf+zqU1zOC1HjlK16Z3o9h5zUh11/99f+FNhXjzsChQbxN2BYGCH/h8/8KJX/YFFSl3/29P4KR0XFaNV9Y7MN8+Cws9oJBvgne/Ptvg42btzT6ddX3L42t6YVnHeY3k1UHAucJOZbBdCGamLX8/uSFH24xxj28KfTzN3/rdTAxFmwXDIv2/GEb1MOpp58J//KRT8EJO3ZCiUuYPFyPmsukRQQGZP3iUtZV482YmqWdrYVwMEiL2fmw2MopYbHAYoAr5ilGtRejrSsrFjTeqHJm86MDaOqQxeWMeJXfrDcq4K1bUD5IHGL0AWXxkOyxlHvKyYSoeZk+NeSgGg5S4sD0KHzqGydnKhcSSRxYbD9F5HLUbk35chcDgPAbAYIIaDcgMeHwAvK1QQ1okx4vf/kr00aqUFdf95YIoSGCP/yUUwEKON5xx21xMlERQPft96+4LJtW/Pzmb/126CP2rU8f7FtP+okbrkbHJkidKq87brsVwKAPE9smsjvw92233wo33Xg9WIju3bMLfnTjdfQbj1gg6WF7E8aD0vDbdLS2zz4veukr4UlPfioTBuVbC+sjdY9+u5oJBb9Xhvbf8c6/hhLpkTi+8p9fycafvkuF1qpXJW76FmzN1TOOm6tgPPQl7dXxMZPNyPAQ9INKWGUNRpu7RMO2xpQjJ+KInMhpQpfkkch+Rw+I3NNnGRGYFQ3n4v5p71we5xTeGx6u4XlPuxl2HH0gA5EvvSDSBhJhLyDvYiCSBeLIzJXxs6jfhIwJERHZyWguLrQ1Nm7aGCVPTJwsH13zYQLJr/v27o52B47z9oDQ3uKcXGed8xgm1j73ZVG+exKBjG0+DDOyFxcdjVDeDA085/zz459/+n/+OCD71+CmG66FL33hc/DW3//t+OzsRz82QtN+ffoTH260hQ6BF7345bKRJhGDo9CXHkuSWr9rWiM67fQzGvVcIsdPZAAYwJubC4PODrOltImmcBqAKqshYhdjcnPVOg4Ggu262ogfbxfz/ICm265kSIJPyJzuJ9WpLM8xTN6oYFLSp/fyelwxbMyU7uHozVPw4+DFSk0komC1rkN75oCkFEgybY47c9FIstWn1WZe2a5g166m9ECOrGslugBojUTd+oqcOBPxJSzARZUlKgr43ubNLIlUFbYx+y4hwvjEitjvZu2JF2M95//6s+Gib30r2Bd7qM33vucvoLw2btoCL3rJK8GZTJZqE+F58+X18FNOi0YxxWkJLAi+EvVKDAv1yIozSD7m3F8hm8ROKS6GoiRZsXpNuukFGJYAIJccDVJxS7F47g/OabfrAlNchO7wMOgaTK1z7yXURIkjvl7+9h7amzMIrX87vW9VLX1qn2tHIRuyfudBapZQqkyAqlRpRu6quifJkB07b0lahbIYphH3Zzk7hoRULIqpCnrzqWFd4NzHnJt1H8/6AONS5OUb60XhongYaHmNh7UQZQLIsY49bif82V/9bdb+xAQnv1ZniTKwEgOmpwp7IDw79rgTElR94rdY57v+8l3we3/4+3L6Va6z45km73zXe9lN7CLfo2+UcugAKNHhiU96GofBe47OBlnsZSYEoKHhXscW5gOlb3mRVy6sAWUEAgXvkjslkbTjqEZngNBFig7pYvRzrwedkWHoBaN9ZHwERrpV5Mszzttwd5Uc8CAunTQwSGs6HAVFLkmc8Vw5oYLyhKl8o5XLPwWoDk2Nwue+fhwtHOaXuIzte0ZdK6NWc7IDco2mua3h+OOPi6Ep+p4Sg+XSylDUuMTirOtDJkXOfvS52VgRIdFeAafvadBhXQ65cX3noq827iGBgC+YkASn4olXH/nIhXDFlVcGz9mNRCjjwTg/51GPgXOCasWSk1MbxQzt4fX79+xuad3DccceBxBTJikxeD52TXIbe03S4Nn2POH448MayBW8CCvrUbxQ2mlKhEabzvApJR8L3fxdnzFAnpPhoYrOY4G5GUowPjqM2457MHloOrp/uwBJHGZDLijFdgEaT9IvS9eJ6pu0HnsOhjCUgKKkgYaXzDd64cgGOWrTNNy9ZyISibWNcsISkaBl4mqzSC3LboyojUs8tutmpVrVrMiLxSuCf+4NyHfTTTfEfitscM2hsatNGIUrJ1vVDP2GJP72BqP5phubag+us6T3BWGp2hROdM7Z54RFy0dBSrABZDPQmg/+J9tpCT6hDnT/llwUjfmJ8TGI50gagFFITZ2CIFUFi1sKyFmjcGFHShpvu0zQAj6DUcK2vEz+t0q14YD5/UWWpjjWB8KayNRkWBwND9YesZbycczNz2OEsuV+liPqXzX4gggGiTIrR2jAHsD6oEAmiJf0fRTfEY9BFokqthnIxSzp/lW1ygLouJXgcajhaef+Eo7eNNXSIy2FDVQ5odBXIiD+0xtFTl0GcjSYGqC1RgXwx4lq4eKuPt7jUslelz/4g7fIOFPPn/iUZwRpsaUYiTMwtLA0SJMNjBERPUp799wLdnZQGuEaiyJEVG40gloOQXXBcC4/VSAQfIb71FGKkPXmOOvJtJyDaK8V6AnC8lgfyD51Vc3N3nWn7dZiuPfFy+XruBfEQY6PRlhn37m0aGfd9v3I3ISRgYT3kDF+4CD1DRdVF+YXgzdxmp5jtEXaMJVd3kgVGaThqrGMtqxfznbKDEUFROR6FeQPpbRQi65eJ5Tx+QCzng4iV2+7lAM2Si69UziTBRmiX87b8i5TWczdTHroKx+98MJ4yi2NJfwzMb4ieHxeARZoJQE1x6OSykE65csFyXEtfPrCD2bl8J8XxPohcXxCDPzNC7iiaPIJXFDH3lAYuvcJaeWkG0SimelJg5r876ZNGwIR9Q0sIf9ElVHHoTtWnXyEOcqOUqkIwBA2GDjH384tbRL4JMh1/Oo4WQwqFcJxcWEh0GiPFgdRenTCGsj+g1NhfeSBINy6xgbx4ikRUawH3EAMTYfMcI5E4PMOccc9QBFTFXNHyR7qeBaB+p4jQnuIgYs6stoSSd7mbb9YGWyQIXp/7/4xMLBIvgWX8+JBMFWJUYE5RtrL1lCtx6Xxa38hPYqAwN833HATfPwTnyjaxPWCV5CtYeKY9RFYwyhjCJGJpOgjlBrve8+fx1e17BOf/LRgND8VvAkINc0bYvTx8AEb08qIrTmzbHS3mU/TZbw6yjdUEsvWYRe1Jhe1BykGNkI72m0ycgdJWY9jK4SE0WLbC4DLC5rSpEIG42d+Zo7ujq8Yp3WPHrCKjoSC50rKEWxzQdyFFUzc+OI2xOnxmVPeYJyz051zkyhFfNL0lczJ7+yVSCC2kziiB43NUvcqE6aPJ5byeFP7t/1iFX3KiwnEG5HaKAEtN6MUqVRVcpDNBIepG+IQRmAzFuEHXah/8Z73xJL6zqODEXz++ReQt7PZB58TSWRSPpUVOwfjl976+68nj5K1ITdu3ATPf+GLA173ICFEScTJ0eDiHnwFgMJfRhK370KiBucg2V/C/WNerzR/zml9kOGFkniMQQPLwzwoyBsE0bxlmFUL62sQFEsPPfcFgzn6Yb2L4tUcBnoGm2NoDHqLPRgd6cJop8b9IIE4/MGwfhM+MA98smg36In7w9/j4bMGrByL81eqAzJQRpKENE6jeZ2IalfHSdIBVJRVRDlIJdy7MkTvgXfH+ZxVLnE1CNfcb/srC2ih8dbmd2o6pigCiBLXxTqEOPbugTf8/h9SHFNqx9H557/1P/9XthW1OZbcBrRdoP455q3ve/dfBON8dzZGXCF/x5/9JWxYt04IpDIGsPzrUlh3TB0aZ0wH4kwErSiPPtWiZeKFunxnSCkiEojuHfGuyfp1u4qv0iJxk10B5CpWO1MbhA1L7TbtBbVqLqiLI2Pj0OkGh2+Pd0V2go20dsUQjAZYYlREt569mNqsYUsA5/5g8O4Kgz0miJewcOIXQ6E5iMeRRemR3MH52PkPPS2IjoqOKhu+pVtpfRK1QBtcIapj5tShqMZF6cLgut+oUoOuvQ+MwTFh8VC7HKWhZU+GazHN83cl7SXpZtDZt3MxxfWp6emCOPhC4njPu94N6wKH78WXPPiGsuLNM1BRCEmx8vCh9/8DfP/Ky/L3QplXvvLVsGH9EUGfXuRZoLDuTmJcKhlIPKcYOC8IqtKCqpOXRKYnODnjaZIL94/4znCUICnrO4C3nphinLX0qc4IyYnWAIPo4bCvPE4LUvsykQvzwSHRWQzEscjJvwPMFvsLdDY9wm4hqF/dxUUUNUFiVNNBtEzBwlw/FLgXhvAM75Hx8ML9ob55SEgEibGYjqhM1f3Izichg4inJmC0E7O8Vor8oo4oLseTcJWAavje1dvgtl+uWRY4F199dBCTNTx854EWqRF1t+I+f3sjFSIjMCVkDpMQNcTxpj/8I9i9e28GH4w9+vP//bZAJBth0UMhdYyzw6d+ZOqk/g7/feZTH4cvf/HfIB+Sh+e94IXw+Mc/nk4k5noR6buSld36hmSeZD+Hdx2Bs8ts+VK2KsJPrGiqsxQ6Xw1FSZEnrk6LvqbDoIjKxKRWh0gzq5NlROIio1j28oX0Meohvo1nys/OzgQjfT5IkCHKkD8cXNUj3WFO5BEIZGhoJECwF5x5w1vJ9ba4cCgQRbDch4EoamY2rDAurjIqsIeM0wml2JxNleinHJzG0LZGOHsSxIsSublPEsO2IwkdlIB+cvt6uO5nm+Fwr+/88Cg4eusMrFnVz0WAACofCxhEhIS0CdpJXHozfgegWz7//l/eD7fednsOnnC9711/SYuMPR/Rjcfs4y7j1Gp8bCSISLTPfPpC+OynPw7l9fwXvgie99znM3F4CZSg4cm+erUGkyjhyAKK3K7i/g6VtNF0k/rVbMf3cN+ITwobXWgPeWSyZs1Kj0JIpA3mnZI47FOX7A+X4Kt2T1s2xHSZOV2GhoaGh2H1EesCYfTInQuShadmr37QoBbI9u0OdUdgavZOGKKHuK96JABtLFDQSLDwJ6hfdd2BHGQ+2SFONjo5DmHXPEfMoJn76wTzq954G70hBtN7S0AGqFfeeBQ8mAsXDa/58Xp40jl7QPfLK3diVUkn2pvxJZVGx5r65fMGJIYMa/nHD3wAvv6tb0t96dU/esub4PiwyuwNovM6AZeMTAFh6gSVpM5kpAN8+T8+30ocLwgG+fOf9wKRHAbG+Ltm5RUcZ0ehpRxKgCjbSiPhi5z2nD4o822IJFB+smnTVoACMhjmsic4CzZtOVLgIvaNdTNFJumiswDv7Ap2FGZl6SgOhXtbjzo6jiNXz2INMOhK6z2Q9dMXZXSfynB3lKrXJOZVB9c/Krj7F/eQGtpFEA6NBL21dyCImm2ho/PBcEEAdmB44a6gpx0BeXSvjx1XxCW/eQUxTT7ZFZqbyYlgdOpnqNlYj8DzRoqw7pLlVhIquWfP6uDOHYEHe+GW3CedsztDyoiYLhFIXILMMryUkkTf177z7ws//Rn4/Je+ZCaAr1e8+IXwtCc9MeGHTBW5jiXkI+Os3mccVyXst799EXz4g//UGNuv/dqz4QUveBGHkzs98bGQPDXHRvVFAjARyi5JcrendjkJdsoQr3vEK7FZ8OXjTzgh74Tg6o3XXwtPIQJxOQJHjUHsWLHeEQWuv/46ePMbfgvMVND1iU9+GnaedHLOaTIiaRcQxn3SeBI7q54shEEwzhfCeshw8GLhouFib4HURPQw7js0F/BtKhBIZwd06utg1douHX0Mrg8H922F8ZWHgphZFQjmfuh0Zrlp5QImNYseWsPSUoSxZ886C3ueIDWA+bmkBVKVw9tQjTQgp4AIDRyafvDEgRdKkYOT3aBm9UATOWTRu2AI3RBIGfKfQOyz35/89KfhE+FTXi970QvhZS98YVQvqQ5K6arwKTxH5jLmGdx+x63wt7StNb/OPudR8JrXvBY0/gnxvO90DkQKeE3rykiJmlSPmJmnWELH/4ASKuUlrmXdnZgTb5jzuDXZ87bdLZs3BVtqS5AYuxJgQvVXXP49eMrTn5VcuwxF7gNls+mrSOK97aEft97y88bYcRfizp07EwZYanBtyG+vdrM8wlWJwyNezJPkw7WQ6akZjhLr6dxD8ASuhCNWj4V1kPqu4B4cQTkCw6MLAYKzMLRiMuhoAZBrDsLkgRHZGeZjR61dEFddY0pK4LI1hxWAEAmJ+XI4dZJKulrtXNpW5VTsOlhG91z64oNh+hD99Nxk3hfQm0mitbkJ43yFH1/88n/AhZ/6lHmff7wkEMZLXvCCwIl0kVFgIwxEvXx1Kx+UnjiMAN4Db/2j3ytax62yx8Ob3vg7BF9NgMFE4qO7PDIdgVsfVZ6a0xvp+YssIcT6814ScydnCW2c66AXrEv2SuU7RNxPe9rT4eMf/3Dqr0cJcg1MTx6ixAucShQAMgLpRQlSyYa5b3ztK43R79ixI0LBZ6LC54IAAA4LIzJNIGkEiNJTc/ON5+mUL5QkYcyrV8/CfFgKmZ3eCPOz82E10VOCYtRFpye3BRiuoIx9VEnkhnJUFznGJAZHN8YgIGTDjJbTbIFsqyhhabiBj6EGkTDi6JQ4qpiq5b9yjQ0tUB/pg/FGnuONKok36gD3XeOTeJtoOg667YPJ1v7lg3mIB36e/IQnwouf/3w+JdfbI9E0YUU/xi1h5Ch/uA/0cfz9wH274A/+8Pdov0ZSAYMNsHEjvO2tb4UV46NSj9aZHBqV93F+nLYrXBxtFfTYoN8f3Zu98OkvzodvDLmQT1hR9uG+7/PHBXd/RTFai9TfC57zHIBi5Egc7/mrd0CKRNB5ZqmsUsRLLNvll34Xbr21uQHtmc98FqiylLOnxJ0dDCaOBkuLNlAiDuwSpncdCYb60FA32CFdGAu/R4N7d3x0FIaHh/h++FQP7J6GyYNhraP/i7BwMg5z812Y3N+D+3avg7m5sHQ4vwJ6/XHbReGgdcxP5aAfg9DiVktN7aN2iRCH5ppyRX0smR2oBhs5uqhhJ20/AP+Va9MR02HwixHxc4JOfdZAOg2uiwnuJCDRBidiapz3f+hDjbaOO/bYoFP/NmiKo7SzsB93F4JtOwb3Sb9E0t0XiON3/+D3YwxXHEsgjne9852weeN67qvu3MsCJb1hXl7aSB8eQ48XEoMHhwmhJ59F2SKLHyGM8HFIJHVgMjUSygKsGh+GC5797IR5gnpXXPZduPCjH4hEoiE7zvezQM89u++Ff/qHv20omJh58VnPepa506Is+Vwa5D1oIRwralQ5AIiRGSTN5UhvULUUFw1pG/YidKvgAx4d7kkDKB5nYaG3Kbh7D8JQ5z6YnVln2kriWw1IjX7VmJ0UVJG0sugHl85aT4QrRx4Hw4uKmlx7pLsA27dMwp27VsKDuc46eTdzUUhiO7acmyLSZytz02/t1p777oM/etv/Zt+/uXAV+02vfx3tWU+2kyV8SCqotO+kECK+voAu0zeHhUbNPGKvt/zOG4ggMCNIPImXO03Pa3XReg3KY1hv3CApm6K7FBL8MxxUzV+WB2tlcJ7OY6Rs/DUb6y9/0QvgsssvC0Qs/ZSKPv6RD8KVl30PfvsNvwOnnXo6KX21hMHvxr3sQfJ+6YtfIPipGqZ9ec1rXpNjvzNzU+hU+qf9BmglKUatgnLQ8VD3OFkDpn9inKwiHGN61o3Hb/B8+COKlZ2ko7qhAzAyGgrX06RHv+L5r4cnnHs2AY6SqYVBd4Pa1XXehIW3d1Bsb1BQpOcDhGQWriA2g9ghmJTh/V98mEnIsPS1emIOfvuCayJyZhIwtmX66o1z1+fKqarzr/qt1wXbYC88mGu5ha1v4MKfFHn7X7wLrvz+DwaW9ebfgc+Lx+/4k7fBwx9yctajQTXrpRvD0A7pSC4xzQ+mJHTr7XfA7731jynRHHMDIToDVwzKRGLGfFj4iQ4SUw7/fX5QS9/8pjexXYQI67omg6Mm3SgulzNZwjU5optwGrOViP2MeNsNLtwhPGIijGd2dhbue+B+GAkeLFwTQZUTkwqCJNrgcx9R20DjfCTcDKIT47KQ0kaCHjY03Anu31VhVR1XTodh0GxYbmk7qx1WwKVkC/JxjaoSNxSdvTa6Kw521fgsvPTpPyaJt9yFxPHSp94YY8FabYqoF9cCWKNW6W/Q/RP8/WCJg8e29H98Qm2fJhWRaKmyGSK36BjON9FfNhqbj65bpzSulfk7Mj2BG6qIuKBGH7Fd+sFWOfaYo+Cv/vTtlHc4uesB7CIEZkBBVXF6aiqpzZBUaPx+5nnPgDe/8fUQWagvxgkwwLhoe9RC/G38INwbHxsjL9bC/Dzr/ZQCKqhWuGiOBIMOhWCXhAJrwxsjMNxZgP7CPjiwL5iJvSE4cGBNGNgENAMTB3y39CJpxeJOVGIpfoMBn1cgCeISJyAi6cHG1YfgNc+8Fo7ZNNgmOeuke+A1z7oW1qyYkxptVseUaSR9EnEQoWQbfgwG+sGc+//lUhulrvvgD6eNFvyJ9+VyjU9OTfbvqq28jjvaU33iqD0lFPlsD0Tyl//nbXDOWY8sOjaok6mjK1dMwO8EtfRtf/T7bKsMescPVp34O5f2A8uZCyUi4hWmZ6q6nZjqCtUtdArRZqlgfnQXFzeFgd5Pq+djQzMwOT0TqOoA7N+3jSQYEgoU5gEYi8iDb0gNq8n6GAfkktvRFxUVBJbWTHzUGSwMSJI85QbYvW8F/GLPGjgoaySrJ+bhlBN2h3H08n5qG+UgjALbUMXNs6K3/+1XXdfNm/+NjVlu3RjUUpfq7korqjKY5xR+sn4dvO0Pfhd+cM218M2LvwtXXvWDBrF688dpp5wCZ5x+GrzwuRfAKnQLa5loIBpJFHknr2G4AgndYLJqv0w4DNoarDpW0AueO8xuwjFYQ3SSMapcbuvJ53ro7YWFMEfrxhZgzyFc9zgEnaEtgbJWAga8ve7VF8DjH3Mmid4ObsFEfY7sED2APkLL8CcjKeJn0ET4hsBMK9vAXCzWnoBuv3Mic6AI4SMQ1RjMqASiTr+cRG+0vPTlbZ0PAif17cafpg77Z1OlbaHsZS5b+vBGZ1+WGDzKdzxEG42GwvcNP/oJ2SaYpUQlNe5dP+20U2D1ylVkB2BIRzwYSDg3Z4/v8sfJN1TGNm3pfTRCfFwg5Txi4umrjQ3S5a22s3OzlKgPmTFmpEc7hGLIPUd/oAGPBNStesMBxUdDBWugXwUKCoPDXci+DquLi7MA3U1NoBQz5ItH9HGZszEFymX1eIiro0rYPrFv5igc/h53tkkjeVqgrAqwqELfMWQ9ER8U77b8hGylyml32xEvq6ulb+1vHCYiF8X4T58RiW/UffiXz/49rFhZ025iXZpvbDF8Hv7wh7PtKcShc00uVad5yrCGyhj1y7esmoQrNYGWqwEXZ386WJibg26QFqPB5kbiRPURCYXUeSAPBWAWIJgIrQ6N92BfoJqxMRdcu5qErCOr4S7voNOu+dRJMMQBcZnKSJG8h+pZ0j+SCE7hAi7uV8e/1OUrNVkG7WwvBoPZFX9FALJ8zwtHj5Zh21mxJSbTL4WifsBvaBcJBaVZBPbttQxo0ueAMlw3qr3OLVNf3kFv5LjES9BuPTonUThWtCeBV7jSScZ4SBF7p9hCtZaQaZH615SZHgbNgG8fu3zZdRAnSRvIPR7WerphwRCTWpNHCwshgQyt3g8Lk11y2a5cjT7hmSBy1lLCCUoPmjXanJJmR62xnVQu+yzVkFA6m3Tzh+4J4UM9qzwCuOiNa3Yj1e3yEhEnFHYSTq0QZLgWSGWQLEfVpSas/WlWtfmdJtSlPhR1LUsQ5aVj9wbRfGQ1wmyKEBzX1neXVypueE0tq/F1HlOi+jobFKE+xag68LKdUP9L2+PSMnE+wy3XEgA/HPhg19AQ18VCXEbF/MxdXD0PD/F4jIX5BeiOd/uwepuDu+4eB3+oTxnxhkf6MEvGuRcxaQG0fPNskJfSo+hg8VcS8GaynNgOKi6QOKo64wSunFFhQnEhzAGkNRDXELPUqpd/NPufT+pLiaD2zxRUyHCqLaJD3o43f+lXRHXXhKoDPxDabarVYc1MdJC4bMdeZHtGUqVjK0qpYhc9K5mjKo6fYrokMLE8+6+i/e+8AKxpIqzGka9rDGIo3kBoKaYESxIZ2zu8GDobpAaGluBedPZoOTqIiLbcOj8C9aFgtCwgUg8ZkQjg2me72QuXdyjrWDaKJtdPQ5VfzoPdaJNerjj6VI6ITjq4j93STToM67TASHeN9yIhk+HSEmoAdi0ECkk3gLurJPItgHIl8vumumAeJuQz42pDggE8feDlDSXF/jirIilC234lOZmeuJw4JBq4lsR/XgwRzntmUB0JyHEUcWSgRlpAIY1zqJgxRB7HuOABGip2O1Xk8CZ1PfR1bmEeRsN6CNq+uDcd1z/QgYDjGB4Zge6BfRWMruqJlMi5lkZfZnQS2zHD8pExJU4s4PUyI3Yggy9vmRcoqXhwZoYU0dX1m/qcNm7lOxyzvdjeEBJ4s9zBP2rKBCiTVqd42+SChBjCQZOrtGOeObOibPBSyiWkzHiztwjlE6HD8jDLicq8IX1WxPI+lo6tpB7kR15wf2w7JjxfPEo+ZucX3qJwIRhI5K5LlepWayeR1U5gZFfJkyAXCZMxV9fCcHMNxeJuO6Hwhesf2PbE2Dgt1Pb6vM6DdghH8vaJDXdXj3dgcj4BoXWhqiBNFYsJTZQ2ygkCQ0wuq8a1FWtp2CpdSS2ohHCSHaCqlHpKnJxZrulo9BCgKARURNvVX9RHa5f1lg5+Ua4n5TRFabaNzINBVMPfhRgtVC1alhKgEk6uZVwsVFo8UUaZSqp438hVg7wQz18x8bZSh8BZqnMlcToXx5i/JwRS25V+b2DsjC+mBnusHScHlPxbLp/PbKgOMkaTSxKA5GjwWX9LVIx4KJ5SZWCYPK4jhFHRAmGwyeuajozrdnoHYArWm2oGkZ0vQO+Lxsuiad0hcq0lKDrjtN4Yos7nEy7I6SNQ04tRSmiKUT7WFawqoXXGecys45qJy050LajqeL8ETae0zwuaTYOSIaXoW6VmoUkQ8b5LkqMyv/VZfIeA4XIEycq4oies7fNeDzx9wNFHjeqYpcRVwl9ctjPUmQa817M0wNCBSxKqNk5fl/FG3Z0NHNEtEeCgJjqzBjsT6Zfua/E5bD3k2TqNmPQZkYIV0hD3uqC7ORBBB43yQBRDSBSY7kruoyqIZbqrJobhnn1DsOSViTRLJlBMhssGlgbnGmWa/mwoeUd8JVahA409cFlfmFu5mHbGBlFkCOwtD09AY8nE3henGFIJ0M02v8QqXPKCgc/teWd75zKEi1q33vNKJCxreEuAGsNGSmrdVU5clgAt4UQVSnT1PoWWsfOEVElyK4mrtWLJ26l4U5UO3bIuiqvWQ4IQJrWJJjaSOLJEGY96q5huNM4ryTDqaUSIhDdeB+V9NmidL9kgCg1KkLayq6A+J4wTE8eRHKP9+5gXy9Oi5QKGumPIyYGpBTawWlA+dkbx3eXdAKOX2zcUCfSVOn/LlMsrbKaHMaWt9Iz/6npJQnhmNsLtUIDI6qp1OKjt4ov+WAaQe7/sE0hqqBPCkM77jNijEpLHOjlDti7dA0hWgCJnIhpTr6EMF8k09bW087yMtxZkohxU3mlsHpeXIwcqPf230kQcKgW8KgXsKOnX8cx73hXqo9pi2aTzRl10JZyxQ33gbCqVIQwnYfk+zlUkAoMg0Tb10FDX07/m29CO1ovX3Ows2R/IkDDEBDOKja+YIFjMz83jiVMdyM8IKcHrYKDn3eWElSGTQjSj9LwNGmIRqF+Mo/XyRZvWElKAsjNFoEd74tvqgaye1HG9l+KXnHE8VIZjl7tgklfNSAP5Jq2v+HamJwb343PIypl7ShzRIWDGUiBMLfUhXPgoaE+JCayZTv2UM8TpqOwGgYg0qBVxec+ENxntafHNM8E7lZouzkyUIiDlnRKDBocCE0aOP1FEc0SEB0jOAtElvMU8B7l97jMCVecHfjAwcdXq1bSCjnFYeKIxSo7pqWnaVdjFD8a74Cb+fh8gRxkv2FdnncwxN02sNwUSQPL7+ZVQqjGrS14DMF0wnHVi3ygdizgwPvXWKmK/HBgC9MrZHVh9uFLjVer18T4jL8YAxe3G0CQOZ9u2cMq/Wv7gRj20ga7JuHwxWhQEdYyjcxJj1+FzxDtVOigoIq6jd/qaLRPXo2qRSJrs2yeWqrDSHaTabmRURLW8g7KShOa6OY4dId7AUwGstQhjiELFQND74juBK8HDcdg+hvL3eNcn21ieDs3BGK7FsEiIV3dxcRr89DQs9oOhMrYO+Py4RBCR6iEhu8tAn9Lm+5IIPC/y5fwRmj3ORgIDiMU3/3QF6ek9c9PHcXhZLU/NNdzXit7C5eICorlEI8lfE5qxXi32ETCX7TiDNBFSLuOsvmV8ihjOdi/rsxfCTNTEOC33E3lbVgR6rAEvK7HBHEgD4474tCcnJz0BRM8h23aC4Jj4QVLeE1cXookagwNJA+WgA4n4lSFw+2yep336HZCz2kJVlanPwNnMgc88V5YV+yZxNODKD+dmZmFkbJSCK5E4OwH3Z+bnSHLghRG+3dlFD6snMKx9Pqye3w8LbmM+B1BnHYsN56wPMk9VhrEtWFsgWE4OyxBS8ZIrbipyRGC4JJIbNWdEwpBT+yRhZPFlBZ5PfVbJEEfsEgfVflpEsb0GQx4JuZNEa0g/gLRWpMdKmHbA/MZ31YNlJauqf1quct6ogma1RFQgJ6NTwqfjDpCYbGYap9/sYu+o5HQJJtH34dkw52/Zr16pR0336wjCgzcQyuRFbNvCM/I1tT+hvDCkqkvEgSol7j3HBcJuIBC0QzCPC4KV9oSgDY83vZ+Hof5MkCSzYeCjEXLNyUx/eNek0hKJfBtmLnn5hBSD3luCwCK6tBBxGzlaAObuQZ8xMZ8RiWuSrQqegmQjvakjwSfisqjtzbj1blws9OX4uA+ZOxUiA29IfSUScu/KQFQS8gJ42lnICRZA3L9MWSx9EyCc7LCsFHGrpE7jr0okkEoRe3E6be6jU0ymqoVIFDiVbGSDtBCpI0qSLZFJmkOAuBFO4ErueKfSlBG3lkVgircKhIDJ49CjRZuogI9FwHtdLDgSltTJqxGMlSqoXHVlsqdnC19GjMl37fNlsFjCiv6M7R7G5eLc5N2wV0SGtstnL6iJOejKvBzKae2hWgbhqIjPAlzkNa6/FspOvnrmyuQv0LeKGbVqkgeL6DL2KJ195o1LrlPpi0tOj9gz0a2jFIkvO9AkerErsnszb8fHtuLcxu3JydYgjzGk1XEbxaDt6ep6lIwS3MjZH/loDLRtvN31KfOTRTIocQ1QwbzuKxf3HZEZflPCOn6Gq+ZomGN/FnpspGM/8Ht0fIwWC3HfetfLPovhkbHg1prFBPCwqJSsIs73k+iXyZO2E3EkXEliTgYH4KKrzlnuDgMQvGDPrcShHFdVKF/Qsn0flruEu6gAUeKMk2gsBJ9q5GHYhUIXJQyWYI3aHuUAmYhw3jafWyG5twqijuX0XWg+d4W6pc2V0i8RVCrUrzUPZp/PXIyd8EapUTjVFKpBSeu0X86O0snRC9pOus/9kcDOWuQkfYmhzDkO06eqpQc1lLLeol42Xkm3pIRM58+QAPCUXMkp7tAe9B7h0DAlbxgipO71OXqCNkxhBfPzcrwBZoLwMrDow3aQYY4z0gN0Unw+CTopTpeMkrtUgxEV5h4OB4EHX1moCTXsWijKtQqvSPCgjEAIX/M2eCeLYUL9HsB6U2zHfWxbH1VgeT1YKRVfgETsLVDIXLf2V0Yg2e3GPSVoHUX8RBVF485UdYIkBSzZOxfrAVVhfJpXiCW5I8n97cx35AUC2+Tl4uoVq4Q4nCTWoGeVFX8ALaDU397nucwo7ZDzsn7PTu9F8WLhBx1yB6cOktsX3bv4zIvI7aJIqevJeGxBXWQwyUWtj1LF0rOde28QX71YXERErAYyQUK0pRYItc7cKG7BNK1EPg4c5NHIrngPksErz9P0SDhG7SV2KSGwN5NUrq0orttjxdSO8VG6QLPv4PI/AQo7JS/WuA9QqF5gRpX/jgGdqtIp7dIQ67jOYd3QLv4DyYlRdCkRh86rOpAtcThqkNT52smaTEox5KIuKiocSqmqL6hSZxzDwQCkIXizlOPUrJwMEFf/+57b192puv8cN0mtWbsG9BiLqtsTR0Pw7KHPF613rLRHKU+wgtk0Z9gpPLHI19JRn/DbJxGeMUQWLRDdl8KNnCBxG78cJEni+oIfAI/E3NKNjJ0uRXrtV20+fSM8U6fyHjso+y9uXHvTJwLy2Y0BY/fQqlo2JUZOXJkUMWUI/obo1A2c5jDnQpWU1wPaNJhK7YKccI0kslJWCFEJjH5Xol6BSI+aFyjpt46v9qJe9Q0uVdmcOtsW5HNAi7lRTVO25wmF+56Jk2wOYGaxYsUKWhdBmwPrQ/tjOLh+x9AWodBeTKsTvnsYQrBwX5zJmI6xNw121RUUoBDlSiSUYj5BJCf/7XycrkZBAONzN48adeZu0lJIPPDAA5TlED9yq+jNUpdLFYpObd2NaQZyWyBjDrHfdVQvbP1Yz1Xf/z5s374dNm7aBAmeUCC9ByjWN2IbzjXaMyMgtyVu/sEJTomk+SlGqF5z7bVw2qmnBmN0PBIJ94E7kWv8jLXOlvGyzqcR0t7MirPMjNtOJxxDDD/hpcFi8oSYNAcZpYWV4xl0jSQRPKS5sMxQGkf1rK7EQVyb+ZP5vPvu+2H/oRk4aefRqC9Qnl4APrtwQYz3+X1z7MXClVOy7MPDoY6IRdeJE8BhBz5OgJ0carN03Gcl0+za2CvvfIGuDnJdqsk+W+9aggq/r7jySjj99NMjgWT1l3fMe84lFRANzHt+8UtiGFu3bjGcMa/O2ap96qNyaV+2I7/37d8HRx11ZJzsuDJs6r37nnvo+yg5TMZFjGgZkfxA5nDLLbfA5KFD8JCHPASOnjgKdBMUHRgTfvXCfN+/bz/NWTzqLEPqbEAgvBvs3pZCfGQd8c6oVNqGUTnTRjb9QPyOkkHtH8duA4jPnDRnywvstBuKYk7j8Zz8riTnGY/tzttvh7/9h0/CCccdB+f96pPgrLMfBv2FedKicNttT9ZFuuxiq2kFdeX4KMXFV3L6jno7R0aGcl7olM9AQgYHkHs7EkLYjrs2GMtU8JcfTGhtPNNSrMtrs4wFr/vvv5/E6Lp162BifDwWRMSanpmBdUccAaOj7M27+567aWV15coVQQSvlKKeOPPk1CTVgRNz6OAhmshVK1fBwYCYuCqL9WHSsc2bN0VNCgG+d88eOCK0EZFF/CH7H9hHZ+ZhjqjxwPWxj7vuvZfqWrNmLawO9/GlfaFeNCBXU7nxBijwna1btsBP9u+nBTA0OkFQAvuEGRGHhoZJzamqSkL7XZT+qHbg8dUY+r1+3RHk2cGn+N6ucB/HhG1jH1atWknvLoR+4zvjgSGtW7ceNKLabhpzBsGTCxhaCQWccQ8r/YrnwIGW8cmJoIwN0n1GI6Z6cu3KgUCoWmlQ5Yb1E7B+jYef/ewGuP22m2EzJs7+9fPg9NNOhNmZQwQLVLU6WzZveTunex+i1cUOnTWnqVg4k8iZZ54BxxxzjBl4/m0/YH5X5dmFSvmRw8DAy5Vcyirs8bnP6sR2br7lZtgSuP7q1asz4F/1gx/CvYErz8/PwfU33AgbNmwgJLvpxz+CO++8kwy1G8L99evXwcGDB2H37j2BUOZIP8VDXbQdfPbDH1xFh7zgmK6//nqYmZmGzZs2w5VXXgH3hDYQuPfeezchOraD35d+77vkLbznnnvpPO7NmzdTHy+55BLKHYXJnG+++edw5JFHwv6A4JiuE8shga5Zuxp++pOfws9//jNawMJym4J6NjY6Kgty/NmyZSsROUoRlHxr1qwhQsBE2D/84Q9hfoEJAPdbn3DC8cFjM8LEEsYxF+By+RWXU/179u6BO+64A7aHOe92O3DxJd8leKAq/tOf/Tz09xAcc/Qx1MfvXnoZjIyOUPnJySk4KvSfgh2x3g4HP+pHgyH5t953MTdWZZ5VcmYgLzpqOQlf0d8Vr9Z3ZPwcImO3AbkUNmPghJ+hQEybVo/C1o0rAkEcDAxxF1x79fXwgx9cHyT8DOw8+eTABCaQKQyBuu1iAJhnly9TczpQJCJkKxLn6GwLuAZnl3/jglSL8pQsLiiXkl2zpfTLl0/4HnLWdQH5cYvlxd+9BHbt3kXE8Itf/AKOP/54OPHEEwMH3kWcHJnBfffdR2ekHH300XJ0gQeAguCdURsE0bZt3w7btm0njn3VVVfRgTB4DgZKh0ed8yiKHP3mN7/JG3YCwp0U2kVbBJMGXPydi+G+gMzbj91ORIIX9mXfvn1w5113wpOf+KTAqcfh6oDsd955R+B2p+fwFclOSBCkB+6txrHfedddsC3Ug6rnoUMH4ZLvfo9OjmIJwxf+PvWUU2BLIFxMpPbVr36NiGbfvmki8Kc++UlB6o7BVT+8mhbWECl//JOfwENPPglOOilw3bl5+MY3vwXHHXdsgOt6oyoVqlZUkdrULC6vjBWEOJJ6Zcpq/RmOpb/j1HsOoe+Aj0klKKN7kA7jgUGdGPp/1NFHEWO78ce3wO2/uBu++Y17w1x8D574xMejkV7RqqKKIRWHwdfFYthBPLzGZaqTA4vH9nKDf5hfubHvXK5SWfXNEotzEF2NURp5SK5iI2xMZ2nSf3DVD4J6sBg4/kxQFVZT4Yc/7GFBzP4c7rrrF0GtWAcPfehDuW5I+m3U1dE7UllpmSZLJwzVEiSUiYDIWKQn3hFUyfBCSa0qxvDIcJBcs3D55ZdT3ZhdA8tXrjJMyFEZvPP9YNxjpYthLCh9NKDQciBFyEqZWygzNzsH27dtI84+PDIq0t0cSiRzjFIAkR4BjO+iNEGpgfbcClLpPKl9PUrsDDSujRvWE9dfEcqsDNIWJTGdGhsJASBXtyyS50RCbxA98Pg1b1VJWFp3YpZm8i2eQOoD/qrE2YL4Mz4xCiuCmnjw4CyMTnTgmOPGYd2mLbDz7nsDDG6Fu+65H772ta8GO6TCCe0QZ3NR0YO4ETLqq84Z9IVsQuwfbvDTeGWGdbwJhhpa3jUmSnxe+H69fd1cqBbddNOP4AmPfzwh1mUBITVp9ViQKI9//ONgJqg411x7XSCWnxGR2JglKxH1d4/0+W6GyGrMIuJq8jFaoZWwBWfgg+X2B8lwyy23Bk71BFL3vv3t72QIpRdmIccL+0kEVgC6+bdBJrlB7UPOeRNiBqfAL38ZyszB05/6VILr57/4xbhzmUIyIIcHjhU9P3OzMzRezCmF546PBaLvVFViHhGZm5KiQRz2b0NAkBEZ5HjmzJdb4l6EO9vWqDquX7cCVq0Yhvvun4L9B33w6q2EY449FjZs3kKS/Kc/uxm9WD0ihiHaSVZJeHYVkxzQ/lw3CNVjq5DFoLhBpX3u/srq0HsuFXDtEiqv0ovnxMdq8RAbRkjm6Kim4ANUpxDB7r/v/qBDH0WBatdccw2dbIRGKXJmBBwdExZeQHUE60oH3PiYbBn1fER8JL4xTBsj7eN9HP7td9wJq9esppVZtDd++tOfkq3DiJo5hIPL8W76NRskG88/G9aHgm2yJ7SPqiAa79cFe2drqGtXsAe2bNlM6p87DJZ0TCh32223UX/vD6pfXFjyiRlxXqgFKnfw4IHIq7C9G2+6Ca6+7npYs3pVeP++oGpNUB9PPnEH/PTnNwfm6oNn7AGSImhDNZC8AiMtLGEYyQIAUNyDTEok3cJFZCkRZBlskUFh3d1uBWNhbsYDka9cMRYk30IglINhfAeDRj8UbMd1Qdo+FDrHbD3q7QrkPgVr9WAOPwF5ZoNRN7/Qg9NOP5V02NiIDD5+oCAKl81/QTA+G7CDUgr5Jcbpci6cbmcie3RkJHG6QPSYfRy9LwcPHCBGgMSBiI6eGPQ0ISfHZ5uDLbAj2COIOCvDM1QX8Dcau7qHApkIvncIPVYBqY7cupXqWrFiAu4MRHH0UUcREaC+/tDgasVz7rBt7NOB0MYRa9eSLYTfR4R60ZuGdeE5eYjwKNEQ0VYFZESjHhFxQ1DPkIjxvEI8gQqdBmgko8qUwcGoGGgHYBAqXvg+to/jRCMaVaENpBo54UOe+jM6OkL2DpZfvXolEQRKr6OO3Bq8dQdhMeADGt5ovxx15JbwzhGhjWE4EJ4hAT/qnLPJ81MVBnHlkiHuMiPcpY1Zht27FlwBI8HsWF0xdPt4ILGEqmamD8J9e+4OMJ6ls05QxV85MRzGvhpWhDGNBALatDYww+3H7vBOMlqQnuZYudLB4YNXvvJl8OhHn5NTbtZtgMaKXtulg/C+2fUlbzgAl0fkuobo5MptHixVNSI71LWKqK4pF/WxX1KCM5j4dPJrxvSdmUozMd+5+OJglO8MiH6UNhDVvriU5tTAdzBYzioyKMetDNdNRqvP+iJ/lLDxSWRbyeXayuv0xvcYPt8PHsDjt2+j29def0NwLOwIHq6jOckDZXRHouDsIKqOt6lKVpUyzRe6cTmx+Tu5OmYBYP5e9nJwcP8DsOueO6PdvTC/GJjPDExNzZArf3x8ONiqs9AdRaONjL0q139lkLT3uHLmiAP7DUvctd3JAZFEZZIWmW0RC2tffAY/Vzy2HeDAtiTRvO1lRiA+Ir7NMpKV9T5ui/axz2BUQZ8RyqrA2cfHRsH5fJOZt+WkMqf2k1qTDeS1l+4qT7DQbPnOLsF73Tpq3+X9EBBDRHhA3hBoBK3dnhBhWsOWTRvhZzffQiro0WGB85ggJRlu4nUShtoRCWFVqTgmV8DXNgwA+VZZn3VBK4j04BwkIz1V7Ipvfa9EFfxd14uwMDcTJMlc0JSA0lDjycFbto4HJ8MQ6DpLd2h4uNHJ7O+IRIMJoPUyvUo/ffwwHitQbP3eaJlltGiqyRUdSmcKMuAyzc4gYEYcYBBVrshMveBiEgFFIRuVzM8fEdaLXHNAubyNwZrS1xKq+o7lAini0bjGwUgEX3B+aJFQHizlOCOlbJmsr8BEtS1IRPzYXTBqmLpMVXJx/SGNoWxF59DMhxCvPXxUJZj3GSoBuHbDviFFXJPNgBn97PQs1AuzQc0dQyJg6YcGPB2mw8GKGEnR5bh+BYaPm01wdxdyhFF0DVKSL2+G1Wy8lXgy0vWR0TmfOFkqajl+vjcikx4iHGwgoKVrdeOR9Kt9sxJvatcvkpJap2tnBm6J4fmWMm0VuJYafPFSlCi2SkvxrvGqpaXUlLkhnDYSnTcc3ThVbE/USNYI10R/yfVdZdICon3oGmPzmlJZKjfzrgQiH15zssRSJyYliB/VaOtdLTSfOIeWUEw9I2PDsGrNCvqz15sDtyin2xLhV7xOhKEmTwgOGtysj3uDaQ8xZpOjdJJdTocSPBTrhguENcI6tpv9gAIZlKx85Az55bLXjZzIcU+5NTTVg7IfNqgxE4xe+54IvsobLbuVIXFJCzoJbf2RR8UbIPjeYoMUeraWjWqEWUAragSbMCH/5lE6/QgMyxqKJiFyeccSjBiOEFfqrvVGWRi1STbTUJ2qj1LCe6Nm1bzVwJw1702buobjjDTVZ0kVK6BbMJTZqfngIZwkryYulo8Hzxw6GjpDGMXLW85rPDPkjuCeow7G3KogFJ1yFT1kYcG2Y37lDsuC+UHjJZ86mNyyKktcK7LnSKBfOWAa+C838764RiejtHJJnrlyMPIVNTGnPTA1u0h3WXsO8ijXSNgFUxvkfLBcEayB7oyhG5HeoLxzDc4aCYTueci74XJ8KtSzjGC9N1Iasn6AIDp4g/+xhfh6LJ7KJKappKbbbPU4ZsRPKzXa+JlWHAUF2B9Owuj53auuugLe8+f/J3VKGICG5w8T0QR7ZNfkIiXKo83xrtIMR7ACpmHVSIeijNeMuKILAI1ZhoRgvvjDZW8ZKollXBxECVSfvatuXh8RLan75ZRoJbafQtTlhi2wXE/eUVsmsS7DxaCAhwOr87nsvrlbEJC3MIgv5lLEFRKkil4sU0ZbK7kpuJxALOzy5sw7OUHYxUSVzFENL6DATLUSIeHNSB3UkEutnBn62G7cdCWNkmSp0550BypFkuvYcE5zlTjLIkTvnnTySfDyV788GOrzcCC42TEeDo+Dngmu/dngvcLI35ng1eru9yvNQYpVzEjR7S/AUId3cy32E9JrGHHsg8+75Bv9s5xBsVmJROpyaeNOPqgE4GzozmXASszCImGBxdJefEYLjPmmLg/qIFDicLFaW3cbZ7S/dJ98+rvFY+SKHy5x//SVCMRJ8F5zkU230sYKEsOQv20myJZmwaol9jv+jgQjdgHUUevg6dTtt563ubomcg6aWw8lQQJkhrdLNUQGqYGNHY1ITu83iUTVNttqWCfauA7OOffR9BvtDeW0lUtR6kjwXdW3kmGrRhIlqKQOzfaSquCttPCtPHvJS/c8R87pIHPxtolOn3Ej4SDCQitDYFotQEknBlm9jwiUbCLThuWoAMrWWumt/YXUj+SKzIs7yInAdjNJDEEUSC5TXZdKkhQSUhsJ0o6MDjKxnjCz0V7WD4AoReLGI5dNmsCVpQZnmvQFHMo+8M/GapjiuGECSqoJBlUkjkQgbXPgkurkTSe1C2jbhEVCUuNo/abLUi74ezmErdKkDRDXOijXkXCqlDuoAz2fUzy0/G5ARDsUb5ZWRmNEJQgTt1NkdnHmYj9raYZSaXpIydBce/1e+hXdidk0uWV6lz9xA5+kH7aMa5EO2d8GEZrfVSxspZGeKc/DKtREWw4MI/AieXxezr5miSN7WCRD0yQOuvhb177JEWzZ2Hkzp5AI1ZtXIv/IkCIFYjo549wymviiaDv8Ss4QEEmGhjowOjrEDgBKVhJW03uSasjJtuBOF0NSsFtpv6+mtsfNJXXFabvqErGtFCkYU3m54jvjIPKeM5AomXV8XzgK7zFwFGahUa+Ozrzwsm7hwerovmDravyRXhu9I3W+fzxKDf6uoipohtDG/CJHTvCwROHM82ylOePcBaGYeuMwhLAjgTvIVAiWjnKMA6gHiqEbiUUQmrglpNM5NCmMB9t3xVipSwml8LX7TEoloHsLH59A3ASggk3G4ax7Oc0lCQDujqk9J74cYK4xXxipvBBsDdfhuEP0ZgXHLeEXn6/O2eu7i706EoWCFv8f9klsqmdW5yCTIoo5+WJERhAlLKK4FYnAbVbgMpZrkA10E4xsuOnwbjkSt4wKlBisL5yMX8yRyyKVekfosMkapSWv82iWjQyRwUGstjGrpqfyj+2+gyZR8H2XE4xTnbswys34NRFaXSfp563L3BeKqFFTYlodKa+aRkwxKkZK5ZJqWNo6dpzJ1Zznvortl3NgR+IMlCKTSPdUwnkda82Z6HWo6FCi5A5y7EJNmoQduRJuMT8FYWKOLNw4RgQSns3PzhMjxHhEDDBFXMNXAoH0IWW0APFEhMUTyiNU88aeAcSRmjdUrDCCkuF6211Ik1jR2RRO8rKmVdG8tN1Z1pFjsvBvRREEZsd7SBubyhrALD4pgfA+ZfK8eJ+didERwqNd0RmnKvrmzMTosMCqTy4hlr3PDzNCTshYSgxdMGMi6ffrbCxNj5KLEopgZBbUtD4lfic6qqfduS6mKIIWh4AHw0QBmMtKe03oSL1m/AqnTMV0LkkNIQw6M7C230AOk1pSzbi+lxO/ahNVZG0xBUNUFFMfBFS493wB964Mj1AQ5lCXPW2IF7Pzc9QftEu6PS+ve+HSWCmtKndoRx2KGeTMmqOjNJgNNKB5+fZnCnQ6tKUjQW4ds0HGcl7lsipBOrKls0PUD8AHwVdGCsapcImweb4MUtV8XLEXqEcCAYiqmaJDlHh2CI0/Uj+dHWf+OHvTSp426WRDLzi3LtCc9GuV+nokdg25+SGSQ1LsdDxEAz85JYDVLMrQXlG+XMokgsdheCEQ3beuc4F4QBnr+5F5wAC7R0do71jYuDRIhrMwXxxbPwx0MVDFYs9TKD3jodRFyeA97RDEYztcVQvR+RZmZPaqg+CVNIv5zmYW+jCE2z0qPBeEdxkODXf5aDbHe37wUDY50BFgoZZULOHlWT8KU6GTuDls1g8DGIRprqHn0iN/lqtYmk2DTjTCTfG4D16+OZGA+voBrMrlZOLjKipyRqPTElc03NQVXYl6rU/i0Ndy1IM3i2gAYL1BHjKMj9xeuXAbYpe0EKFjCdV2TtvwCXG99BmJoBYGpRkf+YCnOi7ullJEx4BZMjuaKBNPKTddTTs5gTMYepGbnk4vpOMQQJhXDN0QShWUBEyXA3FBWRt3YKVMko76XPUJn7ygygBEYvSC2r+IZ3TQjkaRIMAKXU3EAZROlMPnuTYOP/Fx7KoF2sN8LE4dmvewfyHgXVjDGMGNb6hmz+LZ6Li8UXFmdzy38N75CcPKEtd2MB4aXUOHv0/BSuCFRB1amnTn2yTHgEtVKpQY6CEY6lKmDP50o11hRS9Yyk96C4GLRKKyH/BRBQCAXOQ7MIcc5wQU5YP30S7IET9hubrCD/dqEgXr1WrURGK1TXltqzYSzIGeKx7Zjrxqza74LVVVcu4ewdLzcTmMv8anVSuR4Dem4RSVWufKmbUG0jY4mxWpNpzcyqheCeARpaDJrOwckXpMaiNLC5YcffrGYEG8r+XkcARKH0oRxJQ7S2KzIpEwUaTf3Hplgviw9N75Ibh6cn08dg43yiH+EXGEckN4XggGK1adoUQbRiBUkgWPjvntVCkdvmCKtwAhVmAraF4uEkdFp/hgzMsQfYY5o4p0sHJVZswamEdAMSPzlNtVlq1k34adokTIkadRnbLPPhPHSfzTp3JGeiWibCONiLC1/u1zh4D+rZ4z6XEdub6PYRQRcQrkt0Sg6hjZbHWECHhocaM7TenD8KlyV53pJ88lqnCoqrK6qqeCMJFACQ9vEF8TvUXjvISRT4wifxQdREgcCz0mDvwm4pB+6Dt8GIIks0aCr8A4IpwQBqT5dRCTa5DUU1UxfGE7mGgiZlRxzmgwXAkFK7ro4lDYOyOmnBwV1BF2IcB0kEbr2ojCivtEyZxpo0vBYUQYw8OUURslCEuPPJQiry3pqn2ddMxFTgY3pI1NPPXx/Xg2n/bGaTois7kKIBPNYGAQ4dIgjxS852XyEnP0UY2KTgGfNmCRC10IJqp4LslluqtjAlXzmMFUlapGTo4p81E6QfyGlnGYj5FULE34HcpfS84OiN8xQblLECW1pTKzU6dZigBx+rOJH0nSeVEZmSB6QiD43ZO+eMugMgYj3iyZw9q5eN5JFSUiJ47L5la6tnKkCw89ZoMQI0aMdKgfc4sLNEY03GcP7ocuEYAMKNoGTqQHsM+7il4mmTnstp5d6BWDchah0wEueaD0kPYhSTWvxKEeqZjuBUxVUX1I0kJdnMmATb8TN2XfPgFM5LPLeEHy0FiGENUs5yB5XMpLkUo4dLQFIHfDgnrM9NhkzRzvTZ/NxjGDTNneCOkTyJoVzQ9GOlTJu6V7d7zFQAc5s8uG4JLS4CEChlUecQKIm9VXalMoPNieqel+J8KAzxn0sf9aYbL/zAi9Egh/2NZIkqPfZyJIfU1jw/JonCM8KyNB5DQFVsec0QosfStuTN0Hq+7/KUxgEr6JcRgeHaMkFCOja2FsYoJyhuG9rlu5kuwBF5A0YCq44WH6uwocHomn0+vB8Pg4uwu9YJoetiicLVN+G6ik0qNio0fCiynMWG0PTUHjTDXKPa2XQ37XioAF8FObLlebnGtIAG/fsZhiy0bm1Xw3Sg4vEac+X6OopYO1IWb1PPmsrB4U4MsWIsFrX4g8zCEwLKlcQSBNYoMoxatMGiqjj2MWjqawjgSntShQ5YiMSoiHjbM6kwwA3qiGvkEcaQ5kfcd7UanMnhAp5QQW1DRGd5DtowfuMIP3eiCWoGWtNmXsuxcVkDv185/8GN7/3r9mSex9Jm2j7eLxGLaxFfwQ3VWoAnVHmEhGR2BobBQ2rF6BOUlpcY4ntSbd3w40ChDVoyWMIKpWKj2ielUY5VVlDsKxBMGAqiEniNogYMQfaVv4nHHZOuO9yVdjtL5ITD7lTkrq1QDi8CI5dFKRA/paVKOEXLm0M+W1jEVsQ5eJs3vTDRdh7UVyUziQgwgfddn7VgKxUoDHaxeZq8hq+VunVOEDRh2tK5bRrOuIF0yQCgAgmx7D7GyfvJF43sAjEqiZMyYOjRrwYBuKz6pBgbS1aYN/33Td1TCPWWyGR2F85dqgUs1Bnz4LMQsLXgFjO0QcrjNE7laHG/BHRmFsbASO3LAGHrFzA2zbMJ4C0YD1PWsQKwAy5cgloNPmftyhhd4CsUM08186ichKC+XCA5DNtKGqVNpIJfaF/pXjd5y8WgmY6lSbhHVil/tDW4gkEaxyPjpSuJ+IWvuoRJi4aV61TpozEyq4bwAq0NX+uiQDVKI4Y49YKZEuFxFc/7Eclu64dL6gyx9AWsBlhEUnjnrINALaazuFNFQiMCPJyvjiO/9lJYhLgDME4rUfFgkj5TPDpnpowmr45R23whWXfCvc7sDoxh2w81HnEdx07HgU4eLCLMajBBULkTWoOhUmJAt6V3dkGFZNjMFxm9fA2Ts3wkO2boSJsHhy3+Q+2L13PxzYe4iPrULDphd8xn4uo2jsE6W8rHFP4iKMhs/2k0+BDVuOhkOzU8HuWISRkXmSIikzIOvl8/OLJFWQMKZn58hgw78xB+0ipWap+AyT0PTIUBUE20g8MgulE/rzNaYIjbx5PCkInBiAvfBZoDRGuEvSDXVw/DA3hxksglQL07159QSNBdPuUOJm54UReIrPwfgdJmjWkdHAOzi1SCmSXMVpPHmDTx25NYJlYWGRFyXxOR4SiT53x0cdY5/27/0lykXYsHYdzIVnna5weiEunB+MMu0tzrCKAcwIHXkDR2FhZhI8qC3SD+VRTQ4rxHOHqB+doQnojAZNoL8oKW4qWiUm9JF+VYKIo2MT4fc8jI6Mw2i1AMeesDNMMzsIaJW7LwusnhkJhYLQPAHcv/uXMHlgH9WLPKaPLthOIrJKDj2g3y5tfMK5nw0wvO7n98KiGueeF/MiYYtXgELTK3VYMONF+NBa2lA3y/tLrl9Ryfj8kQXYfeP34JsXfSMSEq6kczZLR1LR99kOHxnnzJXdKhSohtHmCEZJUK3Wrx6Hk45ZB2fv2ALb166mvE7zAZP2zczBtXf+Ai76wiWUyhIjILu9SVjZP8jcva5TPJdI2/HFA3DmmWfBup1nwdzefbRopWdSowTByUSOvRCQVrnh1PQs3L37IK2RdCh4jFfZkSBHg1G/6YiVsDoQhlsMZWfQ61HDoel56DvOZjgb6uob+wgnFQltLrj0pqfn4NDUNOzbfyCoj90w3g7MzyzA2lDfpjDuX4qDYtvRR5IqqFyZbDTgsA0ilPCZnZmH/aG+W++dJUSZDX3A7ILIVTGWp9MVpZgWvnqUEQTfn5vnI4eJsYVV3KmpSbjtmm+GezOw46TTYGEkMBaygBmWQyMBsYN0780eCPg9z/3Bfg7h2R5dWJibBvaAcdT1UEBsF5C/HzhgTYtpQzC64gjoDK+ExZkHoDc/FQhrRJCtYgTHA5LCAlknEOHq9VuhP3UvrF27HrasXIAtmzfEhTol+FpUyeSM4LGiunL1FRdTlkr8G71RWB5zZ3UDQ8KEhJhLDOGOw8M8XLrGshgW7P7pQ1+DyTkvsYZMsn2vuyg7oMsElSRY19i8LhnUE9ANjBTTuWKCvC4e6+E4QRy2Scer9WehuuUbMDurh+cAtd8Pc1OLM4qYNi4fdJg5dimnUWhgNEiNI9eugFOOXQdnbN8MG1dMUOPTYUL3Bg51xwOTQYos8slLFA6wCGNhUunYLmnNyeIW6uN4c8dZT4XzX/7igPTzlI2v201rKT05WbQTJnAktA/EcYJ0oJgbD2uC3RPoFo5YNQErxsKg6ZCSiggCJcZiv0dHamH6/f0Hpwmxh8MLmC0vZvLDFKBoG4QJmRgZgpUrxoO+uRLWbthAaV9WhUlbFQhlgsILPAFy5Qo8V6RPHHBoiPvFXirmXhT+sLhITgeP4TgYbRAmc2QUjwzm47xU5wVZ9OzQavQInc1RdWpeZ6j7xCHxM7z2SPBzk/DAfCDtBWY2iACd0L6fRl/9InCyx+A4Ya5BDIKxdoI5Mu5nCG3OTy2E/s3JugciT2ACQfK4apbmp9/DOegRk8J5xHxQlD6006VxjT0Q5mosENVoH4586EPhwIEZluiBGSChIIwxHKMjya95R1+fEa4ahtPOegxcc8UlbOB2+9FWQymLLc8thHHNdWgu8M0e6vzICEL7Tzn7RPjipT/jU71kvb6icwtN0imy8TjrCGAkRFVD3CmIqiZKc3Q44eo4MblKQlI87TF3pSKHkSS1xBwSkFkCeWRi6FjCTIOrxkfh6C1r4ZE7NsHKwNU2B8McJcRkmOzdgcPdcf8U7DkwC9MLfKAinhcxvHgQxioW16RuASOY+uRPf8Sj4PznPBv23j8J69etZN2uBuKyTE8YYjxKagqqVsNdOr4dtq5dCVvXTASiGaJ66MSfAMQ5kJgrp/ZCRRM+MRqQZtUoZYTsyuo8Xn3hbpUYkygFESnWrxyB8dAWZnI/9uijaaO+GqEdV4vuUkUQEugDEeNvJM65hSCxZhbhgf3TsOfgPKmbFJjR4bCO8QBLhBFyxNmDM7zpRtTJtDjIOjuqmRMTK+CEhzyS25JkfWxTiHPDpUBA3auQbKu0OakvuXG7HQkPAbaHlHjU/ulLgGE35s+tSMLiHK5fPQLr1ozByccfGdTMsTAvPbj5jr2wBpnUilFyYJC3DqXgwgypNb3FPvUbx439XbPpBNi0+WaY3Lc3MC9evQfgg3uw32PB8YOr1UOhj8i5SbUJdWJy8bMftg0eCMzu0ht+KSTHLvBK7Rj8i+mBmA9u6KsxyhLPIVzAYwIDw+7iXDFj4yyOyMSQp4Q6AoFkTpPwX4e8tc7sTIQIfyTs7rqgRp0YVKozjt8AN193M3zvsuvgf7zqfNh81BFw9/5J+OX9M7B3cg5mwmBngvoyH5B1eOEBGK9naCsuIQbqwuJdQCCc9shz4TGPfULgTAsB0KN0bzb8XuyzETxM6x+OFqLWrxwLxM5UjPr43EKPBvHAgUmazDWrxlm/VLPXy+JSGDUFmc3PkfgdGu5ESYbvY6gCER5yu9DQhpWhzcDF8YwM5NA7T9hOi5XKljjeiQ8J1shiklSBq87Mz8LUbC+oZ/PBjkKbo0d2zUL4xogAJED23fcJ6JjnFVUwJNapqdkwrqCKBn87SlDUb7Gvnc5oeB6QM5TtU4qlSg4vYuOyEmQGsdOc2Xtt3dbWM9RfXMU2i7rkffLGOTpugRfi8Bkidjdg/NFbjoC1q4IG0WWbaEWQ3KvXrKSy2IujVjGzwjlKq/3JzEbJi3X1AmNFNXYyjPeIYx4O1eLlUPe6JH0WcE0jvDMS1hXQANaMJHqgDaraQ91hwvxffezD4MDUHNx42328jQGHUbETgmK/nKwhBUne77BVw9wiMKqeori4DJK3hHBkOKiRukSg9jtGkujJU84uNYh3rPvIHRvhpC2r4KIvXQK33bWbjLY7du+CyREHd++ZgoPTYbIDAKbCZ9ee+2FkaheMBT2glonjsPEFkQhDsGb9Zhjb8jC4/MZfwpo1LDnmKSsKG9vdkS6vdIrLk6gYDfO+7s/oE1Ax0zgm8BoNHAddwo5sjEXaWI8csTPEp17hcQbk0FJrMNw8sO9+WmMZHRsnUFFWjAB8jPlHpB0e4TUYJ9Yurx30Zco5csBptC/tC+iKqlCbQ+r7UMewc2Abg9Z6hqgM9n0ej/RC6Ydq1+77yMYbGh0mOwzVFExYhqoK+wHQHpuXPd2e9W2xoyoxkL26K8W2sR6i6BFzghPiN+Gx8cSTKzogMpDdQS43uPXugIh4JDIynd4CAZDWI/py0ity4QB/tBeGg41R0dEGHlx0XoRxBsLoyqIvJzt3cPbWYVg7NE+qE6tjaL/NsRQI/yGjwt8UsBpUsx7BO6y5dcfh159wGtx/4HK454FpSG4pDnxBGLDalYIYa4c2bLC7oBeZhZf/xNgLQ+3CyOIct555SzlRXF3VMRAWxJuHz7rHrhqCT370P+HgwSmJh+/DvuDZObR7EqYm54n6DwYut+eB4J342Q9gLBg6hJCohkRvDSMPcttF8ih1iGhQPULdc/LgQVh7xDpCZsy1pTmPlPtRp7xMWgASgmL/vv2B664mbuxcTwz6WlyyoczcPCEFclk0yhC5iIhwgrojNEhEzMVg2NLkL/ZJWI96tAXQxlhkMEYXK46+J56jrjgrOQSBVSyQvSPJdYuI1Qu+c44qrtngQ04oatHQsHhXwmdmehL23X8vTTgS7lhYvZ1YsZrXn1QKOG1DFhP7DF/0VrHOzWd+kwqIcKJx8ITWdR0NaKUQ/MLJ530zzCiQySBCa39R+iMxDI2MiDex5t2agbOi2jYVDO7Z0HdUjdcecQQMBy8XnTmOoSikNvfJM0daBEpkcavuG5+ENUcEKVsvEOGgdGUm1yeuPzrERIOEMR3mGJ0LqA4hU3GhDxc84RT45EXXwQOH5ogwCOeAc7cxUWjiCFG5InF48ejVzHTQViVcDIyxP0X533QxVRnbzNQUjVnt1o7EZNE+pe2PeOb+xYXFNbXvy/pADdtOeQgcsW0bIfzB4OXZu3cvPGv/5fDtO2fpYB1GKtYdVfyrXjcaFh63bH9oaHCBJAqnT5mGiWAcIxCjP1z9196+z/4n5GD4zigeKyDqhK44q68biQ/tJN6z0AG23pysqHpBGp48Vt/qFFLf4ZCN5J52/L5tA4RJgxN3pCBh5Nhe3LQ98kZROA6OL3I8dmnGk4JD3YtzQd3qL5JBPDIyyrYByMYf0NCPVF6OkhW1sY51c2h/SqQD+g62Rw4Sz0hFNlw/bhVUqd0P84pIhetSeDYMIwdr+t4iEKmyi3QUHV5Yfgi9nlUV50OBlY7tc/CIk7bB9iM8rBzukwaB+7878k4lBzMFkgqaSc17UdCjSY4f9hBqdO+dd90NX7zyFlj0Q8I/0mq3l3wEte+ynWNcv/SfruV4YSoBF7YOTcFGtw/2B3V5PuAOakaTw1uCC3yVSQShB0eh02fkru7i/MLfhUWut/EKeU2Amzw4CWNBldkfbI/9u+6GzT/5Bpx0ygjcfdT6YIsE1xfqZkOs85Mr0bEHoEMGUZiQ/T+Feix0oLcoiITrGjGaJkNCRjZB8HifufTkIW/UBBWbLuqWugCn5fN7SoQuqiXRQDOUpn+jylCbNC3aptoo+jOmAlJOzQxTwsb5D0Jdr6Sn+2h8zGqIN6bonpKEK4ACCVIxSloJWdZm7GYKGmO6J3SduElRp9aojMRKMG3TmMXxPZS5cz7V5UydsSvh7ubTVsNYd4KMdAwjXwxSgTYihXaGA/LM4uFCXT4TE89hZFWZJQwdRQ7AuyaDS/rYoYNw28Ka4BzoAm9/lIVRqOn8QSdeLLJLoUd2DTFZWvcK+IeLXWjMB0JfvyJ4A8dlNgQnDh0Iru/6EGtELgXs0Tk5w92Pd++56Zvv2HzyE0IHei8L3pZtKzeuD7r6LOw9NA0zv7gDNv7s22G9Y5Zcnts2r4T7D/XYMxQaGAv6NKEDuUiHSYfVOKO9wQ8/dWge1gzzotVkMG6n5oIXKLgyhwNxrQuep/UrR2HtymGqa9e+g7Dn/vvhxO2b4J79DlZOBG9TYBzo7UDVDDk08tnpuXmSBl62WxLfxDPoOrIrLhh0w51uJA7ygsiRYFS61tVmPX+RnYhjI106DrvbYWONHArRa+IlorsWL16fvDLzwaM1FVTIqdmwzhI8fIgMIxSZgKoN75HHv8dH0VM4TGqFOjWwXVzX4b32XiRazeP0vFi2IJGtvFeBzzQEWg8AqsOJviFmuDAr7F9NC524FoPPiEOH0Qx3JDa1X4uni414ZHa9HmsQ6NjAc8IRoVXloCjaUNFPbrkTfnTLHXDe484OYxmmfvHGLabPL15yFUwuBKkVKpoj4gjeQ5y70OeFObQvwjpQn3HEBTd7jVIHt77imrPsd8HEbTSvtKLdhwk/Dxsh4IZbLQxKKNmpRMENVH36lyQ6MnrcaIVrRnUvBtWi2oaborwwJvqWrbwQ7bcaJHj3QJjzv1/Yd8ef/v8sF0YLdsbHEAAAAABJRU5ErkJggg==", "description": "Designed to display single value of the selected attribute or timeseries data. Widget styles are customizable.", "descriptor": { "type": "latest", "sizeX": 3, "sizeY": 3, "resources": [], - "templateHtml": "\n", + "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n absoluteHeader: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-value-card-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\"}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" } }, { "alias": "horizontal_value_card", "name": "Horizontal value card", - "image": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzk5IiBoZWlnaHQ9IjEwOCIgdmlld0JveD0iMCAwIDM5OSAxMDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGZpbHRlcj0idXJsKCNmaWx0ZXIwX2RfMTI0Nl80NDQ0NykiPgo8cmVjdCB4PSI4IiB5PSI0IiB3aWR0aD0iMzgzIiBoZWlnaHQ9IjkyIiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTU3LjAwMDEgNTEuNjY2N1YzOC4zMzM0QzU3LjAwMDEgMzUuNTY2NyA1NC43NjY3IDMzLjMzMzQgNTIuMDAwMSAzMy4zMzM0QzQ5LjIzMzQgMzMuMzMzNCA0Ny4wMDAxIDM1LjU2NjcgNDcuMDAwMSAzOC4zMzM0VjUxLjY2NjdDNDQuOTgzNCA1My4xODM0IDQzLjY2NjcgNTUuNjE2NyA0My42NjY3IDU4LjMzMzRDNDMuNjY2NyA2Mi45MzM0IDQ3LjQwMDEgNjYuNjY2NyA1Mi4wMDAxIDY2LjY2NjdDNTYuNjAwMSA2Ni42NjY3IDYwLjMzMzQgNjIuOTMzNCA2MC4zMzM0IDU4LjMzMzRDNjAuMzMzNCA1NS42MTY3IDU5LjAxNjcgNTMuMTgzNCA1Ny4wMDAxIDUxLjY2NjdaTTUwLjMzMzQgMzguMzMzNEM1MC4zMzM0IDM3LjQxNjcgNTEuMDgzNCAzNi42NjY3IDUyLjAwMDEgMzYuNjY2N0M1Mi45MTY3IDM2LjY2NjcgNTMuNjY2NyAzNy40MTY3IDUzLjY2NjcgMzguMzMzNEg1Mi4wMDAxVjQwSDUzLjY2NjdWNDMuMzMzNEg1Mi4wMDAxVjQ1SDUzLjY2NjdWNDguMzMzNEg1MC4zMzM0VjM4LjMzMzRaIiBmaWxsPSIjNTQ2OUZGIi8+CjxwYXRoIGQ9Ik04NS44MzU5IDM1LjYyNVY0N0g4My44OTA2VjM1LjYyNUg4NS44MzU5Wk04OS40MDYyIDM1LjYyNVYzNy4xODc1SDgwLjM1MTZWMzUuNjI1SDg5LjQwNjJaTTkzLjk0NTMgNDcuMTU2MkM5My4zMjAzIDQ3LjE1NjIgOTIuNzU1MiA0Ny4wNTQ3IDkyLjI1IDQ2Ljg1MTZDOTEuNzUgNDYuNjQzMiA5MS4zMjI5IDQ2LjM1NDIgOTAuOTY4OCA0NS45ODQ0QzkwLjYxOTggNDUuNjE0NiA5MC4zNTE2IDQ1LjE3OTcgOTAuMTY0MSA0NC42Nzk3Qzg5Ljk3NjYgNDQuMTc5NyA4OS44ODI4IDQzLjY0MDYgODkuODgyOCA0My4wNjI1VjQyLjc1Qzg5Ljg4MjggNDIuMDg4NSA4OS45NzkyIDQxLjQ4OTYgOTAuMTcxOSA0MC45NTMxQzkwLjM2NDYgNDAuNDE2NyA5MC42MzI4IDM5Ljk1ODMgOTAuOTc2NiAzOS41NzgxQzkxLjMyMDMgMzkuMTkyNyA5MS43MjY2IDM4Ljg5ODQgOTIuMTk1MyAzOC42OTUzQzkyLjY2NDEgMzguNDkyMiA5My4xNzE5IDM4LjM5MDYgOTMuNzE4OCAzOC4zOTA2Qzk0LjMyMjkgMzguMzkwNiA5NC44NTE2IDM4LjQ5MjIgOTUuMzA0NyAzOC42OTUzQzk1Ljc1NzggMzguODk4NCA5Ni4xMzI4IDM5LjE4NDkgOTYuNDI5NyAzOS41NTQ3Qzk2LjczMTggMzkuOTE5MyA5Ni45NTU3IDQwLjM1NDIgOTcuMTAxNiA0MC44NTk0Qzk3LjI1MjYgNDEuMzY0NiA5Ny4zMjgxIDQxLjkyMTkgOTcuMzI4MSA0Mi41MzEyVjQzLjMzNTlIOTAuNzk2OVY0MS45ODQ0SDk1LjQ2ODhWNDEuODM1OUM5NS40NTgzIDQxLjQ5NzQgOTUuMzkwNiA0MS4xNzk3IDk1LjI2NTYgNDAuODgyOEM5NS4xNDU4IDQwLjU4NTkgOTQuOTYwOSA0MC4zNDY0IDk0LjcxMDkgNDAuMTY0MUM5NC40NjA5IDM5Ljk4MTggOTQuMTI3NiAzOS44OTA2IDkzLjcxMDkgMzkuODkwNkM5My4zOTg0IDM5Ljg5MDYgOTMuMTE5OCAzOS45NTgzIDkyLjg3NSA0MC4wOTM4QzkyLjYzNTQgNDAuMjI0IDkyLjQzNDkgNDAuNDE0MSA5Mi4yNzM0IDQwLjY2NDFDOTIuMTEyIDQwLjkxNDEgOTEuOTg3IDQxLjIxNjEgOTEuODk4NCA0MS41NzAzQzkxLjgxNTEgNDEuOTE5MyA5MS43NzM0IDQyLjMxMjUgOTEuNzczNCA0Mi43NVY0My4wNjI1QzkxLjc3MzQgNDMuNDMyMyA5MS44MjI5IDQzLjc3NiA5MS45MjE5IDQ0LjA5MzhDOTIuMDI2IDQ0LjQwNjIgOTIuMTc3MSA0NC42Nzk3IDkyLjM3NSA0NC45MTQxQzkyLjU3MjkgNDUuMTQ4NCA5Mi44MTI1IDQ1LjMzMzMgOTMuMDkzOCA0NS40Njg4QzkzLjM3NSA0NS41OTkgOTMuNjk1MyA0NS42NjQxIDk0LjA1NDcgNDUuNjY0MUM5NC41MDc4IDQ1LjY2NDEgOTQuOTExNSA0NS41NzI5IDk1LjI2NTYgNDUuMzkwNkM5NS42MTk4IDQ1LjIwODMgOTUuOTI3MSA0NC45NTA1IDk2LjE4NzUgNDQuNjE3Mkw5Ny4xNzk3IDQ1LjU3ODFDOTYuOTk3NCA0NS44NDM4IDk2Ljc2MDQgNDYuMDk5IDk2LjQ2ODggNDYuMzQzOEM5Ni4xNzcxIDQ2LjU4MzMgOTUuODIwMyA0Ni43Nzg2IDk1LjM5ODQgNDYuOTI5N0M5NC45ODE4IDQ3LjA4MDcgOTQuNDk3NCA0Ny4xNTYyIDkzLjk0NTMgNDcuMTU2MlpNMTAwLjkzIDQwLjI2NTZWNDdIOTkuMDQ2OVYzOC41NDY5SDEwMC44MkwxMDAuOTMgNDAuMjY1NlpNMTAwLjYyNSA0Mi40NjA5TDk5Ljk4NDQgNDIuNDUzMUM5OS45ODQ0IDQxLjg2OTggMTAwLjA1NyA0MS4zMzA3IDEwMC4yMDMgNDAuODM1OUMxMDAuMzQ5IDQwLjM0MTEgMTAwLjU2MiAzOS45MTE1IDEwMC44NDQgMzkuNTQ2OUMxMDEuMTI1IDM5LjE3NzEgMTAxLjQ3NCAzOC44OTMyIDEwMS44OTEgMzguNjk1M0MxMDIuMzEyIDM4LjQ5MjIgMTAyLjc5OSAzOC4zOTA2IDEwMy4zNTIgMzguMzkwNkMxMDMuNzM3IDM4LjM5MDYgMTA0LjA4OSAzOC40NDc5IDEwNC40MDYgMzguNTYyNUMxMDQuNzI5IDM4LjY3MTkgMTA1LjAwOCAzOC44NDY0IDEwNS4yNDIgMzkuMDg1OUMxMDUuNDgyIDM5LjMyNTUgMTA1LjY2NCAzOS42MzI4IDEwNS43ODkgNDAuMDA3OEMxMDUuOTE5IDQwLjM4MjggMTA1Ljk4NCA0MC44MzU5IDEwNS45ODQgNDEuMzY3MlY0N0gxMDQuMTAyVjQxLjUzMTJDMTA0LjEwMiA0MS4xMTk4IDEwNC4wMzkgNDAuNzk2OSAxMDMuOTE0IDQwLjU2MjVDMTAzLjc5NCA0MC4zMjgxIDEwMy42MiA0MC4xNjE1IDEwMy4zOTEgNDAuMDYyNUMxMDMuMTY3IDM5Ljk1ODMgMTAyLjg5OCAzOS45MDYyIDEwMi41ODYgMzkuOTA2MkMxMDIuMjMyIDM5LjkwNjIgMTAxLjkzIDM5Ljk3NCAxMDEuNjggNDAuMTA5NEMxMDEuNDM1IDQwLjI0NDggMTAxLjIzNCA0MC40Mjk3IDEwMS4wNzggNDAuNjY0MUMxMDAuOTIyIDQwLjg5ODQgMTAwLjgwNyA0MS4xNjkzIDEwMC43MzQgNDEuNDc2NkMxMDAuNjYxIDQxLjc4MzkgMTAwLjYyNSA0Mi4xMTIgMTAwLjYyNSA0Mi40NjA5Wk0xMDUuODY3IDQxLjk2MDlMMTA0Ljk4NCA0Mi4xNTYyQzEwNC45ODQgNDEuNjQ1OCAxMDUuMDU1IDQxLjE2NDEgMTA1LjE5NSA0MC43MTA5QzEwNS4zNDEgNDAuMjUyNiAxMDUuNTUyIDM5Ljg1MTYgMTA1LjgyOCAzOS41MDc4QzEwNi4xMDkgMzkuMTU4OSAxMDYuNDU2IDM4Ljg4NTQgMTA2Ljg2NyAzOC42ODc1QzEwNy4yNzkgMzguNDg5NiAxMDcuNzUgMzguMzkwNiAxMDguMjgxIDM4LjM5MDZDMTA4LjcxNCAzOC4zOTA2IDEwOS4wOTkgMzguNDUwNSAxMDkuNDM4IDM4LjU3MDNDMTA5Ljc4MSAzOC42ODQ5IDExMC4wNzMgMzguODY3MiAxMTAuMzEyIDM5LjExNzJDMTEwLjU1MiAzOS4zNjcyIDExMC43MzQgMzkuNjkyNyAxMTAuODU5IDQwLjA5MzhDMTEwLjk4NCA0MC40ODk2IDExMS4wNDcgNDAuOTY4OCAxMTEuMDQ3IDQxLjUzMTJWNDdIMTA5LjE1NlY0MS41MjM0QzEwOS4xNTYgNDEuMDk2NCAxMDkuMDk0IDQwLjc2NTYgMTA4Ljk2OSA0MC41MzEyQzEwOC44NDkgNDAuMjk2OSAxMDguNjc3IDQwLjEzNTQgMTA4LjQ1MyA0MC4wNDY5QzEwOC4yMjkgMzkuOTUzMSAxMDcuOTYxIDM5LjkwNjIgMTA3LjY0OCAzOS45MDYyQzEwNy4zNTcgMzkuOTA2MiAxMDcuMDk5IDM5Ljk2MDkgMTA2Ljg3NSA0MC4wNzAzQzEwNi42NTYgNDAuMTc0NSAxMDYuNDcxIDQwLjMyMjkgMTA2LjMyIDQwLjUxNTZDMTA2LjE2OSA0MC43MDMxIDEwNi4wNTUgNDAuOTE5MyAxMDUuOTc3IDQxLjE2NDFDMTA1LjkwNCA0MS40MDg5IDEwNS44NjcgNDEuNjc0NSAxMDUuODY3IDQxLjk2MDlaTTExNS4xMjUgNDAuMTcxOVY1MC4yNUgxMTMuMjQyVjM4LjU0NjlIMTE0Ljk3N0wxMTUuMTI1IDQwLjE3MTlaTTEyMC42MzMgNDIuNjk1M1Y0Mi44NTk0QzEyMC42MzMgNDMuNDc0IDEyMC41NiA0NC4wNDQzIDEyMC40MTQgNDQuNTcwM0MxMjAuMjczIDQ1LjA5MTEgMTIwLjA2MiA0NS41NDY5IDExOS43ODEgNDUuOTM3NUMxMTkuNTA1IDQ2LjMyMjkgMTE5LjE2NCA0Ni42MjI0IDExOC43NTggNDYuODM1OUMxMTguMzUyIDQ3LjA0OTUgMTE3Ljg4MyA0Ny4xNTYyIDExNy4zNTIgNDcuMTU2MkMxMTYuODI2IDQ3LjE1NjIgMTE2LjM2NSA0Ny4wNTk5IDExNS45NjkgNDYuODY3MkMxMTUuNTc4IDQ2LjY2OTMgMTE1LjI0NyA0Ni4zOTA2IDExNC45NzcgNDYuMDMxMkMxMTQuNzA2IDQ1LjY3MTkgMTE0LjQ4NyA0NS4yNSAxMTQuMzIgNDQuNzY1NkMxMTQuMTU5IDQ0LjI3NiAxMTQuMDQ0IDQzLjczOTYgMTEzLjk3NyA0My4xNTYyVjQyLjUyMzRDMTE0LjA0NCA0MS45MDM2IDExNC4xNTkgNDEuMzQxMSAxMTQuMzIgNDAuODM1OUMxMTQuNDg3IDQwLjMzMDcgMTE0LjcwNiAzOS44OTU4IDExNC45NzcgMzkuNTMxMkMxMTUuMjQ3IDM5LjE2NjcgMTE1LjU3OCAzOC44ODU0IDExNS45NjkgMzguNjg3NUMxMTYuMzU5IDM4LjQ4OTYgMTE2LjgxNSAzOC4zOTA2IDExNy4zMzYgMzguMzkwNkMxMTcuODY3IDM4LjM5MDYgMTE4LjMzOSAzOC40OTQ4IDExOC43NSAzOC43MDMxQzExOS4xNjEgMzguOTA2MiAxMTkuNTA4IDM5LjE5NzkgMTE5Ljc4OSAzOS41NzgxQzEyMC4wNyAzOS45NTMxIDEyMC4yODEgNDAuNDA2MiAxMjAuNDIyIDQwLjkzNzVDMTIwLjU2MiA0MS40NjM1IDEyMC42MzMgNDIuMDQ5NSAxMjAuNjMzIDQyLjY5NTNaTTExOC43NSA0Mi44NTk0VjQyLjY5NTNDMTE4Ljc1IDQyLjMwNDcgMTE4LjcxNCA0MS45NDI3IDExOC42NDEgNDEuNjA5NEMxMTguNTY4IDQxLjI3MDggMTE4LjQ1MyA0MC45NzQgMTE4LjI5NyA0MC43MTg4QzExOC4xNDEgNDAuNDYzNSAxMTcuOTQgNDAuMjY1NiAxMTcuNjk1IDQwLjEyNUMxMTcuNDU2IDM5Ljk3OTIgMTE3LjE2NyAzOS45MDYyIDExNi44MjggMzkuOTA2MkMxMTYuNDk1IDM5LjkwNjIgMTE2LjIwOCAzOS45NjM1IDExNS45NjkgNDAuMDc4MUMxMTUuNzI5IDQwLjE4NzUgMTE1LjUyOSA0MC4zNDExIDExNS4zNjcgNDAuNTM5MUMxMTUuMjA2IDQwLjczNyAxMTUuMDgxIDQwLjk2ODggMTE0Ljk5MiA0MS4yMzQ0QzExNC45MDQgNDEuNDk0OCAxMTQuODQxIDQxLjc3ODYgMTE0LjgwNSA0Mi4wODU5VjQzLjYwMTZDMTE0Ljg2NyA0My45NzY2IDExNC45NzQgNDQuMzIwMyAxMTUuMTI1IDQ0LjYzMjhDMTE1LjI3NiA0NC45NDUzIDExNS40OSA0NS4xOTUzIDExNS43NjYgNDUuMzgyOEMxMTYuMDQ3IDQ1LjU2NTEgMTE2LjQwNiA0NS42NTYyIDExNi44NDQgNDUuNjU2MkMxMTcuMTgyIDQ1LjY1NjIgMTE3LjQ3MSA0NS41ODMzIDExNy43MTEgNDUuNDM3NUMxMTcuOTUxIDQ1LjI5MTcgMTE4LjE0NiA0NS4wOTExIDExOC4yOTcgNDQuODM1OUMxMTguNDUzIDQ0LjU3NTUgMTE4LjU2OCA0NC4yNzYgMTE4LjY0MSA0My45Mzc1QzExOC43MTQgNDMuNTk5IDExOC43NSA0My4yMzk2IDExOC43NSA0Mi44NTk0Wk0xMjYuMjExIDQ3LjE1NjJDMTI1LjU4NiA0Ny4xNTYyIDEyNS4wMjEgNDcuMDU0NyAxMjQuNTE2IDQ2Ljg1MTZDMTI0LjAxNiA0Ni42NDMyIDEyMy41ODkgNDYuMzU0MiAxMjMuMjM0IDQ1Ljk4NDRDMTIyLjg4NSA0NS42MTQ2IDEyMi42MTcgNDUuMTc5NyAxMjIuNDMgNDQuNjc5N0MxMjIuMjQyIDQ0LjE3OTcgMTIyLjE0OCA0My42NDA2IDEyMi4xNDggNDMuMDYyNVY0Mi43NUMxMjIuMTQ4IDQyLjA4ODUgMTIyLjI0NSA0MS40ODk2IDEyMi40MzggNDAuOTUzMUMxMjIuNjMgNDAuNDE2NyAxMjIuODk4IDM5Ljk1ODMgMTIzLjI0MiAzOS41NzgxQzEyMy41ODYgMzkuMTkyNyAxMjMuOTkyIDM4Ljg5ODQgMTI0LjQ2MSAzOC42OTUzQzEyNC45MyAzOC40OTIyIDEyNS40MzggMzguMzkwNiAxMjUuOTg0IDM4LjM5MDZDMTI2LjU4OSAzOC4zOTA2IDEyNy4xMTcgMzguNDkyMiAxMjcuNTcgMzguNjk1M0MxMjguMDIzIDM4Ljg5ODQgMTI4LjM5OCAzOS4xODQ5IDEyOC42OTUgMzkuNTU0N0MxMjguOTk3IDM5LjkxOTMgMTI5LjIyMSA0MC4zNTQyIDEyOS4zNjcgNDAuODU5NEMxMjkuNTE4IDQxLjM2NDYgMTI5LjU5NCA0MS45MjE5IDEyOS41OTQgNDIuNTMxMlY0My4zMzU5SDEyMy4wNjJWNDEuOTg0NEgxMjcuNzM0VjQxLjgzNTlDMTI3LjcyNCA0MS40OTc0IDEyNy42NTYgNDEuMTc5NyAxMjcuNTMxIDQwLjg4MjhDMTI3LjQxMSA0MC41ODU5IDEyNy4yMjcgNDAuMzQ2NCAxMjYuOTc3IDQwLjE2NDFDMTI2LjcyNyAzOS45ODE4IDEyNi4zOTMgMzkuODkwNiAxMjUuOTc3IDM5Ljg5MDZDMTI1LjY2NCAzOS44OTA2IDEyNS4zODUgMzkuOTU4MyAxMjUuMTQxIDQwLjA5MzhDMTI0LjkwMSA0MC4yMjQgMTI0LjcwMSA0MC40MTQxIDEyNC41MzkgNDAuNjY0MUMxMjQuMzc4IDQwLjkxNDEgMTI0LjI1MyA0MS4yMTYxIDEyNC4xNjQgNDEuNTcwM0MxMjQuMDgxIDQxLjkxOTMgMTI0LjAzOSA0Mi4zMTI1IDEyNC4wMzkgNDIuNzVWNDMuMDYyNUMxMjQuMDM5IDQzLjQzMjMgMTI0LjA4OSA0My43NzYgMTI0LjE4OCA0NC4wOTM4QzEyNC4yOTIgNDQuNDA2MiAxMjQuNDQzIDQ0LjY3OTcgMTI0LjY0MSA0NC45MTQxQzEyNC44MzkgNDUuMTQ4NCAxMjUuMDc4IDQ1LjMzMzMgMTI1LjM1OSA0NS40Njg4QzEyNS42NDEgNDUuNTk5IDEyNS45NjEgNDUuNjY0MSAxMjYuMzIgNDUuNjY0MUMxMjYuNzczIDQ1LjY2NDEgMTI3LjE3NyA0NS41NzI5IDEyNy41MzEgNDUuMzkwNkMxMjcuODg1IDQ1LjIwODMgMTI4LjE5MyA0NC45NTA1IDEyOC40NTMgNDQuNjE3MkwxMjkuNDQ1IDQ1LjU3ODFDMTI5LjI2MyA0NS44NDM4IDEyOS4wMjYgNDYuMDk5IDEyOC43MzQgNDYuMzQzOEMxMjguNDQzIDQ2LjU4MzMgMTI4LjA4NiA0Ni43Nzg2IDEyNy42NjQgNDYuOTI5N0MxMjcuMjQ3IDQ3LjA4MDcgMTI2Ljc2MyA0Ny4xNTYyIDEyNi4yMTEgNDcuMTU2MlpNMTMzLjIwMyA0MC4xNTYyVjQ3SDEzMS4zMlYzOC41NDY5SDEzMy4xMTdMMTMzLjIwMyA0MC4xNTYyWk0xMzUuNzg5IDM4LjQ5MjJMMTM1Ljc3MyA0MC4yNDIyQzEzNS42NTkgNDAuMjIxNCAxMzUuNTM0IDQwLjIwNTcgMTM1LjM5OCA0MC4xOTUzQzEzNS4yNjggNDAuMTg0OSAxMzUuMTM4IDQwLjE3OTcgMTM1LjAwOCA0MC4xNzk3QzEzNC42ODUgNDAuMTc5NyAxMzQuNDAxIDQwLjIyNjYgMTM0LjE1NiA0MC4zMjAzQzEzMy45MTEgNDAuNDA4OSAxMzMuNzA2IDQwLjUzOTEgMTMzLjUzOSA0MC43MTA5QzEzMy4zNzggNDAuODc3NiAxMzMuMjUzIDQxLjA4MDcgMTMzLjE2NCA0MS4zMjAzQzEzMy4wNzYgNDEuNTU5OSAxMzMuMDIzIDQxLjgyODEgMTMzLjAwOCA0Mi4xMjVMMTMyLjU3OCA0Mi4xNTYyQzEzMi41NzggNDEuNjI1IDEzMi42MyA0MS4xMzI4IDEzMi43MzQgNDAuNjc5N0MxMzIuODM5IDQwLjIyNjYgMTMyLjk5NSAzOS44MjgxIDEzMy4yMDMgMzkuNDg0NEMxMzMuNDE3IDM5LjE0MDYgMTMzLjY4MiAzOC44NzI0IDEzNCAzOC42Nzk3QzEzNC4zMjMgMzguNDg3IDEzNC42OTUgMzguMzkwNiAxMzUuMTE3IDM4LjM5MDZDMTM1LjIzMiAzOC4zOTA2IDEzNS4zNTQgMzguNDAxIDEzNS40ODQgMzguNDIxOUMxMzUuNjIgMzguNDQyNyAxMzUuNzIxIDM4LjQ2NjEgMTM1Ljc4OSAzOC40OTIyWk0xNDEuNzAzIDQ1LjMwNDdWNDEuMjczNEMxNDEuNzAzIDQwLjk3MTQgMTQxLjY0OCA0MC43MTA5IDE0MS41MzkgNDAuNDkyMkMxNDEuNDMgNDAuMjczNCAxNDEuMjYzIDQwLjEwNDIgMTQxLjAzOSAzOS45ODQ0QzE0MC44MiAzOS44NjQ2IDE0MC41NDQgMzkuODA0NyAxNDAuMjExIDM5LjgwNDdDMTM5LjkwNCAzOS44MDQ3IDEzOS42MzggMzkuODU2OCAxMzkuNDE0IDM5Ljk2MDlDMTM5LjE5IDQwLjA2NTEgMTM5LjAxNiA0MC4yMDU3IDEzOC44OTEgNDAuMzgyOEMxMzguNzY2IDQwLjU1OTkgMTM4LjcwMyA0MC43NjA0IDEzOC43MDMgNDAuOTg0NEgxMzYuODI4QzEzNi44MjggNDAuNjUxIDEzNi45MDkgNDAuMzI4MSAxMzcuMDcgNDAuMDE1NkMxMzcuMjMyIDM5LjcwMzEgMTM3LjQ2NiAzOS40MjQ1IDEzNy43NzMgMzkuMTc5N0MxMzguMDgxIDM4LjkzNDkgMTM4LjQ0OCAzOC43NDIyIDEzOC44NzUgMzguNjAxNkMxMzkuMzAyIDM4LjQ2MDkgMTM5Ljc4MSAzOC4zOTA2IDE0MC4zMTIgMzguMzkwNkMxNDAuOTQ4IDM4LjM5MDYgMTQxLjUxIDM4LjQ5NzQgMTQyIDM4LjcxMDlDMTQyLjQ5NSAzOC45MjQ1IDE0Mi44ODMgMzkuMjQ3NCAxNDMuMTY0IDM5LjY3OTdDMTQzLjQ1MSA0MC4xMDY4IDE0My41OTQgNDAuNjQzMiAxNDMuNTk0IDQxLjI4OTFWNDUuMDQ2OUMxNDMuNTk0IDQ1LjQzMjMgMTQzLjYyIDQ1Ljc3ODYgMTQzLjY3MiA0Ni4wODU5QzE0My43MjkgNDYuMzg4IDE0My44MSA0Ni42NTEgMTQzLjkxNCA0Ni44NzVWNDdIMTQxLjk4NEMxNDEuODk2IDQ2Ljc5NjkgMTQxLjgyNiA0Ni41MzkxIDE0MS43NzMgNDYuMjI2NkMxNDEuNzI3IDQ1LjkwODkgMTQxLjcwMyA0NS42MDE2IDE0MS43MDMgNDUuMzA0N1pNMTQxLjk3NyA0MS44NTk0TDE0MS45OTIgNDMuMDIzNEgxNDAuNjQxQzE0MC4yOTIgNDMuMDIzNCAxMzkuOTg0IDQzLjA1NzMgMTM5LjcxOSA0My4xMjVDMTM5LjQ1MyA0My4xODc1IDEzOS4yMzIgNDMuMjgxMiAxMzkuMDU1IDQzLjQwNjJDMTM4Ljg3OCA0My41MzEyIDEzOC43NDUgNDMuNjgyMyAxMzguNjU2IDQzLjg1OTRDMTM4LjU2OCA0NC4wMzY1IDEzOC41MjMgNDQuMjM3IDEzOC41MjMgNDQuNDYwOUMxMzguNTIzIDQ0LjY4NDkgMTM4LjU3NiA0NC44OTA2IDEzOC42OCA0NS4wNzgxQzEzOC43ODQgNDUuMjYwNCAxMzguOTM1IDQ1LjQwMzYgMTM5LjEzMyA0NS41MDc4QzEzOS4zMzYgNDUuNjEyIDEzOS41ODEgNDUuNjY0MSAxMzkuODY3IDQ1LjY2NDFDMTQwLjI1MyA0NS42NjQxIDE0MC41ODkgNDUuNTg1OSAxNDAuODc1IDQ1LjQyOTdDMTQxLjE2NyA0NS4yNjgyIDE0MS4zOTYgNDUuMDcyOSAxNDEuNTYyIDQ0Ljg0MzhDMTQxLjcyOSA0NC42MDk0IDE0MS44MTggNDQuMzg4IDE0MS44MjggNDQuMTc5N0wxNDIuNDM4IDQ1LjAxNTZDMTQyLjM3NSA0NS4yMjkyIDE0Mi4yNjggNDUuNDU4MyAxNDIuMTE3IDQ1LjcwMzFDMTQxLjk2NiA0NS45NDc5IDE0MS43NjggNDYuMTgyMyAxNDEuNTIzIDQ2LjQwNjJDMTQxLjI4NCA0Ni42MjUgMTQwLjk5NSA0Ni44MDQ3IDE0MC42NTYgNDYuOTQ1M0MxNDAuMzIzIDQ3LjA4NTkgMTM5LjkzOCA0Ny4xNTYyIDEzOS41IDQ3LjE1NjJDMTM4Ljk0OCA0Ny4xNTYyIDEzOC40NTYgNDcuMDQ2OSAxMzguMDIzIDQ2LjgyODFDMTM3LjU5MSA0Ni42MDQyIDEzNy4yNTMgNDYuMzA0NyAxMzcuMDA4IDQ1LjkyOTdDMTM2Ljc2MyA0NS41NDk1IDEzNi42NDEgNDUuMTE5OCAxMzYuNjQxIDQ0LjY0MDZDMTM2LjY0MSA0NC4xOTI3IDEzNi43MjQgNDMuNzk2OSAxMzYuODkxIDQzLjQ1MzFDMTM3LjA2MiA0My4xMDQyIDEzNy4zMTIgNDIuODEyNSAxMzcuNjQxIDQyLjU3ODFDMTM3Ljk3NCA0Mi4zNDM4IDEzOC4zOCA0Mi4xNjY3IDEzOC44NTkgNDIuMDQ2OUMxMzkuMzM5IDQxLjkyMTkgMTM5Ljg4NSA0MS44NTk0IDE0MC41IDQxLjg1OTRIMTQxLjk3N1pNMTQ5LjY4OCAzOC41NDY5VjM5LjkyMTlIMTQ0LjkyMlYzOC41NDY5SDE0OS42ODhaTTE0Ni4yOTcgMzYuNDc2NkgxNDguMThWNDQuNjY0MUMxNDguMTggNDQuOTI0NSAxNDguMjE2IDQ1LjEyNSAxNDguMjg5IDQ1LjI2NTZDMTQ4LjM2NyA0NS40MDEgMTQ4LjQ3NCA0NS40OTIyIDE0OC42MDkgNDUuNTM5MUMxNDguNzQ1IDQ1LjU4NTkgMTQ4LjkwNCA0NS42MDk0IDE0OS4wODYgNDUuNjA5NEMxNDkuMjE2IDQ1LjYwOTQgMTQ5LjM0MSA0NS42MDE2IDE0OS40NjEgNDUuNTg1OUMxNDkuNTgxIDQ1LjU3MDMgMTQ5LjY3NyA0NS41NTQ3IDE0OS43NSA0NS41MzkxTDE0OS43NTggNDYuOTc2NkMxNDkuNjAyIDQ3LjAyMzQgMTQ5LjQxOSA0Ny4wNjUxIDE0OS4yMTEgNDcuMTAxNkMxNDkuMDA4IDQ3LjEzOCAxNDguNzczIDQ3LjE1NjIgMTQ4LjUwOCA0Ny4xNTYyQzE0OC4wNzYgNDcuMTU2MiAxNDcuNjkzIDQ3LjA4MDcgMTQ3LjM1OSA0Ni45Mjk3QzE0Ny4wMjYgNDYuNzczNCAxNDYuNzY2IDQ2LjUyMDggMTQ2LjU3OCA0Ni4xNzE5QzE0Ni4zOTEgNDUuODIyOSAxNDYuMjk3IDQ1LjM1OTQgMTQ2LjI5NyA0NC43ODEyVjM2LjQ3NjZaTTE1Ni40NzcgNDUuMDA3OFYzOC41NDY5SDE1OC4zNjdWNDdIMTU2LjU4NkwxNTYuNDc3IDQ1LjAwNzhaTTE1Ni43NDIgNDMuMjVMMTU3LjM3NSA0My4yMzQ0QzE1Ny4zNzUgNDMuODAyMSAxNTcuMzEyIDQ0LjMyNTUgMTU3LjE4OCA0NC44MDQ3QzE1Ny4wNjIgNDUuMjc4NiAxNTYuODcgNDUuNjkyNyAxNTYuNjA5IDQ2LjA0NjlDMTU2LjM0OSA0Ni4zOTU4IDE1Ni4wMTYgNDYuNjY5MyAxNTUuNjA5IDQ2Ljg2NzJDMTU1LjIwMyA0Ny4wNTk5IDE1NC43MTYgNDcuMTU2MiAxNTQuMTQ4IDQ3LjE1NjJDMTUzLjczNyA0Ny4xNTYyIDE1My4zNTkgNDcuMDk2NCAxNTMuMDE2IDQ2Ljk3NjZDMTUyLjY3MiA0Ni44NTY4IDE1Mi4zNzUgNDYuNjcxOSAxNTIuMTI1IDQ2LjQyMTlDMTUxLjg4IDQ2LjE3MTkgMTUxLjY5IDQ1Ljg0NjQgMTUxLjU1NSA0NS40NDUzQzE1MS40MTkgNDUuMDQ0MyAxNTEuMzUyIDQ0LjU2NTEgMTUxLjM1MiA0NC4wMDc4VjM4LjU0NjlIMTUzLjIzNFY0NC4wMjM0QzE1My4yMzQgNDQuMzMwNyAxNTMuMjcxIDQ0LjU4ODUgMTUzLjM0NCA0NC43OTY5QzE1My40MTcgNDUgMTUzLjUxNiA0NS4xNjQxIDE1My42NDEgNDUuMjg5MUMxNTMuNzY2IDQ1LjQxNDEgMTUzLjkxMSA0NS41MDI2IDE1NC4wNzggNDUuNTU0N0MxNTQuMjQ1IDQ1LjYwNjggMTU0LjQyMiA0NS42MzI4IDE1NC42MDkgNDUuNjMyOEMxNTUuMTQ2IDQ1LjYzMjggMTU1LjU2OCA0NS41Mjg2IDE1NS44NzUgNDUuMzIwM0MxNTYuMTg4IDQ1LjEwNjggMTU2LjQwOSA0NC44MjAzIDE1Ni41MzkgNDQuNDYwOUMxNTYuNjc0IDQ0LjEwMTYgMTU2Ljc0MiA0My42OTc5IDE1Ni43NDIgNDMuMjVaTTE2Mi40MzggNDAuMTU2MlY0N0gxNjAuNTU1VjM4LjU0NjlIMTYyLjM1MkwxNjIuNDM4IDQwLjE1NjJaTTE2NS4wMjMgMzguNDkyMkwxNjUuMDA4IDQwLjI0MjJDMTY0Ljg5MyA0MC4yMjE0IDE2NC43NjggNDAuMjA1NyAxNjQuNjMzIDQwLjE5NTNDMTY0LjUwMyA0MC4xODQ5IDE2NC4zNzIgNDAuMTc5NyAxNjQuMjQyIDQwLjE3OTdDMTYzLjkxOSA0MC4xNzk3IDE2My42MzUgNDAuMjI2NiAxNjMuMzkxIDQwLjMyMDNDMTYzLjE0NiA0MC40MDg5IDE2Mi45NCA0MC41MzkxIDE2Mi43NzMgNDAuNzEwOUMxNjIuNjEyIDQwLjg3NzYgMTYyLjQ4NyA0MS4wODA3IDE2Mi4zOTggNDEuMzIwM0MxNjIuMzEgNDEuNTU5OSAxNjIuMjU4IDQxLjgyODEgMTYyLjI0MiA0Mi4xMjVMMTYxLjgxMiA0Mi4xNTYyQzE2MS44MTIgNDEuNjI1IDE2MS44NjUgNDEuMTMyOCAxNjEuOTY5IDQwLjY3OTdDMTYyLjA3MyA0MC4yMjY2IDE2Mi4yMjkgMzkuODI4MSAxNjIuNDM4IDM5LjQ4NDRDMTYyLjY1MSAzOS4xNDA2IDE2Mi45MTcgMzguODcyNCAxNjMuMjM0IDM4LjY3OTdDMTYzLjU1NyAzOC40ODcgMTYzLjkzIDM4LjM5MDYgMTY0LjM1MiAzOC4zOTA2QzE2NC40NjYgMzguMzkwNiAxNjQuNTg5IDM4LjQwMSAxNjQuNzE5IDM4LjQyMTlDMTY0Ljg1NCAzOC40NDI3IDE2NC45NTYgMzguNDY2MSAxNjUuMDIzIDM4LjQ5MjJaTTE3MC4wMjMgNDcuMTU2MkMxNjkuMzk4IDQ3LjE1NjIgMTY4LjgzMyA0Ny4wNTQ3IDE2OC4zMjggNDYuODUxNkMxNjcuODI4IDQ2LjY0MzIgMTY3LjQwMSA0Ni4zNTQyIDE2Ny4wNDcgNDUuOTg0NEMxNjYuNjk4IDQ1LjYxNDYgMTY2LjQzIDQ1LjE3OTcgMTY2LjI0MiA0NC42Nzk3QzE2Ni4wNTUgNDQuMTc5NyAxNjUuOTYxIDQzLjY0MDYgMTY1Ljk2MSA0My4wNjI1VjQyLjc1QzE2NS45NjEgNDIuMDg4NSAxNjYuMDU3IDQxLjQ4OTYgMTY2LjI1IDQwLjk1MzFDMTY2LjQ0MyA0MC40MTY3IDE2Ni43MTEgMzkuOTU4MyAxNjcuMDU1IDM5LjU3ODFDMTY3LjM5OCAzOS4xOTI3IDE2Ny44MDUgMzguODk4NCAxNjguMjczIDM4LjY5NTNDMTY4Ljc0MiAzOC40OTIyIDE2OS4yNSAzOC4zOTA2IDE2OS43OTcgMzguMzkwNkMxNzAuNDAxIDM4LjM5MDYgMTcwLjkzIDM4LjQ5MjIgMTcxLjM4MyAzOC42OTUzQzE3MS44MzYgMzguODk4NCAxNzIuMjExIDM5LjE4NDkgMTcyLjUwOCAzOS41NTQ3QzE3Mi44MSAzOS45MTkzIDE3My4wMzQgNDAuMzU0MiAxNzMuMTggNDAuODU5NEMxNzMuMzMxIDQxLjM2NDYgMTczLjQwNiA0MS45MjE5IDE3My40MDYgNDIuNTMxMlY0My4zMzU5SDE2Ni44NzVWNDEuOTg0NEgxNzEuNTQ3VjQxLjgzNTlDMTcxLjUzNiA0MS40OTc0IDE3MS40NjkgNDEuMTc5NyAxNzEuMzQ0IDQwLjg4MjhDMTcxLjIyNCA0MC41ODU5IDE3MS4wMzkgNDAuMzQ2NCAxNzAuNzg5IDQwLjE2NDFDMTcwLjUzOSAzOS45ODE4IDE3MC4yMDYgMzkuODkwNiAxNjkuNzg5IDM5Ljg5MDZDMTY5LjQ3NyAzOS44OTA2IDE2OS4xOTggMzkuOTU4MyAxNjguOTUzIDQwLjA5MzhDMTY4LjcxNCA0MC4yMjQgMTY4LjUxMyA0MC40MTQxIDE2OC4zNTIgNDAuNjY0MUMxNjguMTkgNDAuOTE0MSAxNjguMDY1IDQxLjIxNjEgMTY3Ljk3NyA0MS41NzAzQzE2Ny44OTMgNDEuOTE5MyAxNjcuODUyIDQyLjMxMjUgMTY3Ljg1MiA0Mi43NVY0My4wNjI1QzE2Ny44NTIgNDMuNDMyMyAxNjcuOTAxIDQzLjc3NiAxNjggNDQuMDkzOEMxNjguMTA0IDQ0LjQwNjIgMTY4LjI1NSA0NC42Nzk3IDE2OC40NTMgNDQuOTE0MUMxNjguNjUxIDQ1LjE0ODQgMTY4Ljg5MSA0NS4zMzMzIDE2OS4xNzIgNDUuNDY4OEMxNjkuNDUzIDQ1LjU5OSAxNjkuNzczIDQ1LjY2NDEgMTcwLjEzMyA0NS42NjQxQzE3MC41ODYgNDUuNjY0MSAxNzAuOTkgNDUuNTcyOSAxNzEuMzQ0IDQ1LjM5MDZDMTcxLjY5OCA0NS4yMDgzIDE3Mi4wMDUgNDQuOTUwNSAxNzIuMjY2IDQ0LjYxNzJMMTczLjI1OCA0NS41NzgxQzE3My4wNzYgNDUuODQzOCAxNzIuODM5IDQ2LjA5OSAxNzIuNTQ3IDQ2LjM0MzhDMTcyLjI1NSA0Ni41ODMzIDE3MS44OTggNDYuNzc4NiAxNzEuNDc3IDQ2LjkyOTdDMTcxLjA2IDQ3LjA4MDcgMTcwLjU3NiA0Ny4xNTYyIDE3MC4wMjMgNDcuMTU2MloiIGZpbGw9ImJsYWNrIiBmaWxsLW9wYWNpdHk9IjAuODciLz4KPHBhdGggZD0iTTg2LjIxMDkgNjQuODM0VjY2SDgxLjkyNzdWNjQuODM0SDg2LjIxMDlaTTgyLjMzNzkgNTcuNDY4OFY2Nkg4MC44NjcyVjU3LjQ2ODhIODIuMzM3OVpNOTEuMDMxMiA2NC43Mjg1VjYxLjcwNTFDOTEuMDMxMiA2MS40Nzg1IDkwLjk5MDIgNjEuMjgzMiA5MC45MDgyIDYxLjExOTFDOTAuODI2MiA2MC45NTUxIDkwLjcwMTIgNjAuODI4MSA5MC41MzMyIDYwLjczODNDOTAuMzY5MSA2MC42NDg0IDkwLjE2MjEgNjAuNjAzNSA4OS45MTIxIDYwLjYwMzVDODkuNjgxNiA2MC42MDM1IDg5LjQ4MjQgNjAuNjQyNiA4OS4zMTQ1IDYwLjcyMDdDODkuMTQ2NSA2MC43OTg4IDg5LjAxNTYgNjAuOTA0MyA4OC45MjE5IDYxLjAzNzFDODguODI4MSA2MS4xNjk5IDg4Ljc4MTIgNjEuMzIwMyA4OC43ODEyIDYxLjQ4ODNIODcuMzc1Qzg3LjM3NSA2MS4yMzgzIDg3LjQzNTUgNjAuOTk2MSA4Ny41NTY2IDYwLjc2MTdDODcuNjc3NyA2MC41MjczIDg3Ljg1MzUgNjAuMzE4NCA4OC4wODQgNjAuMTM0OEM4OC4zMTQ1IDU5Ljk1MTIgODguNTg5OCA1OS44MDY2IDg4LjkxMDIgNTkuNzAxMkM4OS4yMzA1IDU5LjU5NTcgODkuNTg5OCA1OS41NDMgODkuOTg4MyA1OS41NDNDOTAuNDY0OCA1OS41NDMgOTAuODg2NyA1OS42MjMgOTEuMjUzOSA1OS43ODMyQzkxLjYyNSA1OS45NDM0IDkxLjkxNiA2MC4xODU1IDkyLjEyNyA2MC41MDk4QzkyLjM0MTggNjAuODMwMSA5Mi40NDkyIDYxLjIzMjQgOTIuNDQ5MiA2MS43MTY4VjY0LjUzNTJDOTIuNDQ5MiA2NC44MjQyIDkyLjQ2ODggNjUuMDg0IDkyLjUwNzggNjUuMzE0NUM5Mi41NTA4IDY1LjU0MSA5Mi42MTEzIDY1LjczODMgOTIuNjg5NSA2NS45MDYyVjY2SDkxLjI0MjJDOTEuMTc1OCA2NS44NDc3IDkxLjEyMyA2NS42NTQzIDkxLjA4NCA2NS40MTk5QzkxLjA0ODggNjUuMTgxNiA5MS4wMzEyIDY0Ljk1MTIgOTEuMDMxMiA2NC43Mjg1Wk05MS4yMzYzIDYyLjE0NDVMOTEuMjQ4IDYzLjAxNzZIOTAuMjM0NEM4OS45NzI3IDYzLjAxNzYgODkuNzQyMiA2My4wNDMgODkuNTQzIDYzLjA5MzhDODkuMzQzOCA2My4xNDA2IDg5LjE3NzcgNjMuMjEwOSA4OS4wNDQ5IDYzLjMwNDdDODguOTEyMSA2My4zOTg0IDg4LjgxMjUgNjMuNTExNyA4OC43NDYxIDYzLjY0NDVDODguNjc5NyA2My43NzczIDg4LjY0NjUgNjMuOTI3NyA4OC42NDY1IDY0LjA5NTdDODguNjQ2NSA2NC4yNjM3IDg4LjY4NTUgNjQuNDE4IDg4Ljc2MzcgNjQuNTU4NkM4OC44NDE4IDY0LjY5NTMgODguOTU1MSA2NC44MDI3IDg5LjEwMzUgNjQuODgwOUM4OS4yNTU5IDY0Ljk1OSA4OS40Mzk1IDY0Ljk5OCA4OS42NTQzIDY0Ljk5OEM4OS45NDM0IDY0Ljk5OCA5MC4xOTUzIDY0LjkzOTUgOTAuNDEwMiA2NC44MjIzQzkwLjYyODkgNjQuNzAxMiA5MC44MDA4IDY0LjU1NDcgOTAuOTI1OCA2NC4zODI4QzkxLjA1MDggNjQuMjA3IDkxLjExNzIgNjQuMDQxIDkxLjEyNSA2My44ODQ4TDkxLjU4MiA2NC41MTE3QzkxLjUzNTIgNjQuNjcxOSA5MS40NTUxIDY0Ljg0MzggOTEuMzQxOCA2NS4wMjczQzkxLjIyODUgNjUuMjEwOSA5MS4wODAxIDY1LjM4NjcgOTAuODk2NSA2NS41NTQ3QzkwLjcxNjggNjUuNzE4OCA5MC41IDY1Ljg1MzUgOTAuMjQ2MSA2NS45NTlDODkuOTk2MSA2Ni4wNjQ1IDg5LjcwNyA2Ni4xMTcyIDg5LjM3ODkgNjYuMTE3MkM4OC45NjQ4IDY2LjExNzIgODguNTk1NyA2Ni4wMzUyIDg4LjI3MTUgNjUuODcxMUM4Ny45NDczIDY1LjcwMzEgODcuNjkzNCA2NS40Nzg1IDg3LjUwOTggNjUuMTk3M0M4Ny4zMjYyIDY0LjkxMjEgODcuMjM0NCA2NC41ODk4IDg3LjIzNDQgNjQuMjMwNUM4Ny4yMzQ0IDYzLjg5NDUgODcuMjk2OSA2My41OTc3IDg3LjQyMTkgNjMuMzM5OEM4Ny41NTA4IDYzLjA3ODEgODcuNzM4MyA2Mi44NTk0IDg3Ljk4NDQgNjIuNjgzNkM4OC4yMzQ0IDYyLjUwNzggODguNTM5MSA2Mi4zNzUgODguODk4NCA2Mi4yODUyQzg5LjI1NzggNjIuMTkxNCA4OS42NjggNjIuMTQ0NSA5MC4xMjg5IDYyLjE0NDVIOTEuMjM2M1pNOTcuNzMyNCA2NC4yODMyQzk3LjczMjQgNjQuMTQyNiA5Ny42OTczIDY0LjAxNTYgOTcuNjI3IDYzLjkwMjNDOTcuNTU2NiA2My43ODUyIDk3LjQyMTkgNjMuNjc5NyA5Ny4yMjI3IDYzLjU4NTlDOTcuMDI3MyA2My40OTIyIDk2LjczODMgNjMuNDA2MiA5Ni4zNTU1IDYzLjMyODFDOTYuMDE5NSA2My4yNTM5IDk1LjcxMDkgNjMuMTY2IDk1LjQyOTcgNjMuMDY0NUM5NS4xNTIzIDYyLjk1OSA5NC45MTQxIDYyLjgzMiA5NC43MTQ4IDYyLjY4MzZDOTQuNTE1NiA2Mi41MzUyIDk0LjM2MTMgNjIuMzU5NCA5NC4yNTIgNjIuMTU2MkM5NC4xNDI2IDYxLjk1MzEgOTQuMDg3OSA2MS43MTg4IDk0LjA4NzkgNjEuNDUzMUM5NC4wODc5IDYxLjE5NTMgOTQuMTQ0NSA2MC45NTEyIDk0LjI1NzggNjAuNzIwN0M5NC4zNzExIDYwLjQ5MDIgOTQuNTMzMiA2MC4yODcxIDk0Ljc0NDEgNjAuMTExM0M5NC45NTUxIDU5LjkzNTUgOTUuMjEwOSA1OS43OTY5IDk1LjUxMTcgNTkuNjk1M0M5NS44MTY0IDU5LjU5MzggOTYuMTU2MiA1OS41NDMgOTYuNTMxMiA1OS41NDNDOTcuMDYyNSA1OS41NDMgOTcuNTE3NiA1OS42MzI4IDk3Ljg5NjUgNTkuODEyNUM5OC4yNzkzIDU5Ljk4ODMgOTguNTcyMyA2MC4yMjg1IDk4Ljc3NTQgNjAuNTMzMkM5OC45Nzg1IDYwLjgzNCA5OS4wODAxIDYxLjE3MzggOTkuMDgwMSA2MS41NTI3SDk3LjY2OEM5Ny42NjggNjEuMzg0OCA5Ny42MjUgNjEuMjI4NSA5Ny41MzkxIDYxLjA4NEM5Ny40NTcgNjAuOTM1NSA5Ny4zMzIgNjAuODE2NCA5Ny4xNjQxIDYwLjcyNjZDOTYuOTk2MSA2MC42MzI4IDk2Ljc4NTIgNjAuNTg1OSA5Ni41MzEyIDYwLjU4NTlDOTYuMjg5MSA2MC41ODU5IDk2LjA4NzkgNjAuNjI1IDk1LjkyNzcgNjAuNzAzMUM5NS43NzE1IDYwLjc3NzMgOTUuNjU0MyA2MC44NzUgOTUuNTc2MiA2MC45OTYxQzk1LjUwMiA2MS4xMTcyIDk1LjQ2NDggNjEuMjUgOTUuNDY0OCA2MS4zOTQ1Qzk1LjQ2NDggNjEuNSA5NS40ODQ0IDYxLjU5NTcgOTUuNTIzNCA2MS42ODE2Qzk1LjU2NjQgNjEuNzYzNyA5NS42MzY3IDYxLjgzOTggOTUuNzM0NCA2MS45MTAyQzk1LjgzMiA2MS45NzY2IDk1Ljk2NDggNjIuMDM5MSA5Ni4xMzI4IDYyLjA5NzdDOTYuMzA0NyA2Mi4xNTYyIDk2LjUxOTUgNjIuMjEyOSA5Ni43NzczIDYyLjI2NzZDOTcuMjYxNyA2Mi4zNjkxIDk3LjY3NzcgNjIuNSA5OC4wMjU0IDYyLjY2MDJDOTguMzc3IDYyLjgxNjQgOTguNjQ2NSA2My4wMTk1IDk4LjgzNCA2My4yNjk1Qzk5LjAyMTUgNjMuNTE1NiA5OS4xMTUyIDYzLjgyODEgOTkuMTE1MiA2NC4yMDdDOTkuMTE1MiA2NC40ODgzIDk5LjA1NDcgNjQuNzQ2MSA5OC45MzM2IDY0Ljk4MDVDOTguODE2NCA2NS4yMTA5IDk4LjY0NDUgNjUuNDEyMSA5OC40MTggNjUuNTg0Qzk4LjE5MTQgNjUuNzUyIDk3LjkxOTkgNjUuODgyOCA5Ny42MDM1IDY1Ljk3NjZDOTcuMjkxIDY2LjA3MDMgOTYuOTM5NSA2Ni4xMTcyIDk2LjU0ODggNjYuMTE3MkM5NS45NzQ2IDY2LjExNzIgOTUuNDg4MyA2Ni4wMTU2IDk1LjA4OTggNjUuODEyNUM5NC42OTE0IDY1LjYwNTUgOTQuMzg4NyA2NS4zNDE4IDk0LjE4MTYgNjUuMDIxNUM5My45Nzg1IDY0LjY5NzMgOTMuODc3IDY0LjM2MTMgOTMuODc3IDY0LjAxMzdIOTUuMjQyMkM5NS4yNTc4IDY0LjI3NTQgOTUuMzMwMSA2NC40ODQ0IDk1LjQ1OSA2NC42NDA2Qzk1LjU5MTggNjQuNzkzIDk1Ljc1NTkgNjQuOTA0MyA5NS45NTEyIDY0Ljk3NDZDOTYuMTUwNCA2NS4wNDEgOTYuMzU1NSA2NS4wNzQyIDk2LjU2NjQgNjUuMDc0MkM5Ni44MjAzIDY1LjA3NDIgOTcuMDMzMiA2NS4wNDEgOTcuMjA1MSA2NC45NzQ2Qzk3LjM3NyA2NC45MDQzIDk3LjUwNzggNjQuODEwNSA5Ny41OTc3IDY0LjY5MzRDOTcuNjg3NSA2NC41NzIzIDk3LjczMjQgNjQuNDM1NSA5Ny43MzI0IDY0LjI4MzJaTTEwMy41MDggNTkuNjYwMlY2MC42OTE0SDk5LjkzMzZWNTkuNjYwMkgxMDMuNTA4Wk0xMDAuOTY1IDU4LjEwNzRIMTAyLjM3N1Y2NC4yNDhDMTAyLjM3NyA2NC40NDM0IDEwMi40MDQgNjQuNTkzOCAxMDIuNDU5IDY0LjY5OTJDMTAyLjUxOCA2NC44MDA4IDEwMi41OTggNjQuODY5MSAxMDIuNjk5IDY0LjkwNDNDMTAyLjgwMSA2NC45Mzk1IDEwMi45MiA2NC45NTcgMTAzLjA1NyA2NC45NTdDMTAzLjE1NCA2NC45NTcgMTAzLjI0OCA2NC45NTEyIDEwMy4zMzggNjQuOTM5NUMxMDMuNDI4IDY0LjkyNzcgMTAzLjUgNjQuOTE2IDEwMy41NTUgNjQuOTA0M0wxMDMuNTYxIDY1Ljk4MjRDMTAzLjQ0MyA2Ni4wMTc2IDEwMy4zMDcgNjYuMDQ4OCAxMDMuMTUgNjYuMDc2MkMxMDIuOTk4IDY2LjEwMzUgMTAyLjgyMiA2Ni4xMTcyIDEwMi42MjMgNjYuMTE3MkMxMDIuMjk5IDY2LjExNzIgMTAyLjAxMiA2Ni4wNjA1IDEwMS43NjIgNjUuOTQ3M0MxMDEuNTEyIDY1LjgzMDEgMTAxLjMxNiA2NS42NDA2IDEwMS4xNzYgNjUuMzc4OUMxMDEuMDM1IDY1LjExNzIgMTAwLjk2NSA2NC43Njk1IDEwMC45NjUgNjQuMzM1OVY1OC4xMDc0Wk0xMTEuOSA2NC41MDU5VjU5LjY2MDJIMTEzLjMxOFY2NkgxMTEuOTgyTDExMS45IDY0LjUwNTlaTTExMi4xIDYzLjE4NzVMMTEyLjU3NCA2My4xNzU4QzExMi41NzQgNjMuNjAxNiAxMTIuNTI3IDYzLjk5NDEgMTEyLjQzNCA2NC4zNTM1QzExMi4zNCA2NC43MDkgMTEyLjE5NSA2NS4wMTk1IDExMiA2NS4yODUyQzExMS44MDUgNjUuNTQ2OSAxMTEuNTU1IDY1Ljc1MiAxMTEuMjUgNjUuOTAwNEMxMTAuOTQ1IDY2LjA0NDkgMTEwLjU4IDY2LjExNzIgMTEwLjE1NCA2Ni4xMTcyQzEwOS44NDYgNjYuMTE3MiAxMDkuNTYyIDY2LjA3MjMgMTA5LjMwNSA2NS45ODI0QzEwOS4wNDcgNjUuODkyNiAxMDguODI0IDY1Ljc1MzkgMTA4LjYzNyA2NS41NjY0QzEwOC40NTMgNjUuMzc4OSAxMDguMzExIDY1LjEzNDggMTA4LjIwOSA2NC44MzRDMTA4LjEwNyA2NC41MzMyIDEwOC4wNTcgNjQuMTczOCAxMDguMDU3IDYzLjc1NTlWNTkuNjYwMkgxMDkuNDY5VjYzLjc2NzZDMTA5LjQ2OSA2My45OTggMTA5LjQ5NiA2NC4xOTE0IDEwOS41NTEgNjQuMzQ3N0MxMDkuNjA1IDY0LjUgMTA5LjY4IDY0LjYyMyAxMDkuNzczIDY0LjcxNjhDMTA5Ljg2NyA2NC44MTA1IDEwOS45NzcgNjQuODc3IDExMC4xMDIgNjQuOTE2QzExMC4yMjcgNjQuOTU1MSAxMTAuMzU5IDY0Ljk3NDYgMTEwLjUgNjQuOTc0NkMxMTAuOTAyIDY0Ljk3NDYgMTExLjIxOSA2NC44OTY1IDExMS40NDkgNjQuNzQwMkMxMTEuNjg0IDY0LjU4MDEgMTExLjg1IDY0LjM2NTIgMTExLjk0NyA2NC4wOTU3QzExMi4wNDkgNjMuODI2MiAxMTIuMSA2My41MjM0IDExMi4xIDYzLjE4NzVaTTExNi40MzQgNjAuODc4OVY2OC40Mzc1SDExNS4wMjFWNTkuNjYwMkgxMTYuMzIyTDExNi40MzQgNjAuODc4OVpNMTIwLjU2NCA2Mi43NzE1VjYyLjg5NDVDMTIwLjU2NCA2My4zNTU1IDEyMC41MSA2My43ODMyIDEyMC40IDY0LjE3NzdDMTIwLjI5NSA2NC41Njg0IDEyMC4xMzcgNjQuOTEwMiAxMTkuOTI2IDY1LjIwMzFDMTE5LjcxOSA2NS40OTIyIDExOS40NjMgNjUuNzE2OCAxMTkuMTU4IDY1Ljg3N0MxMTguODU0IDY2LjAzNzEgMTE4LjUwMiA2Ni4xMTcyIDExOC4xMDQgNjYuMTE3MkMxMTcuNzA5IDY2LjExNzIgMTE3LjM2MyA2Ni4wNDQ5IDExNy4wNjYgNjUuOTAwNEMxMTYuNzczIDY1Ljc1MiAxMTYuNTI1IDY1LjU0MyAxMTYuMzIyIDY1LjI3MzRDMTE2LjExOSA2NS4wMDM5IDExNS45NTUgNjQuNjg3NSAxMTUuODMgNjQuMzI0MkMxMTUuNzA5IDYzLjk1NyAxMTUuNjIzIDYzLjU1NDcgMTE1LjU3MiA2My4xMTcyVjYyLjY0MjZDMTE1LjYyMyA2Mi4xNzc3IDExNS43MDkgNjEuNzU1OSAxMTUuODMgNjEuMzc3QzExNS45NTUgNjAuOTk4IDExNi4xMTkgNjAuNjcxOSAxMTYuMzIyIDYwLjM5ODRDMTE2LjUyNSA2MC4xMjUgMTE2Ljc3MyA1OS45MTQxIDExNy4wNjYgNTkuNzY1NkMxMTcuMzU5IDU5LjYxNzIgMTE3LjcwMSA1OS41NDMgMTE4LjA5MiA1OS41NDNDMTE4LjQ5IDU5LjU0MyAxMTguODQ0IDU5LjYyMTEgMTE5LjE1MiA1OS43NzczQzExOS40NjEgNTkuOTI5NyAxMTkuNzIxIDYwLjE0ODQgMTE5LjkzMiA2MC40MzM2QzEyMC4xNDMgNjAuNzE0OCAxMjAuMzAxIDYxLjA1NDcgMTIwLjQwNiA2MS40NTMxQzEyMC41MTIgNjEuODQ3NyAxMjAuNTY0IDYyLjI4NzEgMTIwLjU2NCA2Mi43NzE1Wk0xMTkuMTUyIDYyLjg5NDVWNjIuNzcxNUMxMTkuMTUyIDYyLjQ3ODUgMTE5LjEyNSA2Mi4yMDcgMTE5LjA3IDYxLjk1N0MxMTkuMDE2IDYxLjcwMzEgMTE4LjkzIDYxLjQ4MDUgMTE4LjgxMiA2MS4yODkxQzExOC42OTUgNjEuMDk3NyAxMTguNTQ1IDYwLjk0OTIgMTE4LjM2MSA2MC44NDM4QzExOC4xODIgNjAuNzM0NCAxMTcuOTY1IDYwLjY3OTcgMTE3LjcxMSA2MC42Nzk3QzExNy40NjEgNjAuNjc5NyAxMTcuMjQ2IDYwLjcyMjcgMTE3LjA2NiA2MC44MDg2QzExNi44ODcgNjAuODkwNiAxMTYuNzM2IDYxLjAwNTkgMTE2LjYxNSA2MS4xNTQzQzExNi40OTQgNjEuMzAyNyAxMTYuNCA2MS40NzY2IDExNi4zMzQgNjEuNjc1OEMxMTYuMjY4IDYxLjg3MTEgMTE2LjIyMSA2Mi4wODQgMTE2LjE5MyA2Mi4zMTQ1VjYzLjQ1MTJDMTE2LjI0IDYzLjczMjQgMTE2LjMyIDYzLjk5MDIgMTE2LjQzNCA2NC4yMjQ2QzExNi41NDcgNjQuNDU5IDExNi43MDcgNjQuNjQ2NSAxMTYuOTE0IDY0Ljc4NzFDMTE3LjEyNSA2NC45MjM4IDExNy4zOTUgNjQuOTkyMiAxMTcuNzIzIDY0Ljk5MjJDMTE3Ljk3NyA2NC45OTIyIDExOC4xOTMgNjQuOTM3NSAxMTguMzczIDY0LjgyODFDMTE4LjU1MyA2NC43MTg4IDExOC42OTkgNjQuNTY4NCAxMTguODEyIDY0LjM3N0MxMTguOTMgNjQuMTgxNiAxMTkuMDE2IDYzLjk1NyAxMTkuMDcgNjMuNzAzMUMxMTkuMTI1IDYzLjQ0OTIgMTE5LjE1MiA2My4xNzk3IDExOS4xNTIgNjIuODk0NVpNMTI1Ljg4MyA2NC42ODc1VjU3SDEyNy4zMDFWNjZIMTI2LjAxOEwxMjUuODgzIDY0LjY4NzVaTTEyMS43NTggNjIuOTAwNFY2Mi43NzczQzEyMS43NTggNjIuMjk2OSAxMjEuODE0IDYxLjg1OTQgMTIxLjkyOCA2MS40NjQ4QzEyMi4wNDEgNjEuMDY2NCAxMjIuMjA1IDYwLjcyNDYgMTIyLjQyIDYwLjQzOTVDMTIyLjYzNSA2MC4xNTA0IDEyMi44OTYgNTkuOTI5NyAxMjMuMjA1IDU5Ljc3NzNDMTIzLjUxNCA1OS42MjExIDEyMy44NjEgNTkuNTQzIDEyNC4yNDggNTkuNTQzQzEyNC42MzEgNTkuNTQzIDEyNC45NjcgNTkuNjE3MiAxMjUuMjU2IDU5Ljc2NTZDMTI1LjU0NSA1OS45MTQxIDEyNS43OTEgNjAuMTI3IDEyNS45OTQgNjAuNDA0M0MxMjYuMTk3IDYwLjY3NzcgMTI2LjM1OSA2MS4wMDU5IDEyNi40OCA2MS4zODg3QzEyNi42MDIgNjEuNzY3NiAxMjYuNjg4IDYyLjE4OTUgMTI2LjczOCA2Mi42NTQzVjYzLjA0NjlDMTI2LjY4OCA2My41IDEyNi42MDIgNjMuOTE0MSAxMjYuNDggNjQuMjg5MUMxMjYuMzU5IDY0LjY2NDEgMTI2LjE5NyA2NC45ODgzIDEyNS45OTQgNjUuMjYxN0MxMjUuNzkxIDY1LjUzNTIgMTI1LjU0MyA2NS43NDYxIDEyNS4yNSA2NS44OTQ1QzEyNC45NjEgNjYuMDQzIDEyNC42MjMgNjYuMTE3MiAxMjQuMjM2IDY2LjExNzJDMTIzLjg1NCA2Ni4xMTcyIDEyMy41MDggNjYuMDM3MSAxMjMuMTk5IDY1Ljg3N0MxMjIuODk1IDY1LjcxNjggMTIyLjYzNSA2NS40OTIyIDEyMi40MiA2NS4yMDMxQzEyMi4yMDUgNjQuOTE0MSAxMjIuMDQxIDY0LjU3NDIgMTIxLjkyOCA2NC4xODM2QzEyMS44MTQgNjMuNzg5MSAxMjEuNzU4IDYzLjM2MTMgMTIxLjc1OCA2Mi45MDA0Wk0xMjMuMTcgNjIuNzc3M1Y2Mi45MDA0QzEyMy4xNyA2My4xODk1IDEyMy4xOTUgNjMuNDU5IDEyMy4yNDYgNjMuNzA5QzEyMy4zMDEgNjMuOTU5IDEyMy4zODUgNjQuMTc5NyAxMjMuNDk4IDY0LjM3MTFDMTIzLjYxMSA2NC41NTg2IDEyMy43NTggNjQuNzA3IDEyMy45MzggNjQuODE2NEMxMjQuMTIxIDY0LjkyMTkgMTI0LjM0IDY0Ljk3NDYgMTI0LjU5NCA2NC45NzQ2QzEyNC45MTQgNjQuOTc0NiAxMjUuMTc4IDY0LjkwNDMgMTI1LjM4NSA2NC43NjM3QzEyNS41OTIgNjQuNjIzIDEyNS43NTQgNjQuNDMzNiAxMjUuODcxIDY0LjE5NTNDMTI1Ljk5MiA2My45NTMxIDEyNi4wNzQgNjMuNjgzNiAxMjYuMTE3IDYzLjM4NjdWNjIuMzI2MkMxMjYuMDk0IDYyLjA5NTcgMTI2LjA0NSA2MS44ODA5IDEyNS45NzEgNjEuNjgxNkMxMjUuOSA2MS40ODI0IDEyNS44MDUgNjEuMzA4NiAxMjUuNjg0IDYxLjE2MDJDMTI1LjU2MiA2MS4wMDc4IDEyNS40MTIgNjAuODkwNiAxMjUuMjMyIDYwLjgwODZDMTI1LjA1NyA2MC43MjI3IDEyNC44NDggNjAuNjc5NyAxMjQuNjA1IDYwLjY3OTdDMTI0LjM0OCA2MC42Nzk3IDEyNC4xMjkgNjAuNzM0NCAxMjMuOTQ5IDYwLjg0MzhDMTIzLjc3IDYwLjk1MzEgMTIzLjYyMSA2MS4xMDM1IDEyMy41MDQgNjEuMjk0OUMxMjMuMzkxIDYxLjQ4NjMgMTIzLjMwNyA2MS43MDkgMTIzLjI1MiA2MS45NjI5QzEyMy4xOTcgNjIuMjE2OCAxMjMuMTcgNjIuNDg4MyAxMjMuMTcgNjIuNzc3M1pNMTMyLjYwMiA2NC43Mjg1VjYxLjcwNTFDMTMyLjYwMiA2MS40Nzg1IDEzMi41NjEgNjEuMjgzMiAxMzIuNDc5IDYxLjExOTFDMTMyLjM5NiA2MC45NTUxIDEzMi4yNzEgNjAuODI4MSAxMzIuMTA0IDYwLjczODNDMTMxLjkzOSA2MC42NDg0IDEzMS43MzIgNjAuNjAzNSAxMzEuNDgyIDYwLjYwMzVDMTMxLjI1MiA2MC42MDM1IDEzMS4wNTMgNjAuNjQyNiAxMzAuODg1IDYwLjcyMDdDMTMwLjcxNyA2MC43OTg4IDEzMC41ODYgNjAuOTA0MyAxMzAuNDkyIDYxLjAzNzFDMTMwLjM5OCA2MS4xNjk5IDEzMC4zNTIgNjEuMzIwMyAxMzAuMzUyIDYxLjQ4ODNIMTI4Ljk0NUMxMjguOTQ1IDYxLjIzODMgMTI5LjAwNiA2MC45OTYxIDEyOS4xMjcgNjAuNzYxN0MxMjkuMjQ4IDYwLjUyNzMgMTI5LjQyNCA2MC4zMTg0IDEyOS42NTQgNjAuMTM0OEMxMjkuODg1IDU5Ljk1MTIgMTMwLjE2IDU5LjgwNjYgMTMwLjQ4IDU5LjcwMTJDMTMwLjgwMSA1OS41OTU3IDEzMS4xNiA1OS41NDMgMTMxLjU1OSA1OS41NDNDMTMyLjAzNSA1OS41NDMgMTMyLjQ1NyA1OS42MjMgMTMyLjgyNCA1OS43ODMyQzEzMy4xOTUgNTkuOTQzNCAxMzMuNDg2IDYwLjE4NTUgMTMzLjY5NyA2MC41MDk4QzEzMy45MTIgNjAuODMwMSAxMzQuMDIgNjEuMjMyNCAxMzQuMDIgNjEuNzE2OFY2NC41MzUyQzEzNC4wMiA2NC44MjQyIDEzNC4wMzkgNjUuMDg0IDEzNC4wNzggNjUuMzE0NUMxMzQuMTIxIDY1LjU0MSAxMzQuMTgyIDY1LjczODMgMTM0LjI2IDY1LjkwNjJWNjZIMTMyLjgxMkMxMzIuNzQ2IDY1Ljg0NzcgMTMyLjY5MyA2NS42NTQzIDEzMi42NTQgNjUuNDE5OUMxMzIuNjE5IDY1LjE4MTYgMTMyLjYwMiA2NC45NTEyIDEzMi42MDIgNjQuNzI4NVpNMTMyLjgwNyA2Mi4xNDQ1TDEzMi44MTggNjMuMDE3NkgxMzEuODA1QzEzMS41NDMgNjMuMDE3NiAxMzEuMzEyIDYzLjA0MyAxMzEuMTEzIDYzLjA5MzhDMTMwLjkxNCA2My4xNDA2IDEzMC43NDggNjMuMjEwOSAxMzAuNjE1IDYzLjMwNDdDMTMwLjQ4MiA2My4zOTg0IDEzMC4zODMgNjMuNTExNyAxMzAuMzE2IDYzLjY0NDVDMTMwLjI1IDYzLjc3NzMgMTMwLjIxNyA2My45Mjc3IDEzMC4yMTcgNjQuMDk1N0MxMzAuMjE3IDY0LjI2MzcgMTMwLjI1NiA2NC40MTggMTMwLjMzNCA2NC41NTg2QzEzMC40MTIgNjQuNjk1MyAxMzAuNTI1IDY0LjgwMjcgMTMwLjY3NCA2NC44ODA5QzEzMC44MjYgNjQuOTU5IDEzMS4wMSA2NC45OTggMTMxLjIyNSA2NC45OThDMTMxLjUxNCA2NC45OTggMTMxLjc2NiA2NC45Mzk1IDEzMS45OCA2NC44MjIzQzEzMi4xOTkgNjQuNzAxMiAxMzIuMzcxIDY0LjU1NDcgMTMyLjQ5NiA2NC4zODI4QzEzMi42MjEgNjQuMjA3IDEzMi42ODggNjQuMDQxIDEzMi42OTUgNjMuODg0OEwxMzMuMTUyIDY0LjUxMTdDMTMzLjEwNSA2NC42NzE5IDEzMy4wMjUgNjQuODQzOCAxMzIuOTEyIDY1LjAyNzNDMTMyLjc5OSA2NS4yMTA5IDEzMi42NSA2NS4zODY3IDEzMi40NjcgNjUuNTU0N0MxMzIuMjg3IDY1LjcxODggMTMyLjA3IDY1Ljg1MzUgMTMxLjgxNiA2NS45NTlDMTMxLjU2NiA2Ni4wNjQ1IDEzMS4yNzcgNjYuMTE3MiAxMzAuOTQ5IDY2LjExNzJDMTMwLjUzNSA2Ni4xMTcyIDEzMC4xNjYgNjYuMDM1MiAxMjkuODQyIDY1Ljg3MTFDMTI5LjUxOCA2NS43MDMxIDEyOS4yNjQgNjUuNDc4NSAxMjkuMDggNjUuMTk3M0MxMjguODk2IDY0LjkxMjEgMTI4LjgwNSA2NC41ODk4IDEyOC44MDUgNjQuMjMwNUMxMjguODA1IDYzLjg5NDUgMTI4Ljg2NyA2My41OTc3IDEyOC45OTIgNjMuMzM5OEMxMjkuMTIxIDYzLjA3ODEgMTI5LjMwOSA2Mi44NTk0IDEyOS41NTUgNjIuNjgzNkMxMjkuODA1IDYyLjUwNzggMTMwLjEwOSA2Mi4zNzUgMTMwLjQ2OSA2Mi4yODUyQzEzMC44MjggNjIuMTkxNCAxMzEuMjM4IDYyLjE0NDUgMTMxLjY5OSA2Mi4xNDQ1SDEzMi44MDdaTTEzOC42NTIgNTkuNjYwMlY2MC42OTE0SDEzNS4wNzhWNTkuNjYwMkgxMzguNjUyWk0xMzYuMTA5IDU4LjEwNzRIMTM3LjUyMVY2NC4yNDhDMTM3LjUyMSA2NC40NDM0IDEzNy41NDkgNjQuNTkzOCAxMzcuNjA0IDY0LjY5OTJDMTM3LjY2MiA2NC44MDA4IDEzNy43NDIgNjQuODY5MSAxMzcuODQ0IDY0LjkwNDNDMTM3Ljk0NSA2NC45Mzk1IDEzOC4wNjQgNjQuOTU3IDEzOC4yMDEgNjQuOTU3QzEzOC4yOTkgNjQuOTU3IDEzOC4zOTMgNjQuOTUxMiAxMzguNDgyIDY0LjkzOTVDMTM4LjU3MiA2NC45Mjc3IDEzOC42NDUgNjQuOTE2IDEzOC42OTkgNjQuOTA0M0wxMzguNzA1IDY1Ljk4MjRDMTM4LjU4OCA2Ni4wMTc2IDEzOC40NTEgNjYuMDQ4OCAxMzguMjk1IDY2LjA3NjJDMTM4LjE0MyA2Ni4xMDM1IDEzNy45NjcgNjYuMTE3MiAxMzcuNzY4IDY2LjExNzJDMTM3LjQ0MyA2Ni4xMTcyIDEzNy4xNTYgNjYuMDYwNSAxMzYuOTA2IDY1Ljk0NzNDMTM2LjY1NiA2NS44MzAxIDEzNi40NjEgNjUuNjQwNiAxMzYuMzIgNjUuMzc4OUMxMzYuMTggNjUuMTE3MiAxMzYuMTA5IDY0Ljc2OTUgMTM2LjEwOSA2NC4zMzU5VjU4LjEwNzRaTTE0Mi43ODcgNjYuMTE3MkMxNDIuMzE4IDY2LjExNzIgMTQxLjg5NSA2Ni4wNDEgMTQxLjUxNiA2NS44ODg3QzE0MS4xNDEgNjUuNzMyNCAxNDAuODIgNjUuNTE1NiAxNDAuNTU1IDY1LjIzODNDMTQwLjI5MyA2NC45NjA5IDE0MC4wOTIgNjQuNjM0OCAxMzkuOTUxIDY0LjI1OThDMTM5LjgxMSA2My44ODQ4IDEzOS43NCA2My40ODA1IDEzOS43NCA2My4wNDY5VjYyLjgxMjVDMTM5Ljc0IDYyLjMxNjQgMTM5LjgxMiA2MS44NjcyIDEzOS45NTcgNjEuNDY0OEMxNDAuMTAyIDYxLjA2MjUgMTQwLjMwMyA2MC43MTg4IDE0MC41NjEgNjAuNDMzNkMxNDAuODE4IDYwLjE0NDUgMTQxLjEyMyA1OS45MjM4IDE0MS40NzUgNTkuNzcxNUMxNDEuODI2IDU5LjYxOTEgMTQyLjIwNyA1OS41NDMgMTQyLjYxNyA1OS41NDNDMTQzLjA3IDU5LjU0MyAxNDMuNDY3IDU5LjYxOTEgMTQzLjgwNyA1OS43NzE1QzE0NC4xNDYgNTkuOTIzOCAxNDQuNDI4IDYwLjEzODcgMTQ0LjY1IDYwLjQxNkMxNDQuODc3IDYwLjY4OTUgMTQ1LjA0NSA2MS4wMTU2IDE0NS4xNTQgNjEuMzk0NUMxNDUuMjY4IDYxLjc3MzQgMTQ1LjMyNCA2Mi4xOTE0IDE0NS4zMjQgNjIuNjQ4NFY2My4yNTJIMTQwLjQyNlY2Mi4yMzgzSDE0My45M1Y2Mi4xMjdDMTQzLjkyMiA2MS44NzMgMTQzLjg3MSA2MS42MzQ4IDE0My43NzcgNjEuNDEyMUMxNDMuNjg4IDYxLjE4OTUgMTQzLjU0OSA2MS4wMDk4IDE0My4zNjEgNjAuODczQzE0My4xNzQgNjAuNzM2MyAxNDIuOTI0IDYwLjY2OCAxNDIuNjExIDYwLjY2OEMxNDIuMzc3IDYwLjY2OCAxNDIuMTY4IDYwLjcxODggMTQxLjk4NCA2MC44MjAzQzE0MS44MDUgNjAuOTE4IDE0MS42NTQgNjEuMDYwNSAxNDEuNTMzIDYxLjI0OEMxNDEuNDEyIDYxLjQzNTUgMTQxLjMxOCA2MS42NjIxIDE0MS4yNTIgNjEuOTI3N0MxNDEuMTg5IDYyLjE4OTUgMTQxLjE1OCA2Mi40ODQ0IDE0MS4xNTggNjIuODEyNVY2My4wNDY5QzE0MS4xNTggNjMuMzI0MiAxNDEuMTk1IDYzLjU4MiAxNDEuMjcgNjMuODIwM0MxNDEuMzQ4IDY0LjA1NDcgMTQxLjQ2MSA2NC4yNTk4IDE0MS42MDkgNjQuNDM1NUMxNDEuNzU4IDY0LjYxMTMgMTQxLjkzOCA2NC43NSAxNDIuMTQ4IDY0Ljg1MTZDMTQyLjM1OSA2NC45NDkyIDE0Mi42IDY0Ljk5OCAxNDIuODY5IDY0Ljk5OEMxNDMuMjA5IDY0Ljk5OCAxNDMuNTEyIDY0LjkyOTcgMTQzLjc3NyA2NC43OTNDMTQ0LjA0MyA2NC42NTYyIDE0NC4yNzMgNjQuNDYyOSAxNDQuNDY5IDY0LjIxMjlMMTQ1LjIxMyA2NC45MzM2QzE0NS4wNzYgNjUuMTMyOCAxNDQuODk4IDY1LjMyNDIgMTQ0LjY4IDY1LjUwNzhDMTQ0LjQ2MSA2NS42ODc1IDE0NC4xOTMgNjUuODM0IDE0My44NzcgNjUuOTQ3M0MxNDMuNTY0IDY2LjA2MDUgMTQzLjIwMSA2Ni4xMTcyIDE0Mi43ODcgNjYuMTE3MlpNMTUzLjY4OCA1Ny40Mzk1VjY2SDE1Mi4yNzVWNTkuMTE1MkwxNTAuMTg0IDU5LjgyNDJWNTguNjU4MkwxNTMuNTE4IDU3LjQzOTVIMTUzLjY4OFpNMTYwLjg1MiA2NC42ODc1VjU3SDE2Mi4yN1Y2NkgxNjAuOTg2TDE2MC44NTIgNjQuNjg3NVpNMTU2LjcyNyA2Mi45MDA0VjYyLjc3NzNDMTU2LjcyNyA2Mi4yOTY5IDE1Ni43ODMgNjEuODU5NCAxNTYuODk2IDYxLjQ2NDhDMTU3LjAxIDYxLjA2NjQgMTU3LjE3NCA2MC43MjQ2IDE1Ny4zODkgNjAuNDM5NUMxNTcuNjA0IDYwLjE1MDQgMTU3Ljg2NSA1OS45Mjk3IDE1OC4xNzQgNTkuNzc3M0MxNTguNDgyIDU5LjYyMTEgMTU4LjgzIDU5LjU0MyAxNTkuMjE3IDU5LjU0M0MxNTkuNiA1OS41NDMgMTU5LjkzNiA1OS42MTcyIDE2MC4yMjUgNTkuNzY1NkMxNjAuNTE0IDU5LjkxNDEgMTYwLjc2IDYwLjEyNyAxNjAuOTYzIDYwLjQwNDNDMTYxLjE2NiA2MC42Nzc3IDE2MS4zMjggNjEuMDA1OSAxNjEuNDQ5IDYxLjM4ODdDMTYxLjU3IDYxLjc2NzYgMTYxLjY1NiA2Mi4xODk1IDE2MS43MDcgNjIuNjU0M1Y2My4wNDY5QzE2MS42NTYgNjMuNSAxNjEuNTcgNjMuOTE0MSAxNjEuNDQ5IDY0LjI4OTFDMTYxLjMyOCA2NC42NjQxIDE2MS4xNjYgNjQuOTg4MyAxNjAuOTYzIDY1LjI2MTdDMTYwLjc2IDY1LjUzNTIgMTYwLjUxMiA2NS43NDYxIDE2MC4yMTkgNjUuODk0NUMxNTkuOTMgNjYuMDQzIDE1OS41OTIgNjYuMTE3MiAxNTkuMjA1IDY2LjExNzJDMTU4LjgyMiA2Ni4xMTcyIDE1OC40NzcgNjYuMDM3MSAxNTguMTY4IDY1Ljg3N0MxNTcuODYzIDY1LjcxNjggMTU3LjYwNCA2NS40OTIyIDE1Ny4zODkgNjUuMjAzMUMxNTcuMTc0IDY0LjkxNDEgMTU3LjAxIDY0LjU3NDIgMTU2Ljg5NiA2NC4xODM2QzE1Ni43ODMgNjMuNzg5MSAxNTYuNzI3IDYzLjM2MTMgMTU2LjcyNyA2Mi45MDA0Wk0xNTguMTM5IDYyLjc3NzNWNjIuOTAwNEMxNTguMTM5IDYzLjE4OTUgMTU4LjE2NCA2My40NTkgMTU4LjIxNSA2My43MDlDMTU4LjI3IDYzLjk1OSAxNTguMzU0IDY0LjE3OTcgMTU4LjQ2NyA2NC4zNzExQzE1OC41OCA2NC41NTg2IDE1OC43MjcgNjQuNzA3IDE1OC45MDYgNjQuODE2NEMxNTkuMDkgNjQuOTIxOSAxNTkuMzA5IDY0Ljk3NDYgMTU5LjU2MiA2NC45NzQ2QzE1OS44ODMgNjQuOTc0NiAxNjAuMTQ2IDY0LjkwNDMgMTYwLjM1NCA2NC43NjM3QzE2MC41NjEgNjQuNjIzIDE2MC43MjMgNjQuNDMzNiAxNjAuODQgNjQuMTk1M0MxNjAuOTYxIDYzLjk1MzEgMTYxLjA0MyA2My42ODM2IDE2MS4wODYgNjMuMzg2N1Y2Mi4zMjYyQzE2MS4wNjIgNjIuMDk1NyAxNjEuMDE0IDYxLjg4MDkgMTYwLjkzOSA2MS42ODE2QzE2MC44NjkgNjEuNDgyNCAxNjAuNzczIDYxLjMwODYgMTYwLjY1MiA2MS4xNjAyQzE2MC41MzEgNjEuMDA3OCAxNjAuMzgxIDYwLjg5MDYgMTYwLjIwMSA2MC44MDg2QzE2MC4wMjUgNjAuNzIyNyAxNTkuODE2IDYwLjY3OTcgMTU5LjU3NCA2MC42Nzk3QzE1OS4zMTYgNjAuNjc5NyAxNTkuMDk4IDYwLjczNDQgMTU4LjkxOCA2MC44NDM4QzE1OC43MzggNjAuOTUzMSAxNTguNTkgNjEuMTAzNSAxNTguNDczIDYxLjI5NDlDMTU4LjM1OSA2MS40ODYzIDE1OC4yNzUgNjEuNzA5IDE1OC4yMjEgNjEuOTYyOUMxNTguMTY2IDYyLjIxNjggMTU4LjEzOSA2Mi40ODgzIDE1OC4xMzkgNjIuNzc3M1pNMTcwLjgwOSA2NC43Mjg1VjYxLjcwNTFDMTcwLjgwOSA2MS40Nzg1IDE3MC43NjggNjEuMjgzMiAxNzAuNjg2IDYxLjExOTFDMTcwLjYwNCA2MC45NTUxIDE3MC40NzkgNjAuODI4MSAxNzAuMzExIDYwLjczODNDMTcwLjE0NiA2MC42NDg0IDE2OS45MzkgNjAuNjAzNSAxNjkuNjg5IDYwLjYwMzVDMTY5LjQ1OSA2MC42MDM1IDE2OS4yNiA2MC42NDI2IDE2OS4wOTIgNjAuNzIwN0MxNjguOTI0IDYwLjc5ODggMTY4Ljc5MyA2MC45MDQzIDE2OC42OTkgNjEuMDM3MUMxNjguNjA1IDYxLjE2OTkgMTY4LjU1OSA2MS4zMjAzIDE2OC41NTkgNjEuNDg4M0gxNjcuMTUyQzE2Ny4xNTIgNjEuMjM4MyAxNjcuMjEzIDYwLjk5NjEgMTY3LjMzNCA2MC43NjE3QzE2Ny40NTUgNjAuNTI3MyAxNjcuNjMxIDYwLjMxODQgMTY3Ljg2MSA2MC4xMzQ4QzE2OC4wOTIgNTkuOTUxMiAxNjguMzY3IDU5LjgwNjYgMTY4LjY4OCA1OS43MDEyQzE2OS4wMDggNTkuNTk1NyAxNjkuMzY3IDU5LjU0MyAxNjkuNzY2IDU5LjU0M0MxNzAuMjQyIDU5LjU0MyAxNzAuNjY0IDU5LjYyMyAxNzEuMDMxIDU5Ljc4MzJDMTcxLjQwMiA1OS45NDM0IDE3MS42OTMgNjAuMTg1NSAxNzEuOTA0IDYwLjUwOThDMTcyLjExOSA2MC44MzAxIDE3Mi4yMjcgNjEuMjMyNCAxNzIuMjI3IDYxLjcxNjhWNjQuNTM1MkMxNzIuMjI3IDY0LjgyNDIgMTcyLjI0NiA2NS4wODQgMTcyLjI4NSA2NS4zMTQ1QzE3Mi4zMjggNjUuNTQxIDE3Mi4zODkgNjUuNzM4MyAxNzIuNDY3IDY1LjkwNjJWNjZIMTcxLjAyQzE3MC45NTMgNjUuODQ3NyAxNzAuOSA2NS42NTQzIDE3MC44NjEgNjUuNDE5OUMxNzAuODI2IDY1LjE4MTYgMTcwLjgwOSA2NC45NTEyIDE3MC44MDkgNjQuNzI4NVpNMTcxLjAxNCA2Mi4xNDQ1TDE3MS4wMjUgNjMuMDE3NkgxNzAuMDEyQzE2OS43NSA2My4wMTc2IDE2OS41MiA2My4wNDMgMTY5LjMyIDYzLjA5MzhDMTY5LjEyMSA2My4xNDA2IDE2OC45NTUgNjMuMjEwOSAxNjguODIyIDYzLjMwNDdDMTY4LjY4OSA2My4zOTg0IDE2OC41OSA2My41MTE3IDE2OC41MjMgNjMuNjQ0NUMxNjguNDU3IDYzLjc3NzMgMTY4LjQyNCA2My45Mjc3IDE2OC40MjQgNjQuMDk1N0MxNjguNDI0IDY0LjI2MzcgMTY4LjQ2MyA2NC40MTggMTY4LjU0MSA2NC41NTg2QzE2OC42MTkgNjQuNjk1MyAxNjguNzMyIDY0LjgwMjcgMTY4Ljg4MSA2NC44ODA5QzE2OS4wMzMgNjQuOTU5IDE2OS4yMTcgNjQuOTk4IDE2OS40MzIgNjQuOTk4QzE2OS43MjEgNjQuOTk4IDE2OS45NzMgNjQuOTM5NSAxNzAuMTg4IDY0LjgyMjNDMTcwLjQwNiA2NC43MDEyIDE3MC41NzggNjQuNTU0NyAxNzAuNzAzIDY0LjM4MjhDMTcwLjgyOCA2NC4yMDcgMTcwLjg5NSA2NC4wNDEgMTcwLjkwMiA2My44ODQ4TDE3MS4zNTkgNjQuNTExN0MxNzEuMzEyIDY0LjY3MTkgMTcxLjIzMiA2NC44NDM4IDE3MS4xMTkgNjUuMDI3M0MxNzEuMDA2IDY1LjIxMDkgMTcwLjg1NyA2NS4zODY3IDE3MC42NzQgNjUuNTU0N0MxNzAuNDk0IDY1LjcxODggMTcwLjI3NyA2NS44NTM1IDE3MC4wMjMgNjUuOTU5QzE2OS43NzMgNjYuMDY0NSAxNjkuNDg0IDY2LjExNzIgMTY5LjE1NiA2Ni4xMTcyQzE2OC43NDIgNjYuMTE3MiAxNjguMzczIDY2LjAzNTIgMTY4LjA0OSA2NS44NzExQzE2Ny43MjUgNjUuNzAzMSAxNjcuNDcxIDY1LjQ3ODUgMTY3LjI4NyA2NS4xOTczQzE2Ny4xMDQgNjQuOTEyMSAxNjcuMDEyIDY0LjU4OTggMTY3LjAxMiA2NC4yMzA1QzE2Ny4wMTIgNjMuODk0NSAxNjcuMDc0IDYzLjU5NzcgMTY3LjE5OSA2My4zMzk4QzE2Ny4zMjggNjMuMDc4MSAxNjcuNTE2IDYyLjg1OTQgMTY3Ljc2MiA2Mi42ODM2QzE2OC4wMTIgNjIuNTA3OCAxNjguMzE2IDYyLjM3NSAxNjguNjc2IDYyLjI4NTJDMTY5LjAzNSA2Mi4xOTE0IDE2OS40NDUgNjIuMTQ0NSAxNjkuOTA2IDYyLjE0NDVIMTcxLjAxNFpNMTc4LjAxNCA1OS42NjAySDE3OS4yOTdWNjUuODI0MkMxNzkuMjk3IDY2LjM5NDUgMTc5LjE3NiA2Ni44Nzg5IDE3OC45MzQgNjcuMjc3M0MxNzguNjkxIDY3LjY3NTggMTc4LjM1NCA2Ny45Nzg1IDE3Ny45MiA2OC4xODU1QzE3Ny40ODYgNjguMzk2NSAxNzYuOTg0IDY4LjUwMiAxNzYuNDE0IDY4LjUwMkMxNzYuMTcyIDY4LjUwMiAxNzUuOTAyIDY4LjQ2NjggMTc1LjYwNSA2OC4zOTY1QzE3NS4zMTIgNjguMzI2MiAxNzUuMDI3IDY4LjIxMjkgMTc0Ljc1IDY4LjA1NjZDMTc0LjQ3NyA2Ny45MDQzIDE3NC4yNDggNjcuNzAzMSAxNzQuMDY0IDY3LjQ1MzFMMTc0LjcyNyA2Ni42MjExQzE3NC45NTMgNjYuODkwNiAxNzUuMjAzIDY3LjA4NzkgMTc1LjQ3NyA2Ny4yMTI5QzE3NS43NSA2Ny4zMzc5IDE3Ni4wMzcgNjcuNDAwNCAxNzYuMzM4IDY3LjQwMDRDMTc2LjY2MiA2Ny40MDA0IDE3Ni45MzggNjcuMzM5OCAxNzcuMTY0IDY3LjIxODhDMTc3LjM5NSA2Ny4xMDE2IDE3Ny41NzIgNjYuOTI3NyAxNzcuNjk3IDY2LjY5NzNDMTc3LjgyMiA2Ni40NjY4IDE3Ny44ODUgNjYuMTg1NSAxNzcuODg1IDY1Ljg1MzVWNjEuMDk1N0wxNzguMDE0IDU5LjY2MDJaTTE3My43MDcgNjIuOTAwNFY2Mi43NzczQzE3My43MDcgNjIuMjk2OSAxNzMuNzY2IDYxLjg1OTQgMTczLjg4MyA2MS40NjQ4QzE3NCA2MS4wNjY0IDE3NC4xNjggNjAuNzI0NiAxNzQuMzg3IDYwLjQzOTVDMTc0LjYwNSA2MC4xNTA0IDE3NC44NzEgNTkuOTI5NyAxNzUuMTg0IDU5Ljc3NzNDMTc1LjQ5NiA1OS42MjExIDE3NS44NSA1OS41NDMgMTc2LjI0NCA1OS41NDNDMTc2LjY1NCA1OS41NDMgMTc3LjAwNCA1OS42MTcyIDE3Ny4yOTMgNTkuNzY1NkMxNzcuNTg2IDU5LjkxNDEgMTc3LjgzIDYwLjEyNyAxNzguMDI1IDYwLjQwNDNDMTc4LjIyMSA2MC42Nzc3IDE3OC4zNzMgNjEuMDA1OSAxNzguNDgyIDYxLjM4ODdDMTc4LjU5NiA2MS43Njc2IDE3OC42OCA2Mi4xODk1IDE3OC43MzQgNjIuNjU0M1Y2My4wNDY5QzE3OC42ODQgNjMuNSAxNzguNTk4IDYzLjkxNDEgMTc4LjQ3NyA2NC4yODkxQzE3OC4zNTUgNjQuNjY0MSAxNzguMTk1IDY0Ljk4ODMgMTc3Ljk5NiA2NS4yNjE3QzE3Ny43OTcgNjUuNTM1MiAxNzcuNTUxIDY1Ljc0NjEgMTc3LjI1OCA2NS44OTQ1QzE3Ni45NjkgNjYuMDQzIDE3Ni42MjcgNjYuMTE3MiAxNzYuMjMyIDY2LjExNzJDMTc1Ljg0NiA2Ni4xMTcyIDE3NS40OTYgNjYuMDM3MSAxNzUuMTg0IDY1Ljg3N0MxNzQuODc1IDY1LjcxNjggMTc0LjYwOSA2NS40OTIyIDE3NC4zODcgNjUuMjAzMUMxNzQuMTY4IDY0LjkxNDEgMTc0IDY0LjU3NDIgMTczLjg4MyA2NC4xODM2QzE3My43NjYgNjMuNzg5MSAxNzMuNzA3IDYzLjM2MTMgMTczLjcwNyA2Mi45MDA0Wk0xNzUuMTE5IDYyLjc3NzNWNjIuOTAwNEMxNzUuMTE5IDYzLjE4OTUgMTc1LjE0NiA2My40NTkgMTc1LjIwMSA2My43MDlDMTc1LjI2IDYzLjk1OSAxNzUuMzQ4IDY0LjE3OTcgMTc1LjQ2NSA2NC4zNzExQzE3NS41ODYgNjQuNTU4NiAxNzUuNzM4IDY0LjcwNyAxNzUuOTIyIDY0LjgxNjRDMTc2LjEwOSA2NC45MjE5IDE3Ni4zMyA2NC45NzQ2IDE3Ni41ODQgNjQuOTc0NkMxNzYuOTE2IDY0Ljk3NDYgMTc3LjE4OCA2NC45MDQzIDE3Ny4zOTggNjQuNzYzN0MxNzcuNjEzIDY0LjYyMyAxNzcuNzc3IDY0LjQzMzYgMTc3Ljg5MSA2NC4xOTUzQzE3OC4wMDggNjMuOTUzMSAxNzguMDkgNjMuNjgzNiAxNzguMTM3IDYzLjM4NjdWNjIuMzI2MkMxNzguMTEzIDYyLjA5NTcgMTc4LjA2NCA2MS44ODA5IDE3Ny45OSA2MS42ODE2QzE3Ny45MiA2MS40ODI0IDE3Ny44MjQgNjEuMzA4NiAxNzcuNzAzIDYxLjE2MDJDMTc3LjU4MiA2MS4wMDc4IDE3Ny40MyA2MC44OTA2IDE3Ny4yNDYgNjAuODA4NkMxNzcuMDYyIDYwLjcyMjcgMTc2Ljg0NiA2MC42Nzk3IDE3Ni41OTYgNjAuNjc5N0MxNzYuMzQyIDYwLjY3OTcgMTc2LjEyMSA2MC43MzQ0IDE3NS45MzQgNjAuODQzOEMxNzUuNzQ2IDYwLjk1MzEgMTc1LjU5MiA2MS4xMDM1IDE3NS40NzEgNjEuMjk0OUMxNzUuMzU0IDYxLjQ4NjMgMTc1LjI2NiA2MS43MDkgMTc1LjIwNyA2MS45NjI5QzE3NS4xNDggNjIuMjE2OCAxNzUuMTE5IDYyLjQ4ODMgMTc1LjExOSA2Mi43NzczWk0xODAuNzQyIDYyLjkwMDRWNjIuNzY1NkMxODAuNzQyIDYyLjMwODYgMTgwLjgwOSA2MS44ODQ4IDE4MC45NDEgNjEuNDk0MUMxODEuMDc0IDYxLjA5OTYgMTgxLjI2NiA2MC43NTc4IDE4MS41MTYgNjAuNDY4OEMxODEuNzcgNjAuMTc1OCAxODIuMDc4IDU5Ljk0OTIgMTgyLjQ0MSA1OS43ODkxQzE4Mi44MDkgNTkuNjI1IDE4My4yMjMgNTkuNTQzIDE4My42ODQgNTkuNTQzQzE4NC4xNDggNTkuNTQzIDE4NC41NjIgNTkuNjI1IDE4NC45MjYgNTkuNzg5MUMxODUuMjkzIDU5Ljk0OTIgMTg1LjYwNCA2MC4xNzU4IDE4NS44NTcgNjAuNDY4OEMxODYuMTExIDYwLjc1NzggMTg2LjMwNSA2MS4wOTk2IDE4Ni40MzggNjEuNDk0MUMxODYuNTcgNjEuODg0OCAxODYuNjM3IDYyLjMwODYgMTg2LjYzNyA2Mi43NjU2VjYyLjkwMDRDMTg2LjYzNyA2My4zNTc0IDE4Ni41NyA2My43ODEyIDE4Ni40MzggNjQuMTcxOUMxODYuMzA1IDY0LjU2MjUgMTg2LjExMSA2NC45MDQzIDE4NS44NTcgNjUuMTk3M0MxODUuNjA0IDY1LjQ4NjMgMTg1LjI5NSA2NS43MTI5IDE4NC45MzIgNjUuODc3QzE4NC41NjggNjYuMDM3MSAxODQuMTU2IDY2LjExNzIgMTgzLjY5NSA2Ni4xMTcyQzE4My4yMyA2Ni4xMTcyIDE4Mi44MTQgNjYuMDM3MSAxODIuNDQ3IDY1Ljg3N0MxODIuMDg0IDY1LjcxMjkgMTgxLjc3NSA2NS40ODYzIDE4MS41MjEgNjUuMTk3M0MxODEuMjY4IDY0LjkwNDMgMTgxLjA3NCA2NC41NjI1IDE4MC45NDEgNjQuMTcxOUMxODAuODA5IDYzLjc4MTIgMTgwLjc0MiA2My4zNTc0IDE4MC43NDIgNjIuOTAwNFpNMTgyLjE1NCA2Mi43NjU2VjYyLjkwMDRDMTgyLjE1NCA2My4xODU1IDE4Mi4xODQgNjMuNDU1MSAxODIuMjQyIDYzLjcwOUMxODIuMzAxIDYzLjk2MjkgMTgyLjM5MyA2NC4xODU1IDE4Mi41MTggNjQuMzc3QzE4Mi42NDMgNjQuNTY4NCAxODIuODAzIDY0LjcxODggMTgyLjk5OCA2NC44MjgxQzE4My4xOTMgNjQuOTM3NSAxODMuNDI2IDY0Ljk5MjIgMTgzLjY5NSA2NC45OTIyQzE4My45NTcgNjQuOTkyMiAxODQuMTg0IDY0LjkzNzUgMTg0LjM3NSA2NC44MjgxQzE4NC41NyA2NC43MTg4IDE4NC43MyA2NC41Njg0IDE4NC44NTUgNjQuMzc3QzE4NC45OCA2NC4xODU1IDE4NS4wNzIgNjMuOTYyOSAxODUuMTMxIDYzLjcwOUMxODUuMTkzIDYzLjQ1NTEgMTg1LjIyNSA2My4xODU1IDE4NS4yMjUgNjIuOTAwNFY2Mi43NjU2QzE4NS4yMjUgNjIuNDg0NCAxODUuMTkzIDYyLjIxODggMTg1LjEzMSA2MS45Njg4QzE4NS4wNzIgNjEuNzE0OCAxODQuOTc5IDYxLjQ5MDIgMTg0Ljg1IDYxLjI5NDlDMTg0LjcyNSA2MS4wOTk2IDE4NC41NjQgNjAuOTQ3MyAxODQuMzY5IDYwLjgzNzlDMTg0LjE3OCA2MC43MjQ2IDE4My45NDkgNjAuNjY4IDE4My42ODQgNjAuNjY4QzE4My40MTggNjAuNjY4IDE4My4xODggNjAuNzI0NiAxODIuOTkyIDYwLjgzNzlDMTgyLjgwMSA2MC45NDczIDE4Mi42NDMgNjEuMDk5NiAxODIuNTE4IDYxLjI5NDlDMTgyLjM5MyA2MS40OTAyIDE4Mi4zMDEgNjEuNzE0OCAxODIuMjQyIDYxLjk2ODhDMTgyLjE4NCA2Mi4yMTg4IDE4Mi4xNTQgNjIuNDg0NCAxODIuMTU0IDYyLjc2NTZaIiBmaWxsPSJibGFjayIgZmlsbC1vcGFjaXR5PSIwLjM4Ii8+CjxwYXRoIGQ9Ik0yODMuNTc0IDYzLjEyNVY2OEgyNTguNzkzVjYzLjgxMDVMMjcwLjgyOCA1MC42ODM2QzI3Mi4xNDggNDkuMTk0IDI3My4xODkgNDcuOTA3NiAyNzMuOTUxIDQ2LjgyNDJDMjc0LjcxMyA0NS43NDA5IDI3NS4yNDYgNDQuNzY3NiAyNzUuNTUxIDQzLjkwNDNDMjc1Ljg3MiA0My4wMjQxIDI3Ni4wMzMgNDIuMTY5MyAyNzYuMDMzIDQxLjMzOThDMjc2LjAzMyA0MC4xNzE5IDI3NS44MTMgMzkuMTQ3OCAyNzUuMzczIDM4LjI2NzZDMjc0Ljk1IDM3LjM3MDQgMjc0LjMyNCAzNi42NjggMjczLjQ5NCAzNi4xNjAyQzI3Mi42NjUgMzUuNjM1NCAyNzEuNjU4IDM1LjM3MyAyNzAuNDczIDM1LjM3M0MyNjkuMTAyIDM1LjM3MyAyNjcuOTUxIDM1LjY2OTMgMjY3LjAyIDM2LjI2MTdDMjY2LjA4OSAzNi44NTQyIDI2NS4zODYgMzcuNjc1MSAyNjQuOTEyIDM4LjcyNDZDMjY0LjQzOCAzOS43NTcyIDI2NC4yMDEgNDAuOTQyMSAyNjQuMjAxIDQyLjI3OTNIMjU4LjA4MkMyNTguMDgyIDQwLjEyOTYgMjU4LjU3MyAzOC4xNjYgMjU5LjU1NSAzNi4zODg3QzI2MC41MzYgMzQuNTk0NCAyNjEuOTU4IDMzLjE3MjUgMjYzLjgyIDMyLjEyM0MyNjUuNjgyIDMxLjA1NjYgMjY3LjkyNSAzMC41MjM0IDI3MC41NDkgMzAuNTIzNEMyNzMuMDIgMzAuNTIzNCAyNzUuMTE5IDMwLjkzODIgMjc2Ljg0NiAzMS43Njc2QzI3OC41NzIgMzIuNTk3IDI3OS44ODQgMzMuNzczNCAyODAuNzgxIDM1LjI5NjlDMjgxLjY5NSAzNi44MjAzIDI4Mi4xNTIgMzguNjIzIDI4Mi4xNTIgNDAuNzA1MUMyODIuMTUyIDQxLjg1NjEgMjgxLjk2NiA0Mi45OTg3IDI4MS41OTQgNDQuMTMyOEMyODEuMjIxIDQ1LjI2NjkgMjgwLjY4OCA0Ni40MDEgMjc5Ljk5NCA0Ny41MzUyQzI3OS4zMTcgNDguNjUyMyAyNzguNTEzIDQ5Ljc3OCAyNzcuNTgyIDUwLjkxMjFDMjc2LjY1MSA1Mi4wMjkzIDI3NS42MjcgNTMuMTYzNCAyNzQuNTEgNTQuMzE0NUwyNjYuNTEyIDYzLjEyNUgyODMuNTc0Wk0zMTIuMjE5IDYzLjEyNVY2OEgyODcuNDM4VjYzLjgxMDVMMjk5LjQ3MyA1MC42ODM2QzMwMC43OTMgNDkuMTk0IDMwMS44MzQgNDcuOTA3NiAzMDIuNTk2IDQ2LjgyNDJDMzAzLjM1OCA0NS43NDA5IDMwMy44OTEgNDQuNzY3NiAzMDQuMTk1IDQzLjkwNDNDMzA0LjUxNyA0My4wMjQxIDMwNC42NzggNDIuMTY5MyAzMDQuNjc4IDQxLjMzOThDMzA0LjY3OCA0MC4xNzE5IDMwNC40NTggMzkuMTQ3OCAzMDQuMDE4IDM4LjI2NzZDMzAzLjU5NSAzNy4zNzA0IDMwMi45NjggMzYuNjY4IDMwMi4xMzkgMzYuMTYwMkMzMDEuMzA5IDM1LjYzNTQgMzAwLjMwMiAzNS4zNzMgMjk5LjExNyAzNS4zNzNDMjk3Ljc0NiAzNS4zNzMgMjk2LjU5NSAzNS42NjkzIDI5NS42NjQgMzYuMjYxN0MyOTQuNzMzIDM2Ljg1NDIgMjk0LjAzMSAzNy42NzUxIDI5My41NTcgMzguNzI0NkMyOTMuMDgzIDM5Ljc1NzIgMjkyLjg0NiA0MC45NDIxIDI5Mi44NDYgNDIuMjc5M0gyODYuNzI3QzI4Ni43MjcgNDAuMTI5NiAyODcuMjE4IDM4LjE2NiAyODguMTk5IDM2LjM4ODdDMjg5LjE4MSAzNC41OTQ0IDI5MC42MDMgMzMuMTcyNSAyOTIuNDY1IDMyLjEyM0MyOTQuMzI3IDMxLjA1NjYgMjk2LjU3IDMwLjUyMzQgMjk5LjE5NCAzMC41MjM0QzMwMS42NjUgMzAuNTIzNCAzMDMuNzY0IDMwLjkzODIgMzA1LjQ5IDMxLjc2NzZDMzA3LjIxNyAzMi41OTcgMzA4LjUyOSAzMy43NzM0IDMwOS40MjYgMzUuMjk2OUMzMTAuMzQgMzYuODIwMyAzMTAuNzk3IDM4LjYyMyAzMTAuNzk3IDQwLjcwNTFDMzEwLjc5NyA0MS44NTYxIDMxMC42MTEgNDIuOTk4NyAzMTAuMjM4IDQ0LjEzMjhDMzA5Ljg2NiA0NS4yNjY5IDMwOS4zMzMgNDYuNDAxIDMwOC42MzkgNDcuNTM1MkMzMDcuOTYyIDQ4LjY1MjMgMzA3LjE1OCA0OS43NzggMzA2LjIyNyA1MC45MTIxQzMwNS4yOTYgNTIuMDI5MyAzMDQuMjcyIDUzLjE2MzQgMzAzLjE1NCA1NC4zMTQ1TDI5NS4xNTYgNjMuMTI1SDMxMi4yMTlaTTMxNi41NjUgMzcuMzAyN0MzMTYuNTY1IDM2LjA2NzEgMzE2Ljg2OSAzNC45MzI5IDMxNy40NzkgMzMuOTAwNEMzMTguMDg4IDMyLjg2NzggMzE4LjkwMSAzMi4wNDY5IDMxOS45MTYgMzEuNDM3NUMzMjAuOTQ5IDMwLjgxMTIgMzIyLjA2NiAzMC40OTggMzIzLjI2OCAzMC40OThDMzI0LjQ4NyAzMC40OTggMzI1LjU5NSAzMC44MTEyIDMyNi41OTQgMzEuNDM3NUMzMjcuNTkzIDMyLjA0NjkgMzI4LjM4OCAzMi44Njc4IDMyOC45ODEgMzMuOTAwNEMzMjkuNTkgMzQuOTMyOSAzMjkuODk1IDM2LjA2NzEgMzI5Ljg5NSAzNy4zMDI3QzMyOS44OTUgMzguNTM4NCAzMjkuNTkgMzkuNjcyNSAzMjguOTgxIDQwLjcwNTFDMzI4LjM4OCA0MS43MjA3IDMyNy41OTMgNDIuNTI0NyAzMjYuNTk0IDQzLjExNzJDMzI1LjU5NSA0My43MDk2IDMyNC40ODcgNDQuMDA1OSAzMjMuMjY4IDQ0LjAwNTlDMzIyLjA2NiA0NC4wMDU5IDMyMC45NDkgNDMuNzA5NiAzMTkuOTE2IDQzLjExNzJDMzE4LjkwMSA0Mi41MjQ3IDMxOC4wODggNDEuNzIwNyAzMTcuNDc5IDQwLjcwNTFDMzE2Ljg2OSAzOS42NzI1IDMxNi41NjUgMzguNTM4NCAzMTYuNTY1IDM3LjMwMjdaTTMxOS45OTMgMzcuMzAyN0MzMTkuOTkzIDM4LjIxNjggMzIwLjMxNCAzOC45ODcgMzIwLjk1NyAzOS42MTMzQzMyMS42MDEgNDAuMjIyNyAzMjIuMzcxIDQwLjUyNzMgMzIzLjI2OCA0MC41MjczQzMyNC4xNjUgNDAuNTI3MyAzMjQuOTE4IDQwLjIyMjcgMzI1LjUyOCAzOS42MTMzQzMyNi4xMzcgMzkuMDAzOSAzMjYuNDQyIDM4LjIzMzcgMzI2LjQ0MiAzNy4zMDI3QzMyNi40NDIgMzYuMzU0OCAzMjYuMTM3IDM1LjU2NzcgMzI1LjUyOCAzNC45NDE0QzMyNC45MTggMzQuMzE1MSAzMjQuMTY1IDM0LjAwMiAzMjMuMjY4IDM0LjAwMkMzMjIuMzcxIDM0LjAwMiAzMjEuNjAxIDM0LjMxNTEgMzIwLjk1NyAzNC45NDE0QzMyMC4zMTQgMzUuNTY3NyAzMTkuOTkzIDM2LjM1NDggMzE5Ljk5MyAzNy4zMDI3Wk0zNTcuODc5IDU1Ljk2NDhIMzY0LjIyN0MzNjQuMDI0IDU4LjM4NTQgMzYzLjM0NyA2MC41NDM2IDM2Mi4xOTYgNjIuNDM5NUMzNjEuMDQ1IDY0LjMxODQgMzU5LjQyOCA2NS43OTk1IDM1Ny4zNDYgNjYuODgyOEMzNTUuMjY0IDY3Ljk2NjEgMzUyLjczNCA2OC41MDc4IDM0OS43NTQgNjguNTA3OEMzNDcuNDY5IDY4LjUwNzggMzQ1LjQxMyA2OC4xMDE2IDM0My41ODQgNjcuMjg5MUMzNDEuNzU2IDY2LjQ1OTYgMzQwLjE5MSA2NS4yOTE3IDMzOC44ODcgNjMuNzg1MkMzMzcuNTg0IDYyLjI2MTcgMzM2LjU4NSA2MC40MjUxIDMzNS44OTEgNTguMjc1NEMzMzUuMjE0IDU2LjEyNTcgMzM0Ljg3NSA1My43MjIgMzM0Ljg3NSA1MS4wNjQ1VjQ3Ljk5MjJDMzM0Ljg3NSA0NS4zMzQ2IDMzNS4yMjIgNDIuOTMxIDMzNS45MTYgNDAuNzgxMkMzMzYuNjI3IDM4LjYzMTUgMzM3LjY0MyAzNi43OTQ5IDMzOC45NjMgMzUuMjcxNUMzNDAuMjg0IDMzLjczMTEgMzQxLjg2NiAzMi41NTQ3IDM0My43MTEgMzEuNzQyMkMzNDUuNTczIDMwLjkyOTcgMzQ3LjY2NCAzMC41MjM0IDM0OS45ODMgMzAuNTIzNEMzNTIuOTI4IDMwLjUyMzQgMzU1LjQxNiAzMS4wNjUxIDM1Ny40NDggMzIuMTQ4NEMzNTkuNDc5IDMzLjIzMTggMzYxLjA1MyAzNC43Mjk4IDM2Mi4xNyAzNi42NDI2QzM2My4zMDUgMzguNTU1MyAzNjMuOTk5IDQwLjc0NzQgMzY0LjI1MiA0My4yMTg4SDM1Ny45MDVDMzU3LjczNSA0MS42Mjc2IDM1Ny4zNjMgNDAuMjY1IDM1Ni43ODggMzkuMTMwOUMzNTYuMjI5IDM3Ljk5NjcgMzU1LjQgMzcuMTMzNSAzNTQuMjk5IDM2LjU0MUMzNTMuMTk5IDM1LjkzMTYgMzUxLjc2IDM1LjYyNyAzNDkuOTgzIDM1LjYyN0MzNDguNTI3IDM1LjYyNyAzNDcuMjU4IDM1Ljg5NzggMzQ2LjE3NCAzNi40Mzk1QzM0NS4wOTEgMzYuOTgxMSAzNDQuMTg1IDM3Ljc3NjcgMzQzLjQ1NyAzOC44MjYyQzM0Mi43MyAzOS44NzU3IDM0Mi4xOCA0MS4xNzA2IDM0MS44MDcgNDIuNzEwOUMzNDEuNDUyIDQ0LjIzNDQgMzQxLjI3NCA0NS45Nzc5IDM0MS4yNzQgNDcuOTQxNFY1MS4wNjQ1QzM0MS4yNzQgNTIuOTI2NCAzNDEuNDM1IDU0LjYxOTEgMzQxLjc1NiA1Ni4xNDI2QzM0Mi4wOTUgNTcuNjQ5MSAzNDIuNjAzIDU4Ljk0NCAzNDMuMjggNjAuMDI3M0MzNDMuOTc0IDYxLjExMDcgMzQ0Ljg1NCA2MS45NDg2IDM0NS45MiA2Mi41NDFDMzQ2Ljk4NyA2My4xMzM1IDM0OC4yNjUgNjMuNDI5NyAzNDkuNzU0IDYzLjQyOTdDMzUxLjU2NiA2My40Mjk3IDM1My4wMyA2My4xNDE5IDM1NC4xNDcgNjIuNTY2NEMzNTUuMjgxIDYxLjk5MDkgMzU2LjEzNiA2MS4xNTMgMzU2LjcxMSA2MC4wNTI3QzM1Ny4zMDQgNTguOTM1NSAzNTcuNjkzIDU3LjU3MjkgMzU3Ljg3OSA1NS45NjQ4WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iMC44NyIvPgo8L2c+CjxkZWZzPgo8ZmlsdGVyIGlkPSJmaWx0ZXIwX2RfMTI0Nl80NDQ0NyIgeD0iMCIgeT0iMCIgd2lkdGg9IjM5OSIgaGVpZ2h0PSIxMDgiIGZpbHRlclVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgY29sb3ItaW50ZXJwb2xhdGlvbi1maWx0ZXJzPSJzUkdCIj4KPGZlRmxvb2QgZmxvb2Qtb3BhY2l0eT0iMCIgcmVzdWx0PSJCYWNrZ3JvdW5kSW1hZ2VGaXgiLz4KPGZlQ29sb3JNYXRyaXggaW49IlNvdXJjZUFscGhhIiB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMTI3IDAiIHJlc3VsdD0iaGFyZEFscGhhIi8+CjxmZU9mZnNldCBkeT0iNCIvPgo8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI0Ii8+CjxmZUNvbXBvc2l0ZSBpbjI9ImhhcmRBbHBoYSIgb3BlcmF0b3I9Im91dCIvPgo8ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMC4wNCAwIi8+CjxmZUJsZW5kIG1vZGU9Im5vcm1hbCIgaW4yPSJCYWNrZ3JvdW5kSW1hZ2VGaXgiIHJlc3VsdD0iZWZmZWN0MV9kcm9wU2hhZG93XzEyNDZfNDQ0NDciLz4KPGZlQmxlbmQgbW9kZT0ibm9ybWFsIiBpbj0iU291cmNlR3JhcGhpYyIgaW4yPSJlZmZlY3QxX2Ryb3BTaGFkb3dfMTI0Nl80NDQ0NyIgcmVzdWx0PSJzaGFwZSIvPgo8L2ZpbHRlcj4KPC9kZWZzPgo8L3N2Zz4K", + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAA6CAYAAAD1AhaMAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAADi3SURBVHgB7X15uCVVde9vV53pDj030PQATTODSLQBEYxC1KCoIF8Cgg9Bo/gE1DgkTvniR+J7CRmMyQMkUQyivkRNvoBG9CUCikYjIMhMMzXNcHu4Pd/xTFX7rbX2WHXqNOSP/Nd1u/rU2bWHtdde015r732A/df+a/+1/9p/7b/2X/uv/dd/x6W1VvbTPcsdPQ9LH7hL7/ZV5z7vUhkPp7tdHvuuUKb0Xl111VVJXP4lwoJyfS59yLOHJYYphsO9i5/LeKron3qx/pXSEH2vghUVuPXv4z5U4acEI/DiYwkMjmeBPlyaHacCLFXtDMEJoutF4S3je0g9poJjz/zUofR5mFJKOwTyc1SpyWzfx1df8veUykx+pXL6yOkz0ej30extVmctfhZ3zL5CT6ejaiSb0ut6/6mexvHoqFGNGpdPqJ0a6nX6TjXqNFF11dDFVmowsFHd9UTe1fz7tAgUv+hnUq7fbqPd3oPe/LR6xcg2ffgxx+DprW2sa+5W3922RHPVvd60es/Fb9LHH3MEDORaUzGqp4YNW2/C/NxuNTnZ0ZseoLzUV9cI4+Nd579LHXLIIZrzZp2O4lYbaVrAUzfL1KOPPam/9Z0H0O7XqL051dm7Ua8/7hB1+RVXIOX8tVoBq7Wod1RcURad0YOmB0WfXEa+0/XTn/5c/cO3b9arX/YmECppCBLdp/7rXlfV+jM4oXO3Xr+6jR8kZ6tdcw1CYVcdPfEdLKjP6sVo4e1ba/jKr/0aNmEcqzf8Eq9fsRa3v+ZczPRaGNVzKh9ZKPDlVHcjaWoGlZ9r9FBvmO91HgWbJ0lS3ZvrqKmpeZ00lDp2+7/qU1//a7i/dgbmfv5ddfzaGTyz8hLt8Oi6nmd9wW2S1rTrPafl9F0+iaa7nb7aNd3W9/7HL7CQ+nf5ZWfr1avHPbb6/T7DVcB/nMbPT72wVf/4tqfw7otPVa1WSwesRzSl1J4l4+MP1I4681NfILL/XWaswDwKeT7AC0CJuxy3KS5Lf8RuyGGlfZbJ8wJkqNH4a5VTYo6kP0XIVJSqTN4sAWFU7izvgZCLRNOz7hOMiQUnkdyUQI+EQy2PlMItJ0yotk9K5IPOOW9KfSAiYdgYs/Q5WicU5Aq17gym0oSQz30mODMG3dRP40vlqBKCp5ftRbc7h16/R4xGSSM5RtOatM29nNuTYa4zT7Bq5jIpw6yalfCUUnpOwoLImcpmLJUYQWiONPD85s0BdotL80/BdkfaElxTP7huTkuUeZNlfTz++KNSst+julOCQHGf+pQ9R70/S4w7S0w4CkVM06W73t6FNYspf17HaK2F3vP0nsZnZr5NRTP09+zA4qmncdIJh2Hp/T/Ez0ffjJ35IsqTgkVmTuORyJjQTTARQ0LX6B31s07ULt2jccqpzlrSIFgygpuRlqCZT2F8ZIHAm/BYMhVYOZykicWFoyOWm4mMDY+7onyKx41oo93uYSG116orgSG3OEzTWplMfRrjkOlr73bGR04M3SjQeaoUdETrO/dO/w2xvP7dClaQyrhB91lOs7l8ujCIgGn4SNnXylEzAyh/uSFaRw6KB5T5NiUkpMIUjjEMwasCA5gkmw5D0MI0UBGcuYGR5FBu65N2tCljuEhHXdDmux2TLDOdmO/uQKfbFyR2e7l0j8abpCYxeJ+UT09j1+7dkaCIsQLfZ487YRYarHqD4E5x11134d5777WZVcQMRTyawc3lrcctY9F2o0PqbnzJIQRn7m0LFhIsGDJizHavS7lH0Cdm7rf7aPXnceCyFFnaRGvxQajtnMbsjh3oJQuQ1JiZu/jVT36A157+fjS33YuRA86kdhZaKAO1xOMjN1hGJBYfyuNE+x5KIRl/VbBNYL8bUasKWHR1BRoMGNCWDoKAecmXjmy5IWUp+XdrZZurUIex0wppPAi+hWjwfYtmNMOASkswjCGECyMdtNArHGHAMp620lmYRFkpY5nBI1EZrSFSRdnvAUK6E3g1Y5mD8wiUVko4vij3l43Inz22ERNPPUWaY5qkaoOkFWminDSbqqM/n4LNL+4eWYy4d3MHG3/+OHLSIBkRliZtI4xOhLKwVcdZJx9DGtQQTb0xirS1VAqPLVqOrNe2wiXqL8ObWLhZm9rbKhaLC8Jm1pM2yfYgSVgn6Vs3fchyknmM5FzGKqfv/dyMSZaTydnntC7JJJa+xFyzHeQjTcxun8TcWJdNTJIQJF1JSqf1Om7oHI0lXUVSv4eREdI44000G00Wt5hta3QyLTgV2Ke3Y3z5MswTE2rWpRa/qiQ6AhPYby5fEgmTEtH6MlbyWjbDf/VyjBx/39dVq0osaoiyxtCV+bSVwip3DGLfa4eM3DKcWArCJO49c4Wov8DTlmBYmveEsZqNmkj2rN9BvUnmAkm/wc6VKN4Sm5hwysz/gizy8tpLeVfFPBHy1oyYYZLMkyzF/HwNjUadYCCVnCS+rFq+EtPpOKZ3zCDrttGfmzW1WQJddeBiySeESp1mG701OgbWlmz+GWHjqEP525mNBm77mVhtyf2wxE4cTATfpbZ6oi2kvtzimbVJbrW6Gw9mqj5pCDbzWsS0pBVnZ6apmiYWkWbLCbc5M2dzBAmZMO1tO7CbzKcTO5tw1Ggdi486FSvWrcLCxYsJHw18/54X8PCze70o3jvXweiuSahFK0hQZFYwWmVtJaWKhskwAqwFoC2jaCtnI7PZjpfWFUOM0vcKgvca3r2r4InYMorrqBlJP4zQKiACClolPOfWUtFB8zhmgdUl2kg30UHWDFLWPFPWdnDaiD/7WQd7djxKdvEeHLx8BAc2G9hIRLvkkCOwfXdCgzSKg1euxNQs2fe5CoabMnMi6afVNkhixR1JETeCUTcPXjiKJ1asMQy6eZNHarJoGfLpPabswmWoHbAaWXvOzA26HSH6ZquBbrsrw3zAogXWPrb4EGJgMWBNyTRAtGAkxaLxOkn1VIRBs1kThmw062iQJOcJMTMYzzF4yNrUxq7dM3jkqS1k6nXo7optGIROZrVTbu15o9W5rE6NJk8bKc2jptHpJVhE7+v1Grp790KPLRStMDk7jT1kQm7uNXHY1B5M7qa+zmYYWUSah0zMxzbtorppvpixba/RIPy8sOVpLF6wCmbKG1MgIsvWwOMsAWc3FgSX8iZGqEJFdpEzQdSLa4F4iuCKlum6rLXcd3X4az42wAFrVi7DJ694C0ZbTez7suZBgb7cl5zlJGokrVIZpAR9sZ8yQ7gksUiH04DXyDxgk8QAlZPkYbuZJ58iJTVN3Hmyp8wkKrXzFDajmNjIiyLqvEcMwgMF7aSy1Va5IRayuFFXfJu3PGnsZoxjrqOO8fEWRlotIkLKyVqEJrx8952JAivgnfbw3c0DUdr+12TymKJF9fIzS/Z5Iuh2J6OJP/NTbGDwPFQRsxNjUJl6PRGTjCf2jJeUn+k2plYiNxfKCci5Tg/TZCLNzXdJC2QyGdZWg7AmUZq9YT3qc48tIhkDnqUkBHODcUE4SdmBQXWR5UUeOiVEx5NlNsGQGhzn1HaPzMtejeihTjiqs4+N+plzjVrqZobKkdt5iJKxkv5RWzz3dn2QVPrMaTKnU7pVOkBVxTmICnqehSYB2usa87KesunXwNhokwRI4ueo5VmDS+NxYO9et2eYt05jzYKHNVin2zWmaaGcKppYjsMuOvfUSuYwBlf8DYEf4rQqrVNRR8GMcIIjUd7OdD0drC2kunlLhE9UFioCH7JU5HdqX+Y/ObztqwZbjzRQ0F5+XuT7FfXDaitdqEthQKIV+ojKq4BHl8LPZZxYbaq8prSWgekeVJjgBEeIb8NodxZSir2CLLT6opiF0RLrSxQNa0FIYOeM0VwhEL1Njz1GQDS/KPVOuzLWYYQhSIiTojRdGNdqTcOmK2vpNjFesawuMkjRQ1WkqTJzFAetWnVVDXmhE24wEuuJYjconLcm9xP9AvI8ICZPxhMTo5L8e+eGhStXRWBV+WxbPMAs1fnOWDJa7RYY11brjGJnJsIg25VNVCALbR0XucwPghcPjoF0qHvYGBRSPP6s7RI9a9cxJ3TkzxCzTKYtgYo2gQAtWVPHZtYBkhi/gbiASeeKe5Vd4ylxSD2XmZSvi1242nJIAhOZUrY/7LZPPJqTqB/FXrkxMQnuS8k8cu+ign4OqQbxFWuUIXImqkrZZrVFL41j2T6LuUwNqUZHkqkSaA95AHxA+vJ/MlFN7HvjeTImQl5gEImvaCN5EivRDE1ltn4tZlbsLXESdYA/XELBxrV9sqKTCZtjNTn73O1EN8sjHah00BqWSQQ2NtfYXBLVnQiBOYJ3ZpjEZPyAmeGUvsJMvs28wQKpw0fAXFIStM6bl4hUD048beIGVqJLUoJItkNwlteciRx0BqzJZPJrG98hnCgzo6GJK303Y+FdFlJhUXS7b27MImMJ5WtAuEcTaj9UQyl83zQbpjlFxhrMx6XzQEVEizXnElVeo+kXAaF0RVojNjtUMQOCsHUSt2/aFUaoGf85JHIqapwDeIh8/xI9YW9XYohIPEPizSEplnAgqQYfWITjA+Wle+I6HisCHQAN75SVmuQEsOZxorQE5oVh3c1MaQlR4isyP0pkossMUremY8HTVzU+XlKWpKIuYdWaGvAMFIg9mEbKOCMyZbUCManmOVsu5iLPJYQpLKkEqe40ndMgJj13Gl6aMGyWWtPRTldERKmQCU6MZzbYx7hLrF7WdlJdRWEeDXGChS4iscpLRRZMzKMeq/516WVh8FUhB1smbfLn17yKhg5ut+Hs4BwOQ02Y4lddGGR5r41EZn89+/DZ1y8el8QMlzAITdJVnnuJE/XfmyrCJDwp5Zh8mgkDJM7u92hzz8a8SBBb+0GSBgidNjDmRc3mSXmKnxim1HmsOfhKrBRPJQhYk4l1GplX2pGwJTaFiC8LbkxEQsq5akWSq9xEsHNDALLqIMt9FFgVzC3qpXLaw9yJTBiYaepE9OQu1wYTavgwm/osfIV5VaLshDz0xxGYf/aGA0tgM44hAOzordScQ78qpPjxKZv/PkdM6IUCjjlCwr6EvPGQWeHO/RMnRyEO4jwAeh/qAoHptPkSq8tC3yIzzKk332X2ZMGYTUzsyjOINt4X0iBK1Hiowwy4M1VcPRb5PInkOENip4c6DJpT6oZBjLlh6CrYwrqym0poipc2yPIThpWXoPCyCue5kow2EJmYzyRRKAfGDPFHE+CkgC3PJOw9S3IHTx5wKbjSxmSTgcyFWfq8hCOPYHFS0Ep3x5jibGDtwbEOJlnrOdqHUA5wRUwWM4t5b9r4+X/8RO5tW7dI+kErVuLEV6zHWW8+W5iEPYi513cKmyc24x+//U/YvGUrZqZnpMzrznwDXvcbb8CKlatCt+11w/XX4L5f3i3PH/zoJ3Do2sMr4eWVCbfddhs2b57A1NSUpB17zLG45NJLsWr1KuwrKO76K0aWNgFWtmrUka/9RKlUjt//wNk4et3B+6iqZA7Q3/RMHVPTNaxaMQdnI/CKK3Yl1nhAYcIiYp7IGinnnU/ExlWO2awJoz3zBa8K36md/LpOiCVtJ8WpGzxvLwYglSUwR+zs0uxSdJyJpcZu3rERjFJEmU0kF6R0jOgkkbbaz0huHSll5eH0BXXQeOyCbZNLlt28/ZKbF7ZPNXLx1lLTN9NHdo0qk2bXqmnL4s6a75HLs0t+Y/7MrclolpjkYqYmJHga5OJtcmCQtQ65VruqISSrrYAr8rKOWTpoEe9pNPMcZfExuW0zPv/n/wsP3n9fXMpfv3X+RfjQhz+CRkI0UDP9+OY3v4kv/NVfGUdCKf/BxBx//tfX4cijj/VA/fVf/Cm++Y2bJG1meoqYawJfuulbWHfYOuPmHW3QuDXwt9d/Eddec81Q4f7BD30IH7zygwU3b41NYYkvWVc8uY6NAM0llsV1pcsOPe0q21+vQU4/+SgcsHQBhl9FKO5+4AB8/8drsGHjEuzYPYIj106JpDPDmcMtAg5jor3Nqj3GY0JLjGROwjoqtxTDm4TaDKCXbExAyhCR9kRktEWuXbvBZpcAl5gjSvzzdSFQowFihhCFlTungLZMrgL8dm2Mi7nInZlJvfmeme+SBmuHG4HgJtgmCGTqyn09xgTNrSnZz5jRNLp9bRmDPqXO3MIUa1arXbWLReWCP83mFTOHNcWKly6ZJKXn4F4yDEhR+c//2edw7z13SepZb34LfpsY4sRXnoTnnttEEfoZPPbowzL269e/UvB6663fx9VXXy0jcPCq1bjsA1fijW9+KxYsWIAnH99ADDCNX/zsp7jo4kslzwxF+T/xkSvxlnPOwxe++GWc/bbzcMs/f4vy7cXprzlDBEmDxu1LX7oeX7z2WoFj4cKFuPCii3AR3atWrcKOHTswPTWNu++6G+PUzgkvf7nEkIT4bVwpsS7nTBufvtJhSVWtOIlUHtGDblw1lFeYQdatmcbC8R7uf2wpMUkLy5fMW2FqCQnKeiLMSlsejjvu/DF+/OM78Cgh8rjjTsD5F1yI444/oaj6I2XAWiDzplVwLnAHM0f+zg53NGOJJZHFU8CXb7wR7/+d93pp7CQyBxlZGou3TGVR42EeZeYfhlYSu+REB1Xhn8NqAPOc2aUmxqZ3XqhY4xhNlFkzWBYTw8w5EtYEypiXhtwRG6sV4xR/li/bE+3mRkUT2fRhoFJzcd+dV45geuj+e/Cf//lTgeSss96ET33ykxL8ZcP49Ne8Dv/zdy4WAv+Pn/4El733vVLF9773PflkQr3+Szfg4NVrRagxA/B163dvxhYyj+795V1Yf9KrfDeOIu3B48rl+BazzL7bsnkzrr/uWsEjM8S/3PIdLFq0UPKfp8/DJZdcikve9S5MTLyA6669Bueccw6avFQJxTiMMW6UFeaB1mtuIG0WR8oITPFiSDfXukOmMbF1TJ473Sg6WpiYWIJTRpKy3fnaM9+ID13xPvzhH/2pdOqfvv0PeHbTRvz2Be/E7Ows7vzRbZibm8VJJ5+KRx95kBjpeKw99FDceeeP5P2rXnUKTjnlFHyfkP/II4+Q9OByc2KPHrr2MBqkGWx6ZiMOP2yt3D+8/Ud42cteTibhHNa/6nQ8+PDDJMEWYueOSezcuR2nnfYaPPjQ/UQAD+CNNPCvfvXpgUGsq9JMxI1p5MwoZ2rq3M16nOYxzGGYJvFOEO8vsd/DF0O0ua2XnXm8bBxiYkUu0nhoCpf2HwHukF1H0i9YejoaZjv2Lo9WfpmOaDn+JM596IH7fZk3/ebribF7ssiRBc+KA5fTPGQFZp6aFiZx1333mZXLr1y/HqsOXulmWXK9lmiBGYQvZhK+eFxeedIp+PLfXotpMq84ne9Lfucybx3+3d990ddxzXXXkQYZj/oBYZpLLr0Ef/onf0J1TOPmW27Bhe+4KCjbCIa5mVlZwaFkZUNDxigxrstMbmVdq7qM7GGXLmY55cTJIeUiief9244VrWeDJMk9d9+FTZuewW9dcDFuuvEGbN+xHWvXHS5MdM89v6COvg93ksaZIcaYnJzEpTT5uvHGv8fDDz8izHHBOy7E33/lBkxun8TY+Bh+4/VvxPj4ApxByP/X7/0rMcYJGB0bx6mvejUepvxz8208++wmyr8dDzz4INaffBp27Z7Cr+77FX77oktw01dvRLuXo0N3u0tmTTc3q2HtxDj3GkpHhOc8UGFNWogxwZuTzgPkTC2/ZswLEqehUDDzYty/yOhYM9E9RrEYhPmRX1CqzJ04uJTTcFFfjP0nz6e++jR8/GO/h9/7+Edx+Lp1Zj8NBRLZ9EKvS3O6MSnL+OeLzafPfvazcl900YWeQKMPfzFjOJnx2c9dTRrkGNxATHLnj27Hhz/+SZx19rm+3H2/vEeemRGOPfZYOHsF0f2GN7xBhCjfqoREZYUO79fptOexe88Mep02er2OjEtN6SKVD53px5qnqIX8xaZW5VWx8KwiE2ZJU/D17LMbxd6cnZ0hgl6AMSLqsdExeh6Fg3WMnkfHx+UdEzinbtq0CW9929ulngMPXAEmsh/fcRvOfss5EfEFQnVzHeeqHaG2tm6dJO0yi6effgoXvPPdJBQTL4llPhVJ5vipQHgFpMHbtc4E9OpdI5pXRZjwcRGrW3ScP8ZYuEJUH0ELIDCsQmBkbZ0gKtIgfrWw7OeAZ4g8Wh3sF3zS82E0ST5i3VpyjGTiIPHtU5nN5M16gCfuVN+RRxwpZdg0eutb32rNTFXQHpz2E7IUTD6jNdyk+GAi/Ou/8nVyAE3JWPPauF6nK00x023eskXAYgYJ8RBdqHvVqpX42te/Jpo8k0l6hgK+pb88r+qjTQJwnOZ8ikMNDW00SFnSDTg+q6ws7Q0Jn3TKidsHC5WjYwNSIwzzyaechjnSDo8+/BC2T27DIBcaycqD+Oyzz+Hzf/EXMmc55ZTTsZ2YhDXJtslJmKCUmVvMzs3hEZrjzBDRc+mDDjwQt93xI/KCHI7/8zd/iUceerDgMDj+xFcKDA9T+jPPPC0MlCi31BwYCGbJZDiYJS5i7IworyOVi2rHVmfsEnYMFHoaz1GCKrBpESC6JBUL7BFpNbEOchuAZdc6P4tLvc9LScG7UnmxZLOVkp3OHh4XBbdWRm7LwAZLc+3NSJOuJcB71VV/KM+sRd596Xtsezpi3AArX7d+51+8eXXh/7hUNIhZ9uFWFhgGQwF3Wrxarg5mAhW/d+3pwhqBiLZ1hK8AWyOBDYRaYXr4aR/WZUR/8spzccwRK309ulR5bP7y8zVfOw7Ll7YlkSfo5/3mM1h10Iy4GcVvIhNMJQEqE8o3EiyzK3bCYDsvFiLJagc3z/3QP/boQ6Ru78AVH/poIDBvuthIr4M95z0PU1gw1kKdbHleCjI3P4/RBYtl/8LI+GJDwqqAflOlMl44g2QDN0eG62niXbIR8iyuItkYCR2e/BscpOjrEM2O21SRp8is2bQub+1iInb3ZWK8Xi5vGDsj6UXqsy2d96yb19jVPBpdbluHOZAzrXi1bb3ZoLtptIiV1N12z9SHSNNxgFfZ5SaiQSBuam7j77/6DZLW35BsV15xJS44/x2yUrnG7nMXp+IVwmmT4jJ10jZbcckF58kcg928N//gjgGx6MQ2awCnQfJ+Dzu2bcFF558jHrLzzjsPV//Z1YEJ/cCEMQqreTPpi6zmJbg5PNAls3By2w7snOli2cIGWoSLFlkoNY/88qUDWwQgHcDhW7tr3IU7drV8WqebYEil8J4eaO8xMME+Q1xamSUSPqCmTcjMLMAzEdnD1h1JA1qXvcYMoQmWxe1Y2W2lz6jYw5mXqvyd37HKzl32UvEg/XMhAtEMygYb/eS5tEhDmzKBziNjS5l4fmJr7um0IGSCCaX9kHr/mXZtcAMunB659wrNReLLSWDlltqQH0xWXgLefFPOvOL95cosUyFBpojBkn6X8nfp2bKyUr5JF0j1DnUC66av/yO+/o3/K3kueeeF+K23nU1euA7ddRPohTMuDX1wQO+Ky97jmeOLZEqF+svdU6XOYvDSbrNVnEUHYWlNx+CACGYnl6sTp480atKvVrOGMdKiEYPEIBUHKFZHYSTNdfO/r0P5uv3nq3HA2U9i0XiG6iuggCVy6tQ/T3yZK1ItBwQ4BpHto5HhME7zjxNefoKR4PLO7c6zXEWSyVNswJ1840MPUufW2ddltUYCs5dE5L9T136PmbI9CbpAufmGil0T5skVy4RRTHy/qJMtvCrg2g2q5FDabiyzLyQxXthpWdVznvLjpXRuV9maeRSsdjYrLBJD5LLMxzIfSWi+U3YzIyyXMQ8m5sSaILHa7p9v/g6++nXDHOzVevfF7zT448M3ZDWvhIrhlo9u2ULM8f7LxE3LJhUzx8E2il6mklhEx8O2YHzcP5vIeXFyUGAWp2ERvheW89CcI+13sKRJHizSpg3SeDxfqQVgtEWvQth0hIghhFLDM1W+8fnFpDlGUL7YzXv/hmV43foXgPJJQTqO1hr7PFVmeYlEqMV8qNkAjtM5xrzyzKy1kBiXYxeoLFXJ+mYIeW+2jbUUm7UxlDwmXqAwEtCBqPzE2hFXESe6aNkV6ooj/ypiVH5krZMMOEJiQRRLOBvkdF+0GQNlTVUXMc/JlJKgiTScBoBir5gNqsrCyqRk1rkoOfc2CyaKRPDtmTwqyqu9ejda5N9++O+47u9ukHevOPFEfJpjIhYeldptz3a8uSy7Wz9w2fuISbYIc1z3la8NMAdQQqsexBRP6HluMkfOnA0bNqBSq1Alm1+YwKc/8xmhgTPOOBPvIG+nsTDsiSrcEMtVmYCkYoKlXd700nOMrbyINWYJb7q3kzF7y3dtdvhpe2/f1cCwiyPqujzwMYdTk7t27iS7b6vZlSbBvMwgFiYKzBJo185J2axjzBzrivbzATeJNOk8N/HMTf2Ym5/D/Pych0Ci0rn53LjxaYp77PDwPfP0kxJvQTThNkzpog+60A9HsLp8A8W5qI6YBSHGpBBralTUa+D00Xwgcsvydlpe9cx7zNvI+LSS7hzd88jJPekm0jLusrU3EcGh2e6vk0BrkDewQWYm3XltVO4sHUFftWiUGzT6DXnup5Repzx0Z41xeZbvNVNO10fxxLMTuPovvyDMcPgRR+GP/vefy/usPm7rbZndg8ruHiGCfP8HLifmMMcdfeT3P+2XllTRd0wv0Yd5R7h4y1veJviZmJjALyj2VXZnc/6777kbd999N4UK7pGovSsbVxpOvjHfp3fvwV6ak9RkWblb3cZozadIms/JIBTMLu2YxDGNxsKxeQy7Fox1bMlI6sKoaTcJb5PfmbfS8r7tvVN7MUESRTWaNHFeQN6nGSxZuhhPPL6BPFXHYsnipXh+4jlKWyYeq9HREVnOwFtwD1pxEJ588klihrYwxMTmjRght/AcebDYn710yRLsopgKB5EOXbOG0voYGRkVb1VzdFaYZWrvXllkx0A+s/FJ2eO9koJde3Zsped5jI8SwXTN+pwDli3HosWLKkbRfHFGq1uTqGKTp1TEraBGiXEkxpLHzOrH0rhc+VMOYeiY01SIKRKZ/Grrrq35oKSyJ6TwQRdJYhcrKrOqOM8j10sEn4r+U/Fn5JbeRsLtYx//mKQdSIG/P/qTz2N04XKzS8d69/KEtby2Kx0S/PEffw5PPvGElPnI738KZ9soekSuBfyUr3I6a4Rvf+sf5fkzn/kD3HTTV7GaXL4uHzPOtdde5/OfdNJJRTMs6g9v5WUcptJPjdlejxjEHrZgVM4UKYkJ+uRjBWMG4cvthcg8qIet3kFMsgZTs62Bjpx4zCSCnexZgwZJyZ5rVru8WEyJaWQ8RfVaHTuJUFs0ieY9wq1WC4uIqA9cvkS8F/Pzs1iil5K9uVc0DAeoHnvsUUy88DzWHrYWTzzxlPSF691JDLFq9WqKpUyTu/YpQVqfD3cDZB9yvV5Hlwhs7949WEGMwW2XR4Lf7SV4jj36CDz/3CbMk4ZZ/8pX4t777pNPILKRnWWmi1hze5ii0Aa8No1MKTMBd+nw2gi5DhXD+P8SPx4Z/B4VN45+z4qOrCt7hBAf+ECahNeeiTNEqtDR4WnB9tSWeEK6QlgknRBzbMEnPnqlCClOXXEQxRpu/EoJh2Yed8brfh2/ceYZ+PINX8H3br1VXo3b9Vef++ynC3h0Lf4hBQiLV5iNxCnr15+EKy6/HNf/7fXCDJde+m5y+58scZGJic24/fbb/creKy6/AitXHixnnBVMRhizc3TBGJy3jvE6snBhyYvFywVkD1UTfrm11wAaKNjhGs1GH29/w0O45bYTPJM0632cvn4CyxfPw/uXI5OYT+YQ91qaitdgYstWtGf2YqTeEJOox2c9UZmRkRFRwyOkKXjB2WLSApy28ZmNxOldkdPPPfeM1LWQkP3UE6RB5trYuWs7fc6R9piWpSC7dkzioAMOQJuIe9myZZ5ZncG3jLTBIw89JMy3+pBDJXUHReIXL1osMHcJnqeefloWxY2MjuKBhx/GsuXLAnFbKV1wo3EgTJu1beJBUnajqZ1cK088wQyIA3l57sw0F+RzQsy0YTYNWrnvIt7RAkpTvTX3LOPmjqTs9MGdzKjysoaKNYnyFKB8eYM7Xtrulrfz9cD998qNoq6T/1evWoEziUHuu/c+n5+DfLd+9xYMuwYZxOu5qHbzwMe38kET1113nTDJzTdPFEryAsbLiYkuvvhisR7Mlo5ivL1L2mO+Q25xcu9mlIeXMcnq8DXr32NHmqRy/qw09KkP/x6OPXJtsLsjexuR7eyDWvSwfbc5TnJ8lCzYuhlQniPU5UQSbezPxPjD5bQPPj2EvCTddpsPXCXe7EmtfcXLslOBwyz3NmYdr4TtmViVaKBnyCw6bO2hpGWaspy837fOOvZgJXLgLxFa389l/PBT/TV30BovrlPWR+NdtsGs5Ana5JbnhckWkyY7hMyzOId51ras05JuQmvnfircTJmMh4428YiejnZAWveum4vnOuAddpUp3CpnZXQJB/n4EDheJuGOWXX9l91/iZZtsrwzMiGXOCFf5iJyagnjmXHKJ7e4nViJWdnsV07HeFHFZ5473vZv37PmuTXBreZSdhKv7Bzx5PWvINNmPb7//R9g69bNti81mZfo0i5Qd73v8g+hzB5sWvKq6C7FQTI+1YSKjrWInlp1EbabySN28y034/ENj0vknbXIMUcfg3PPPRfj5PHicAB7png1tMRB6kZYy6kmvMxk9y5ZCl9TSlb2Ll68EGr1K97tfZcKe+hjG/7gIx/GsUcdYYWWU/sZCrNP5XDmSCKxmt3uW+DjYzioZhlEhpT3bBNA7ELjwBQvDGO7PicG4TOdOIBlDkkwy855s2FiPVgs6DILAu/Yk33f9sTCfm6lrjUlxH0qni22fI1JaJcRyeBz/IRPI1RJUhwWpQqq3i6YJxjbsm9AVah4VyCOgCNiEuNIMJ9mT4eJgfTk/GFnygQTzK/vQoixeAmvrEy22oT7xnOPPh+RZJfYm/Cd2+TERwppCY6yeSWCI0n9iZQSeOubJfNcJpVFmPYMLjnjN4FryWknZ5a4I1/NQXa5zIMYT2yaS4yqZkw5tufNfpDEwyR4oPlQTsysVTQGVhvr4qhYGEzU3gUKmUE4QDlKsQqOWQihO6T7Gqzst+vYTKAwF4GaWBO/Zsvx/JWXrXA92u7l5zZrbgyEgJn7+9ukkyHohMh8iLSHfA0q2COynN+aCLIQTjYx02CiJ/52mWxmJiorbjZrjskRM/yXh4XdCQIlJcrtA7FnRcmxu24ymph9FDzw0BYEbZaSW142sDhPWbwUQcW8AhegM0jLS+wRumjMo6L+sYcF2gChnNRp8WDMrbpdR+DaFcJIItQp5SfZDqWylsjGfWAPkxCWUPZJ9obknonsedFyWmIip7/0vWmhrJbK7EJEIXxijFqDCbwlp7VzYNSFGM12BYstc5qDX4Yvf5nRZtrGTXSiIs4HYkMtIqMBXPp5zsClBgvFHj471oXKXJ2xFLM0EBS0CW2I4CQzP9NuR6bBfGE/SKKfNcuqo4l4ce4R8joGcrJOx9ljRFjCkLix2yudwWsnE1QzDBJQWMagSU0thcteDFEvZqurO1DNSSgGv0f/Jbmyc1xl2uZa3RIJ9GGa1V4TOAMpDlKbY3p0NMWoZBMPputDHhO6HRw59kAZzapsf5zJoixB6UiruD6JkcjMoawpk9nJuW3LxGnMAQlwG6gctOI5V7KlWUV2N1yQzPbJuDkJZyRJ2HnfUHURQGaJDB/6l9glKswcuRy+zQc48DDwQd7mlPy+Wa+VBmtjgNg5ubBSRiEagOGXHsR7PCRmWqE8wbv35Sr9Cuq4WmUouaaU32bgPJA18ZlbtaRxIMHL+31bQGG+ESaUbiLpmvbMoVQJdOXLyskWKvL9Rz1zR0/qSL2GzkcS3bfjMJKbnynQRhuwaafc/ozcbJDKo9r8+U2ITjcpR/vc5E1HMESHNMSLAlXVYGovoEIed5KHVKG8ZC0er6TgZtMKgVGRh5PwZWUt70G3pyfmBQYxcl62Nifaaz5ft8W966+PKkeCNVFGo6V8kmVmNo2ZSLmJXaTuVBLpAwdyjd1vDtY25p4/ZRKuPSfeNRCTpU+LkBXThdoXpyDCW/nB9TeMhXutDRoGGM1ZFZzaF5PcXMYRwicr5rknrAwHkVTgJec9BOaIPFdxg/5JeSnp1JKuUHV+jZIu1qQ94aJAmGV5UVhEIBNSbcw1ZYhOjLLEspGTjrlbaGhqiJdDe2JRQesVxsVKI6fGndep1K2Bq9Q9aASrWizMXAUpFu9eUwhM45PNd7Nt2BzcwHMNMxmO25Jl2dJOrgYx5ySCcmJOFbrpmpdArWjfrpYD4tzuTHPYuNXGvAQobZDm0HLaS40dD8ouw3HWho4Wd8KYYWbHgwowYCgKI/GLIfmKFBKECkpcgZhYfYeVKmc0B1uwBws2LtTv9+VT5iA6D+TOgzi5cw7HHAkUHGEafi9EQcIicKHXVzE8pWddYTrpitu80J67vSp20i/LPUO6wxULHXfEDQzCo6MB0hEcwwRXucP7vNzSN42S51cIzLNLwTYvQDfQUBwXiWMnHmYdMibQ+7DjdYXJEZeHOE60/NCRg8cytysttjpJ2ox/6Khp1tIh92ut/AYsq9n5Fw3kYMYkXtipItxjANgBGFElouNewcNZ4C5bUBe+DA4iv+HJe588WKn8QI9xzTNyatouIHON5LqOr37rZxRH2I2xESOp2AvCBwSk7FlMGuI1Yq+F/BgMjAGT1keJ0ZxxmVjVTbEStHHI6BxGSOJ0+nlsXRn9lIcOtTMzAIWOe01cQIOfb7nLH+nrBDMwoKlVVSLg7VeUYCvk8f+hIAEHBk9HOXSUQ5UqKZOB1lWUYNktrEw2sFUPcmgTwzgEg6SmguRT5nuQMwEgD7o4Qmo4hLfVHnUiFh20Au2dE9j2xAN4aPOseKV4NyevQjhkvC+Olpk9u7HsmBOxu7YKautjFNMaw56xI80hgCr67RMgxHXKnbAalM2gmZl5TL6wGaNEKscdtYLojoK+qTtxRXnBqCOcKmOxiom6c/c0Zmb7OHTNMtm2wPXyPnd2fzOTJO7Qbspb0zZiHjSDwtxsG1/71v8Du301MUwrmSK/fQPNpINmaxF27pwlJpnHeJ0qbrNkJGnSWENA1BEO3zLAjuW78dplW7G0lWLXXF7oc66d/WtU3POzPOlrIE0ipGQmsOMPZM7tMnntGEX7zampmwBbJKeWi5II6QpRRNiIcttUiEFYHKOwMjbSnrElBK2QQ0e0H0xJWZ2MyLSxWiU21bSOKvfEqCPNFsEVXV5PxRIHg89BR5cZNVzmvLFYA0edjgbMaS/+sa3XHrMOBx5xAta8fD26zz+BuU3346cPPIfJ+S4WjY3hzScfjSVreAUE0dOeSQrPpNgwMo7+L36Il52wAg8tP6QglBL/Y0im/SRJBtplN22H4jY7dk3jF7f9EgcSoSxbejqWLkxlZYR4oCKvnBz+Zgnd8LZR449t2IRNz89gwW++zLifYT2qrDH4dxZlT00mpnvNTz6N49cODg8r/6zAUsrYQpf+Go0O3eakvESNU3BGoUVAzfTIJ9TbSSbPTor98M90tYJZhLDWXp4d8ULZIJK55qjcdH0Zus26HMXSs65QtyCRl5vzLx7xDwWmdPfmZsQPbuYamay1dMPqmM0dyixHbnrPRoAG1uNlFxr4oJYc0+x+RSsmWm2Dd7a8cw1CVucrmcBm2pz/5bfXwvUx4rySnVowqjw8CByszdzOrdmKrdjAILqgaarMCH/WQFmFR2k6ZvBQ0JxKhKBleb6zauUCHNjahtrET3h3AloHL8F714wJVDWii0ajBc1HKVE8ZPmi5RidfgzHdXahvXg3pa2GW1TomMKToNXmYR9/EGD+ikwokYF2mzBHwJUdd/6U31NRLuaT+ZNlrJXu20klLpOauJw2489xr76sxfJLyFVAkJRmBzo1oF8gE2uGCmQyiem1tTCPond8+JqqNc0qXI6KZnMygQsBJtsLIWRDYMohxRrP0+lCbNHLKW6RGs2QZX6AEosBE+8g5mmOozaisOiABK3+DHZOPIPOXBfGyDOnkzsGEReq3UYdb3c1EJnvmZXtjrmMggo/eOMQKRP5PFLZtrz7nZLAfpFGsJg0/3JPhF452pHSdr9+4bgZ346vpaAACgwQMZpAPvDjq7FJFzGlUnZ/SVlPFDVkmNuFuvj7nf2TkHXWopY3JKi4Z+tTFBDUWLz6aDJbmvLrVVk7w9iCcayb/DecfMTheLjx6+g9tgsnrup75jBd0BFTRHB6wTCoxXyfOHhIjJElZpcgM4swhq1LDhi0P0XHxCABVXZHay3LiGRdYN0yCv9SMdEf0xDXuXv3nmIcpDB5zThU1KHnlUhbE9TQnPnl1PYclo6nGCF34NzoCA5YuBPbty0xqyGSFGUdru0Qs698ruMWicEjYOsIqWFmBR3MJkcfuQqmB7t0eYVtL+FVwAnGR0ex6viTMDXxNLZPvCB+eLdPwR22rzxClQmMoYJ2VImorabQ0GFa4JjFMYelEjHnEuuKtXabO886jyW0CqaOdlo6Nt+UI9xIyusAotckPiGe45RRXmQIhQK7IlYbygKcaOXdoLFDwMHriokkZk9azj80RZFwPYq6agmR/eqXP8Oo3otj+vNYcvTrKGjPArRLdY+QOc6rKGiekIzxDycgPv/A0YEfJ6UxQEOxY0KpAl4yN98goGqiBTIJInM6L8FJaqn9Nd1Efp0rUYYK5DdBGg2ZSzMDcZk8y7xU6FPA87kXtokGuYbAKi58kaY5emzWV+n5ccz0F6Pf2YMlYz1k5PvqdVrYvWcEIyNk/zWIGzt1lAyGCLNaTi4caZidaw4p7HnvpSMIRnYpHmIp1BFpYr1WzI18rtWT7S7WrDgchy9dihee3IDu3DzcYnN/dM0AYXhZX4RXo0gUKmgQkbYIDOwOg2R1nMgSF0dZMJoYYQl5WM6uUJyI6xK+Axwl+ggwISaUyKQaLIBiRMnNggbz2doLWspUoH0tflGlJUYeh92bH0M2Oy/aI2vPoNXeLaeAzO18Dpv//Us4/vWXUL9b1gxSXsgE7GvEZk7ZlDLmVqxJYPEa9wuiGdhpwDtQeXKdk+Tnn+1ObRCZr74lfP59S8aEzDNg5j2JLIlR4Yzj3DgCeAnKkmULr6lt3/Cdjx98wttvytp6iRnd3FJNJtN3XlLGHqxev0UBpFHkjUnwz7xP9RaSucWMktpR65LVVDdLWGsZu7lMad1RGYmdmUyrTuY6ZyL1fWGQXH6QRangwNe6pzIKG6dk3NPEn1rrs0HJNqF85/ecnxfZPfncpDrp2JW6Nfqc6vHPrpJnnrlf1cyP0fPiDl662HeffctyNWZP/uFKQ/aEFk6klsJv69WlnAyUJ3H22+WqptyvzluBq2pyNojE10i3ZsqcDQ8dLHpTQPGRDbUanyojV03eMFAEL1XLZjT/5H1G+Ti2i77pi8DXd5gzOGSTgKvPXGW2Nr5kGQsTAiE/4WXNfTOamZyVTLBqLTjUOuVfwePVDZTWF1il3r4yoaDU4IUGROepxQNB+MTj96pm8xFpqbNrF1aP1dBpHiArqdPuJGZ3bkM6tpCk8xh5nab01j2zaqY5CUxPYmZ+FFM7dwqcCQ0ySW7FBMl9qjcaNF/OxADm0/kSndJcOeOfeGdhpGfpc3bXLOamtqt2awxTe3eBj+LqdzoYHR3V3a4p22iMasZrt9tVHXp3wJLlukPtNKm9LVu2kYDtql07dzPtyRhzW1xHShiZ5cWf8/Obznnb2zYJGtevX8/iv2Hv5hFHHNGMPltr167lteyt0nPTpbl8pfRC2fjTPg/UXbqbQ54r35VgiNtolr+/FHjjMg4fpXbi703Oy8/u091VsFT0xcNVwodvy6WX66zqSzx+Jfw3q8YgHseq9HJ+12bcx6r+lGGpyNsq96sibWgZDNJjcxieHfxx/tJY+vu4445jPqifccYZEid0DFKPGSUCrhF9NuJKbEWuoUacFuVvRI3GBOrrceUjIAfyVsBTgKNUx7DPYX2K+9uM6nL9aVQMQKEfL+Wu6kOMl330v1HRXgyXhz8ek4goC7iN0qvq9GXifOU8VXjZR71NVNNVo6q/FThpDMHLAG5KcDUwnJYKOIvKCXPQXXMMwrqtZu96+S4XjL+X3vnvjuEcJ6LILI2Sxqqqr17Oz/eQ9gaYu1RHvapt98l1DIOnCvaqvpRgq1cgfFj/66W26uU2h+Gw3AfXrsN9VR/21c9hY1l691LLDx2LCnz7tDg97nfcv3Jdw3Bdaqde0a+B+t1tGYNvsVST888/P7WJwiz8HGWSArYxl15HYCr/rpzu6nBl3PdSXbWqsigybPm53Ha9qk0Hd6mdgTzlfpTrdGkxTspwRwO8r77UKvpd2V6p35XlyvlK+PYwV5SrO3gr+j8Ae1W7cVoZz0xPES5e9H6peWP8l3Ed01TJIqosH9NxGUcMP+CP/w+/A3DVVVeZcIK9uZDNHGuZNEpLK77X9vXp8pbr5e+ltIH6S5+1cj7+HvfBMb0rFwmBSniH9KtWrmcYnEPuSpzF72K4Sm3tE94yrO4uMUo5vdBenF4xjmUhVwVzJQ4i2qnEXfw+Hs+IWCvrrhrDuEwMb4yT8phW4biEB8cP/sE4i01ml5a4AhHhJa7ROI9Lj9J8esX7QhtxuTgtLhfXOeR7GrX3YrfPF8NbqrcMh9wl+Crrjt6lFfCW+1/uZ9xOGc60ArZKXMfl3F0uVx7juCx77kpjWdlO1RjGfS/DXh7nuL6ImAfqqKq/jNcSMyRlPMS4jctWwOT4wXu/lXVlqvL3EvPEBeM7HoSB9NJzDEihnRiGqrqi9wNwuPJxnnKfYnhKRKNi2GJExXlKMCdVbcRwlOCpKjNQdwVRxrhJynU5GOM6Y5yX0933Un1VjFB4H/UlGVKu8nsZnyUcJOU2KvA+0OfSWCelPlfSAirodkh/iu+djz96gVLlQAUxRg3APgNDmC2uO85TGqyh5eKBLTOSa9vWB1QzO/YB0zDEqQpYh+KiquywMvtoDzEuhuAFFXVX9c/jZB/9RwV8qOjDi41nZZlhbZbophLXpTrwEvFXBdtAeacdh9Ff9In4KhMUUBwQxLftKModi5CAUiOqXAbVgxLXX2ZU4EWIoNSpgU5W1BfDWh6guI4XHYR9EBaGDDRK71BR77D2BsaqNLADgqNURkW4q8JJVX3D+lA5JijhXw8KsMp3ZSYp1VvGMTBIH+X6YnyglLc8Pvuv/df+a/+1/9p/7b/2X/uv/97r/wM7LHoKyFPc/QAAAABJRU5ErkJggg==", "description": "Designed to display single value of the selected attribute or timeseries data. Widget styles are customizable.", "descriptor": { "type": "latest", "sizeX": 5, "sizeY": 1.5, "resources": [], - "templateHtml": "\n", + "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n absoluteHeader: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-value-card-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\"}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" } } ] diff --git a/ui-ngx/src/app/core/services/dialog.service.ts b/ui-ngx/src/app/core/services/dialog.service.ts index 6ba2687278..c5f54f9cf0 100644 --- a/ui-ngx/src/app/core/services/dialog.service.ts +++ b/ui-ngx/src/app/core/services/dialog.service.ts @@ -21,11 +21,11 @@ import { TranslateService } from '@ngx-translate/core'; import { AuthService } from '@core/auth/auth.service'; import { ColorPickerDialogComponent, - ColorPickerDialogData + ColorPickerDialogData, ColorPickerDialogResult } from '@shared/components/dialog/color-picker-dialog.component'; import { MaterialIconsDialogComponent, - MaterialIconsDialogData + MaterialIconsDialogData, MaterialIconsDialogResult } from '@shared/components/dialog/material-icons-dialog.component'; import { ConfirmDialogComponent } from '@shared/components/dialog/confirm-dialog.component'; import { AlertDialogComponent } from '@shared/components/dialog/alert-dialog.component'; @@ -96,8 +96,8 @@ export class DialogService { return dialogRef.afterClosed(); } - colorPicker(color: string, colorClearButton = false): Observable { - return this.dialog.open(ColorPickerDialogComponent, + colorPicker(color: string, colorClearButton = false): Observable { + return this.dialog.open(ColorPickerDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], @@ -109,13 +109,14 @@ export class DialogService { }).afterClosed(); } - materialIconPicker(icon: string): Observable { - return this.dialog.open(MaterialIconsDialogComponent, + materialIconPicker(icon: string, iconClearButton = false): Observable { + return this.dialog.open(MaterialIconsDialogComponent, { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { - icon + icon, + iconClearButton }, autoFocus: false }).afterClosed(); diff --git a/ui-ngx/src/app/core/services/dynamic-component-factory.service.ts b/ui-ngx/src/app/core/services/dynamic-component-factory.service.ts index 84134f04a9..b7e21f7b22 100644 --- a/ui-ngx/src/app/core/services/dynamic-component-factory.service.ts +++ b/ui-ngx/src/app/core/services/dynamic-component-factory.service.ts @@ -33,11 +33,17 @@ import { catchError, map, mergeMap } from 'rxjs/operators'; @NgModule() export abstract class DynamicComponentModule implements OnDestroy { + // eslint-disable-next-line @angular-eslint/contextual-lifecycle ngOnDestroy(): void { } } +interface DynamicComponentData { + componentType: Type; + componentModuleRef: NgModuleRef; +} + interface DynamicComponentModuleData { moduleRef: NgModuleRef; moduleType: Type; @@ -48,22 +54,22 @@ interface DynamicComponentModuleData { }) export class DynamicComponentFactoryService { - private dynamicComponentModulesMap = new Map, DynamicComponentModuleData>(); + private dynamicComponentModulesMap = new Map, DynamicComponentModuleData>(); constructor(private compiler: Compiler, private injector: Injector) { } - public createDynamicComponentFactory( + public createDynamicComponent( componentType: Type, template: string, modules?: Type[], preserveWhitespaces?: boolean, compileAttempt = 1, - styles?: string[]): Observable> { + styles?: string[]): Observable> { return from(import('@angular/compiler')).pipe( mergeMap(() => { - const comp = this.createDynamicComponent(componentType, template, preserveWhitespaces, styles); + const comp = this._createDynamicComponent(componentType, template, preserveWhitespaces, styles); let moduleImports: Type[] = [CommonModule]; if (modules) { moduleImports = [...moduleImports, ...modules]; @@ -82,17 +88,19 @@ export class DynamicComponentFactoryService { this.compiler.clearCacheFor(module.moduleType); throw e; } - const factory = moduleRef.componentFactoryResolver.resolveComponentFactory(comp); - this.dynamicComponentModulesMap.set(factory, { + this.dynamicComponentModulesMap.set(comp, { moduleRef, moduleType: module.moduleType }); - return factory; + return { + componentType: comp, + componentModuleRef: moduleRef + }; }), catchError((error) => { if (compileAttempt === 1) { ɵresetCompiledComponents(); - return this.createDynamicComponentFactory(componentType, template, modules, preserveWhitespaces, ++compileAttempt, styles); + return this.createDynamicComponent(componentType, template, modules, preserveWhitespaces, ++compileAttempt, styles); } else { throw error; } @@ -102,16 +110,16 @@ export class DynamicComponentFactoryService { ); } - public destroyDynamicComponentFactory(factory: ComponentFactory) { - const moduleData = this.dynamicComponentModulesMap.get(factory); + public destroyDynamicComponent(componentType: Type) { + const moduleData = this.dynamicComponentModulesMap.get(componentType); if (moduleData) { moduleData.moduleRef.destroy(); this.compiler.clearCacheFor(moduleData.moduleType); - this.dynamicComponentModulesMap.delete(factory); + this.dynamicComponentModulesMap.delete(componentType); } } - private createDynamicComponent(componentType: Type, template: string, preserveWhitespaces?: boolean, styles?: string[]): Type { + private _createDynamicComponent(componentType: Type, template: string, preserveWhitespaces?: boolean, styles?: string[]): Type { // noinspection AngularMissingOrInvalidDeclarationInModule return Component({ template, diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 9a369cb5aa..2a2f664c3a 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -180,9 +180,7 @@ export function objToBase64(obj: any): string { } export function base64toString(b64Encoded: string): string { - return decodeURIComponent(atob(b64Encoded).split('').map((c) => { - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); - }).join('')); + return decodeURIComponent(atob(b64Encoded).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')); } export function objToBase64URI(obj: any): string { @@ -190,9 +188,7 @@ export function objToBase64URI(obj: any): string { } export function base64toObj(b64Encoded: string): any { - const json = decodeURIComponent(atob(b64Encoded).split('').map((c) => { - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); - }).join('')); + const json = decodeURIComponent(atob(b64Encoded).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join('')); return JSON.parse(json); } @@ -355,9 +351,7 @@ const SNAKE_CASE_REGEXP = /[A-Z]/g; export function snakeCase(name: string, separator: string): string { separator = separator || '_'; - return name.replace(SNAKE_CASE_REGEXP, (letter, pos) => { - return (pos ? separator : '') + letter.toLowerCase(); - }); + return name.replace(SNAKE_CASE_REGEXP, (letter, pos) => (pos ? separator : '') + letter.toLowerCase()); } export function getDescendantProp(obj: any, path: string): any { @@ -381,7 +375,7 @@ export function insertVariable(pattern: string, name: string, value: any): strin return result; } -export function createLabelFromDatasource(datasource: Datasource, pattern: string): string { +export const createLabelFromDatasource = (datasource: Datasource, pattern: string): string => { let label = pattern; if (!datasource) { return label; @@ -406,7 +400,9 @@ export function createLabelFromDatasource(datasource: Datasource, pattern: strin match = varsRegex.exec(pattern); } return label; -} +}; + +export const hasDatasourceLabelsVariables = (pattern: string): boolean => varsRegex.test(pattern) !== null; export function formattedDataFormDatasourceData(input: DatasourceData[], dataIndex?: number): FormattedData[] { return _(input).groupBy(el => el.datasource.entityName + el.datasource.entityType) @@ -694,7 +690,7 @@ export function getEntityDetailsPageURL(id: string, entityType: EntityType): str } export function parseHttpErrorMessage(errorResponse: HttpErrorResponse, - translate: TranslateService, responseType?: string): {message: string, timeout: number} { + translate: TranslateService, responseType?: string): {message: string; timeout: number} { let error = null; let errorMessage: string; let timeout = 0; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index d58c057b68..b9a1a71c03 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -196,7 +196,6 @@ flatButton [displayTimewindowValue]="false" [isEdit]="true" - direction="left" tooltipPosition="below" aggregation="true" timezone="true" @@ -205,7 +204,6 @@

diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts index c67a59ac20..6c25585f76 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts @@ -23,7 +23,10 @@ import { WidgetConfigComponentData } from '@home/models/widget-component.models' import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { isUndefined } from '@core/utils'; -import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; @Component({ selector: 'tb-alarms-table-basic-config', @@ -74,9 +77,7 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent } protected prepareOutputConfig(config: any): WidgetConfigComponentData { - this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; - this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; - this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); this.widgetConfig.config.alarmFilterConfig = config.alarmFilterConfig; this.widgetConfig.config.alarmSource = config.datasources[0]; this.setColumns(config.columns, this.widgetConfig.config.alarmSource); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html index b4c2dbd616..ae0ca13dbe 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.html @@ -64,6 +64,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts index f407293064..228879e2ef 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/entities-table-basic-config.component.ts @@ -29,7 +29,10 @@ import { import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { isUndefined } from '@core/utils'; -import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; @Component({ selector: 'tb-entities-table-basic-config', @@ -93,9 +96,7 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen } protected prepareOutputConfig(config: any): WidgetConfigComponentData { - this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; - this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; - this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); this.widgetConfig.config.datasources = config.datasources; this.setColumns(config.columns, this.widgetConfig.config.datasources); this.widgetConfig.config.actions = config.actions; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts index 283e39362a..9b2a6a764b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts @@ -27,7 +27,10 @@ import { } from '@shared/models/widget.models'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; -import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; import { isUndefined } from '@core/utils'; import { getLabel, setLabel } from '@shared/models/widget-settings.models'; @@ -80,9 +83,7 @@ export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent { } protected prepareOutputConfig(config: any): WidgetConfigComponentData { - this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; - this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; - this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); this.widgetConfig.config.datasources = config.datasources; setLabel(config.label, this.widgetConfig.config.datasources); this.widgetConfig.config.actions = config.actions; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html index 5952c206b6..15c903736a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.html @@ -64,6 +64,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts index a8c4206fa7..dc2a41b816 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts @@ -24,7 +24,10 @@ import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models' import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { deepClone, isUndefined } from '@core/utils'; -import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; @Component({ selector: 'tb-timeseries-table-basic-config', @@ -79,9 +82,7 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon } protected prepareOutputConfig(config: any): WidgetConfigComponentData { - this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; - this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; - this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); this.widgetConfig.config.datasources = config.datasources; this.setColumns(config.columns, this.widgetConfig.config.datasources); this.widgetConfig.config.actions = config.actions; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html index 356612564f..a036ab2b1c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.html @@ -65,6 +65,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts index b535aaa7f8..dacb2dfa11 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts @@ -27,7 +27,10 @@ import { } from '@shared/models/widget.models'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; -import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; import { formatValue, isDefinedAndNotNull, isUndefined } from '@core/utils'; import { DateFormatProcessor, @@ -145,9 +148,7 @@ export class ValueCardBasicConfigComponent extends BasicWidgetConfigComponent { } protected prepareOutputConfig(config: any): WidgetConfigComponentData { - this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; - this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; - this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); this.widgetConfig.config.datasources = config.datasources; this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html index 0d607c230d..6bd31f41eb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.html @@ -64,6 +64,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts index c77d0ecb76..050d362868 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts @@ -24,7 +24,10 @@ import { DataKey, Datasource, WidgetConfig } from '@shared/models/widget.models' import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { isUndefined } from '@core/utils'; -import { getTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; @Component({ selector: 'tb-flot-basic-config', @@ -83,9 +86,7 @@ export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { } protected prepareOutputConfig(config: any): WidgetConfigComponentData { - this.widgetConfig.config.useDashboardTimewindow = config.timewindowConfig.useDashboardTimewindow; - this.widgetConfig.config.displayTimewindow = config.timewindowConfig.displayTimewindow; - this.widgetConfig.config.timewindow = config.timewindowConfig.timewindow; + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); this.widgetConfig.config.datasources = config.datasources; this.setSeries(config.series, this.widgetConfig.config.datasources); this.widgetConfig.config.actions = config.actions; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.html index 045d41ee03..d144cb3db6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.html @@ -27,14 +27,19 @@ {{ 'widget-config.display-timewindow' | translate }} - +
+ + + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts index 410896dd74..93fc304b7a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts @@ -22,11 +22,13 @@ import { Timewindow } from '@shared/models/time/time.models'; import { TranslateService } from '@ngx-translate/core'; import { coerceBoolean } from '@shared/decorators/coercion'; import { isDefined } from '@core/utils'; +import { TimewindowStyle } from '@shared/models/widget-settings.models'; export interface TimewindowConfigData { useDashboardTimewindow: boolean; displayTimewindow: boolean; timewindow: Timewindow; + timewindowStyle: TimewindowStyle; } export const getTimewindowConfig = (config: WidgetConfig): TimewindowConfigData => ({ @@ -34,9 +36,17 @@ export const getTimewindowConfig = (config: WidgetConfig): TimewindowConfigData config.useDashboardTimewindow : true, displayTimewindow: isDefined(config.displayTimewindow) ? config.displayTimewindow : true, - timewindow: config.timewindow + timewindow: config.timewindow, + timewindowStyle: config.timewindowStyle }); +export const setTimewindowConfig = (config: WidgetConfig, data: TimewindowConfigData): void => { + config.useDashboardTimewindow = data.useDashboardTimewindow; + config.displayTimewindow = data.displayTimewindow; + config.timewindow = data.timewindow; + config.timewindowStyle = data.timewindowStyle; +}; + @Component({ selector: 'tb-timewindow-config-panel', templateUrl: './timewindow-config-panel.component.html', @@ -78,7 +88,8 @@ export class TimewindowConfigPanelComponent implements ControlValueAccessor, OnI this.timewindowConfig = this.fb.group({ useDashboardTimewindow: [null, []], displayTimewindow: [null, []], - timewindow: [null, []] + timewindow: [null, []], + timewindowStyle: [null, []] }); this.timewindowConfig.valueChanges.subscribe( (val) => this.propagateChange(val) @@ -86,6 +97,9 @@ export class TimewindowConfigPanelComponent implements ControlValueAccessor, OnI this.timewindowConfig.get('useDashboardTimewindow').valueChanges.subscribe(() => { this.updateTimewindowConfigEnabledState(); }); + this.timewindowConfig.get('displayTimewindow').valueChanges.subscribe(() => { + this.updateTimewindowConfigEnabledState(); + }); } writeValue(data?: TimewindowConfigData): void { @@ -112,12 +126,19 @@ export class TimewindowConfigPanelComponent implements ControlValueAccessor, OnI private updateTimewindowConfigEnabledState() { const useDashboardTimewindow: boolean = this.timewindowConfig.get('useDashboardTimewindow').value; + const displayTimewindow: boolean = this.timewindowConfig.get('displayTimewindow').value; if (useDashboardTimewindow) { this.timewindowConfig.get('displayTimewindow').disable({emitEvent: false}); this.timewindowConfig.get('timewindow').disable({emitEvent: false}); + this.timewindowConfig.get('timewindowStyle').disable({emitEvent: false}); } else { this.timewindowConfig.get('displayTimewindow').enable({emitEvent: false}); this.timewindowConfig.get('timewindow').enable({emitEvent: false}); + if (displayTimewindow) { + this.timewindowConfig.get('timewindowStyle').enable({emitEvent: false}); + } else { + this.timewindowConfig.get('timewindowStyle').disable({emitEvent: false}); + } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.html new file mode 100644 index 0000000000..5ba8df3012 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.html @@ -0,0 +1,97 @@ + +
+
timewindow.style
+
+ + {{ 'timewindow.icon' | translate }} + +
+ + + + + +
+
+
+
timewindow.icon-position
+ + + + {{ 'timewindow.icon-position-left' | translate }} + + + {{ 'timewindow.icon-position-right' | translate }} + + + +
+
+
timewindow.font
+ + +
+
+
timewindow.color
+ + +
+ +
+
timewindow.preview
+ + +
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.scss new file mode 100644 index 0000000000..d3c2dfb4fb --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.scss @@ -0,0 +1,54 @@ +/** + * Copyright © 2016-2023 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-timewindow-style-panel { + width: 100%; + display: flex; + flex-direction: column; + gap: 16px; + @media #{$mat-gt-xs} { + min-width: 320px; + } + .tb-timewindow-style-title { + font-size: 16px; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.25px; + color: rgba(0, 0, 0, 0.87); + } + .tb-form-row { + .fixed-title-width { + min-width: 120px; + } + &.timewindow-preview { + align-items: flex-start; + tb-timewindow { + font-size: 14px; + opacity: .85; + } + } + } + .tb-timewindow-style-panel-buttons { + height: 60px; + display: flex; + flex-direction: row; + gap: 16px; + justify-content: flex-end; + align-items: flex-end; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts new file mode 100644 index 0000000000..e0e4ee5615 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts @@ -0,0 +1,108 @@ +/// +/// Copyright © 2016-2023 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, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; +import { PageComponent } from '@shared/components/page.component'; +import { defaultTimewindowStyle, TimewindowStyle } from '@shared/models/widget-settings.models'; +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 { Timewindow } from '@shared/models/time/time.models'; +import { deepClone } from '@core/utils'; + +@Component({ + selector: 'tb-timewindow-style-panel', + templateUrl: './timewindow-style-panel.component.html', + providers: [], + styleUrls: ['./timewindow-style-panel.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class TimewindowStylePanelComponent extends PageComponent implements OnInit { + + @Input() + timewindowStyle: TimewindowStyle; + + @Input() + previewValue: Timewindow; + + @Input() + popover: TbPopoverComponent; + + @Output() + timewindowStyleApplied = new EventEmitter(); + + timewindowStyleFormGroup: UntypedFormGroup; + + previewTimewindowStyle: TimewindowStyle; + + constructor(private fb: UntypedFormBuilder, + protected store: Store) { + super(store); + } + + ngOnInit(): void { + const computedTimewindowStyle = {...defaultTimewindowStyle, ...(this.timewindowStyle || {})}; + this.timewindowStyleFormGroup = this.fb.group( + { + showIcon: [computedTimewindowStyle.showIcon, []], + iconSize: [computedTimewindowStyle.iconSize, []], + icon: [computedTimewindowStyle.icon, []], + iconPosition: [computedTimewindowStyle.iconPosition, []], + font: [computedTimewindowStyle.font, []], + color: [computedTimewindowStyle.color, []] + } + ); + this.updatePreviewStyle(this.timewindowStyle); + this.updateTimewindowStyleEnabledState(); + this.timewindowStyleFormGroup.valueChanges.subscribe((timewindowStyle: TimewindowStyle) => { + if (this.timewindowStyleFormGroup.valid) { + this.updatePreviewStyle(timewindowStyle); + setTimeout(() => {this.popover?.updatePosition();}, 0); + } + }); + this.timewindowStyleFormGroup.get('showIcon').valueChanges.subscribe(() => { + this.updateTimewindowStyleEnabledState(); + }); + } + + cancel() { + this.popover?.hide(); + } + + applyTimewindowStyle() { + const timewindowStyle = this.timewindowStyleFormGroup.getRawValue(); + this.timewindowStyleApplied.emit(timewindowStyle); + } + + private updateTimewindowStyleEnabledState() { + const showIcon: boolean = this.timewindowStyleFormGroup.get('showIcon').value; + if (showIcon) { + this.timewindowStyleFormGroup.get('iconSize').enable({emitEvent: false}); + this.timewindowStyleFormGroup.get('icon').enable({emitEvent: false}); + this.timewindowStyleFormGroup.get('iconPosition').enable({emitEvent: false}); + } else { + this.timewindowStyleFormGroup.get('iconSize').disable({emitEvent: false}); + this.timewindowStyleFormGroup.get('icon').disable({emitEvent: false}); + this.timewindowStyleFormGroup.get('iconPosition').disable({emitEvent: false}); + } + } + + private updatePreviewStyle(timewindowStyle: TimewindowStyle) { + this.previewTimewindowStyle = deepClone(timewindowStyle); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.html b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.html new file mode 100644 index 0000000000..2bd981fffc --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.html @@ -0,0 +1,25 @@ + + diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.ts new file mode 100644 index 0000000000..ad6d3e1b85 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style.component.ts @@ -0,0 +1,97 @@ +/// +/// Copyright © 2016-2023 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, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { TimewindowStyle } from '@shared/models/widget-settings.models'; +import { MatButton } from '@angular/material/button'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { Timewindow } from '@shared/models/time/time.models'; +import { TimewindowStylePanelComponent } from '@home/components/widget/config/timewindow-style-panel.component'; + +@Component({ + selector: 'tb-timewindow-style', + templateUrl: './timewindow-style.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TimewindowStyleComponent), + multi: true + } + ] +}) +export class TimewindowStyleComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + @Input() + previewValue: Timewindow; + + private modelValue: TimewindowStyle; + + private propagateChange = null; + + constructor(private popoverService: TbPopoverService, + private renderer: Renderer2, + private viewContainerRef: ViewContainerRef) {} + + ngOnInit(): void { + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + writeValue(value: TimewindowStyle): void { + this.modelValue = value; + } + + openTimewindowStylePopup($event: Event, matButton: MatButton) { + if ($event) { + $event.stopPropagation(); + } + const trigger = matButton._elementRef.nativeElement; + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const ctx: any = { + timewindowStyle: this.modelValue, + previewValue: this.previewValue + }; + const timewindowStylePanelPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, TimewindowStylePanelComponent, 'left', true, null, + ctx, + {}, + {}, {}, true); + timewindowStylePanelPopover.tbComponentRef.instance.popover = timewindowStylePanelPopover; + timewindowStylePanelPopover.tbComponentRef.instance.timewindowStyleApplied.subscribe((timewindowStyle) => { + timewindowStylePanelPopover.hide(); + this.modelValue = timewindowStyle; + this.propagateChange(this.modelValue); + }); + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-config-components.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-config-components.module.ts index 392a829955..ea0d27dcf6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-config-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-config-components.module.ts @@ -30,6 +30,8 @@ import { WidgetSettingsModule } from '@home/components/widget/lib/settings/widge import { WidgetSettingsComponent } from '@home/components/widget/config/widget-settings.component'; import { TimewindowConfigPanelComponent } from '@home/components/widget/config/timewindow-config-panel.component'; import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings/common/widget-settings-common.module'; +import { TimewindowStyleComponent } from '@home/components/widget/config/timewindow-style.component'; +import { TimewindowStylePanelComponent } from '@home/components/widget/config/timewindow-style-panel.component'; @NgModule({ declarations: @@ -43,6 +45,8 @@ import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings DatasourcesComponent, EntityAliasSelectComponent, FilterSelectComponent, + TimewindowStyleComponent, + TimewindowStylePanelComponent, TimewindowConfigPanelComponent, WidgetSettingsComponent ], @@ -62,6 +66,8 @@ import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings DatasourcesComponent, EntityAliasSelectComponent, FilterSelectComponent, + TimewindowStyleComponent, + TimewindowStylePanelComponent, TimewindowConfigPanelComponent, WidgetSettingsComponent, WidgetSettingsCommonModule diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts index dc3e9c7ac2..3c20317b13 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/custom-dialog-container.component.ts @@ -20,8 +20,8 @@ import { ComponentFactory, ComponentRef, HostBinding, Inject, - Injector, - OnDestroy, + Injector, NgModuleRef, + OnDestroy, Type, ViewContainerRef } from '@angular/core'; import { DialogComponent } from '@shared/components/dialog.component'; @@ -35,11 +35,13 @@ import { } from '@home/components/widget/dialog/custom-dialog.component'; import { DialogService } from '@core/services/dialog.service'; import { TranslateService } from '@ngx-translate/core'; +import { DynamicComponentModule } from '@core/services/dynamic-component-factory.service'; export interface CustomDialogContainerData { controller: (instance: CustomDialogComponent) => void; data?: any; - customComponentFactory: ComponentFactory; + customComponentType: Type; + customComponentModuleRef: NgModuleRef; } @Component({ @@ -77,7 +79,8 @@ export class CustomDialogContainerComponent extends DialogComponent> + private customModules: Array>; constructor( private translate: TranslateService, @@ -56,12 +56,13 @@ export class CustomDialogService { if (Array.isArray(this.customModules)) { modules.push(...this.customModules); } - return this.dynamicComponentFactoryService.createDynamicComponentFactory( + return this.dynamicComponentFactoryService.createDynamicComponent( class CustomDialogComponentInstance extends CustomDialogComponent {}, template, modules).pipe( - mergeMap((factory) => { + mergeMap((componentData) => { const dialogData: CustomDialogContainerData = { controller, - customComponentFactory: factory, + customComponentType: componentData.componentType, + customComponentModuleRef: componentData.componentModuleRef, data }; let dialogConfig: MatDialogConfig = { @@ -76,7 +77,7 @@ export class CustomDialogService { CustomDialogContainerComponent, dialogConfig).afterClosed().pipe( tap(() => { - this.dynamicComponentFactoryService.destroyDynamicComponentFactory(factory); + this.dynamicComponentFactoryService.destroyDynamicComponent(componentData.componentType); }) ); } diff --git a/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts index 22fac750b5..feeb1fe802 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts @@ -15,7 +15,7 @@ /// import { PageComponent } from '@shared/components/page.component'; -import { Directive, Injector, OnDestroy, OnInit } from '@angular/core'; +import { Directive, Injector, OnDestroy, OnInit, TemplateRef } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { IDynamicWidgetComponent, WidgetContext } from '@home/models/widget-component.models'; @@ -67,7 +67,8 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid @TbInject(UntypedFormBuilder) public fb: UntypedFormBuilder, @TbInject(Injector) public readonly $injector: Injector, @TbInject('widgetContext') public readonly ctx: WidgetContext, - @TbInject('errorMessages') public readonly errorMessages: string[]) { + @TbInject('errorMessages') public readonly errorMessages: string[], + @TbInject('widgetTitlePanel') public readonly widgetTitlePanel: TemplateRef) { super(store); this.ctx.$injector = $injector; this.ctx.deviceService = $injector.get(DeviceService); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts index f799ed43ff..234443855f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts @@ -37,16 +37,7 @@ import { DataKey, WidgetActionDescriptor, WidgetConfig } from '@shared/models/wi import { IWidgetSubscription } from '@core/api/widget-api.models'; import { UtilsService } from '@core/services/utils.service'; import { TranslateService } from '@ngx-translate/core'; -import { - createLabelFromDatasource, - deepClone, - hashCode, - isDefined, - isDefinedAndNotNull, - isNumber, - isObject, - isUndefined -} from '@core/utils'; +import { deepClone, hashCode, isDefined, isDefinedAndNotNull, isNumber, isObject, isUndefined } from '@core/utils'; import cssjs from '@core/css/css'; import { sortItems } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; @@ -194,8 +185,6 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, private subscription: IWidgetSubscription; private widgetResize$: ResizeObserver; - private alarmsTitlePattern: string; - private displayActivity = false; private displayDetails = true; public allowAcknowledgment = true; @@ -322,7 +311,6 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, } public onDataUpdated() { - this.updateTitle(true); this.alarmsDatasource.updateAlarms(); this.clearCache(); this.ctx.detectChanges(); @@ -342,13 +330,11 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, this.allowAssign = isDefined(this.settings.allowAssign) ? this.settings.allowAssign : true; if (this.settings.alarmsTitle && this.settings.alarmsTitle.length) { - this.alarmsTitlePattern = this.utils.customTranslation(this.settings.alarmsTitle, this.settings.alarmsTitle); + this.ctx.widgetTitle = this.settings.alarmsTitle; } else { - this.alarmsTitlePattern = this.translate.instant('alarm.alarms'); + this.ctx.widgetTitle = this.translate.instant('alarm.alarms'); } - this.updateTitle(false); - this.enableSelection = isDefined(this.settings.enableSelection) ? this.settings.enableSelection : true; if (!this.allowAcknowledgment && !this.allowClear) { this.enableSelection = false; @@ -394,16 +380,6 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, $(this.elementRef.nativeElement).addClass(namespace); } - private updateTitle(updateWidgetParams = false) { - const newTitle = createLabelFromDatasource(this.subscription.alarmSource, this.alarmsTitlePattern); - if (this.ctx.widgetTitle !== newTitle) { - this.ctx.widgetTitle = newTitle; - if (updateWidgetParams) { - this.ctx.updateWidgetParams(); - } - } - } - private updateAlarmSource() { if (this.enableSelection) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html index 8c79c0e1e7..fee7dc5259 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html @@ -17,6 +17,9 @@ -->
+
+ +
@@ -60,7 +63,7 @@ {{ icon }} -
{{ label }}
+
{{ label$ | async }}
{{ dateFormat.formatted }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.scss index d0cf0ea0b7..05bbbb0bf0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.scss @@ -44,6 +44,13 @@ bottom: 12px; right: 12px; } + > div.tb-value-card-title-panel { + position: absolute; + top: 12px; + left: 12px; + right: 12px; + z-index: 2; + } .tb-value-card-icon-row { display: flex; flex-direction: row; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts index ac2cb62fee..5505a1e8dd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectorRef, Component, Input, OnInit, TemplateRef } from '@angular/core'; import { WidgetContext } from '@home/models/widget-component.models'; import { formatValue, isDefinedAndNotNull } from '@core/utils'; import { DatePipe } from '@angular/common'; @@ -31,6 +31,7 @@ import { } from '@shared/models/widget-settings.models'; import { valueCardDefaultSettings, ValueCardLayout, ValueCardWidgetSettings } from './value-card-widget.models'; import { WidgetComponent } from '@home/components/widget/widget.component'; +import { Observable } from 'rxjs'; @Component({ selector: 'tb-value-card-widget', @@ -46,6 +47,9 @@ export class ValueCardWidgetComponent implements OnInit { @Input() ctx: WidgetContext; + @Input() + widgetTitlePanel: TemplateRef; + layout: ValueCardLayout; showIcon = true; icon = ''; @@ -53,7 +57,7 @@ export class ValueCardWidgetComponent implements OnInit { iconColor: ColorProcessor; showLabel = true; - label = ''; + label$: Observable; labelStyle: ComponentStyle = {}; labelColor: ColorProcessor; @@ -102,15 +106,16 @@ export class ValueCardWidgetComponent implements OnInit { this.iconColor = ColorProcessor.fromSettings(this.settings.iconColor); this.showLabel = this.settings.showLabel; - this.label = getLabel(this.ctx.datasources); - this.labelStyle = textStyle(this.settings.labelFont, '1.5', '0.25px'); + const label = getLabel(this.ctx.datasources); + this.label$ = this.ctx.registerLabelPattern('valueCardLabel', label); + this.labelStyle = textStyle(this.settings.labelFont, '0.25px'); this.labelColor = ColorProcessor.fromSettings(this.settings.labelColor); - this.valueStyle = textStyle(this.settings.valueFont, '100%', '0.13px'); + this.valueStyle = textStyle(this.settings.valueFont, '0.13px'); this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); this.showDate = this.settings.showDate; this.dateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.dateFormat); - this.dateStyle = textStyle(this.settings.dateFont, '1.33', '0.25px'); + this.dateStyle = textStyle(this.settings.dateFont, '0.25px'); this.dateColor = ColorProcessor.fromSettings(this.settings.dateColor); this.backgroundStyle = backgroundStyle(this.settings.background); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts index 549ba4abcd..aa442bd199 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.models.ts @@ -89,7 +89,8 @@ export const valueCardDefaultSettings = (horizontal: boolean): ValueCardWidgetSe size: 16, sizeUnit: 'px', style: 'normal', - weight: '500' + weight: '500', + lineHeight: '1.5' }, labelColor: constantColor('rgba(0, 0, 0, 0.87)'), showIcon: true, @@ -102,7 +103,8 @@ export const valueCardDefaultSettings = (horizontal: boolean): ValueCardWidgetSe size: 52, sizeUnit: 'px', style: 'normal', - weight: '500' + weight: '500', + lineHeight: '100%' }, valueColor: constantColor('rgba(0, 0, 0, 0.87)'), showDate: true, @@ -112,7 +114,8 @@ export const valueCardDefaultSettings = (horizontal: boolean): ValueCardWidgetSe size: 12, sizeUnit: 'px', style: 'normal', - weight: '500' + weight: '500', + lineHeight: '1.33' }, dateColor: constantColor('rgba(0, 0, 0, 0.38)'), background: { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts index 07b05db0f2..ecb10f3ade 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts @@ -42,15 +42,7 @@ import { import { IWidgetSubscription } from '@core/api/widget-api.models'; import { UtilsService } from '@core/services/utils.service'; import { TranslateService } from '@ngx-translate/core'; -import { - createLabelFromDatasource, - deepClone, - hashCode, - isDefined, - isNumber, - isObject, - isUndefined -} from '@core/utils'; +import { deepClone, hashCode, isDefined, isNumber, isObject, isUndefined } from '@core/utils'; import cssjs from '@core/css/css'; import { CollectionViewer, DataSource } from '@angular/cdk/collections'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; @@ -164,8 +156,6 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni private subscription: IWidgetSubscription; private widgetResize$: ResizeObserver; - private entitiesTitlePattern: string; - private defaultPageSize = 10; private defaultSortOrder = 'entityName'; @@ -266,7 +256,6 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni } public onDataUpdated() { - this.updateTitle(true); this.entityDatasource.dataUpdated(); this.clearCache(); this.ctx.detectChanges(); @@ -281,16 +270,15 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni this.setCellButtonAction = !!this.ctx.actionsApi.getActionDescriptors('actionCellButton').length; - this.hasRowAction = !!this.ctx.actionsApi.getActionDescriptors('rowClick').length || !!this.ctx.actionsApi.getActionDescriptors('rowDoubleClick').length; + this.hasRowAction = !!this.ctx.actionsApi.getActionDescriptors('rowClick').length || + !!this.ctx.actionsApi.getActionDescriptors('rowDoubleClick').length; if (this.settings.entitiesTitle && this.settings.entitiesTitle.length) { - this.entitiesTitlePattern = this.utils.customTranslation(this.settings.entitiesTitle, this.settings.entitiesTitle); + this.ctx.widgetTitle = this.settings.entitiesTitle; } else { - this.entitiesTitlePattern = this.translate.instant('entity.entities'); + this.ctx.widgetTitle = this.translate.instant('entity.entities'); } - this.updateTitle(false); - this.searchAction.show = isDefined(this.settings.enableSearch) ? this.settings.enableSearch : true; this.displayPagination = isDefined(this.settings.displayPagination) ? this.settings.displayPagination : true; this.enableStickyHeader = isDefined(this.settings.enableStickyHeader) ? this.settings.enableStickyHeader : true; @@ -319,16 +307,6 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni $(this.elementRef.nativeElement).addClass(namespace); } - private updateTitle(updateWidgetParams = false) { - const newTitle = createLabelFromDatasource(this.subscription.datasources[0], this.entitiesTitlePattern); - if (this.ctx.widgetTitle !== newTitle) { - this.ctx.widgetTitle = newTitle; - if (updateWidgetParams) { - this.ctx.updateWidgetParams(); - } - } - } - private updateDatasources() { const displayEntityName = isDefined(this.settings.displayEntityName) ? this.settings.displayEntityName : true; @@ -498,14 +476,12 @@ export class EntitiesTableWidgetComponent extends PageComponent implements OnIni overlayRef.dispose(); }); - const columns: DisplayColumn[] = this.columns.map(column => { - return { + const columns: DisplayColumn[] = this.columns.map(column => ({ title: column.title, def: column.def, display: this.displayedColumns.indexOf(column.def) > -1, selectable: this.columnSelectionAvailability[column.def] - }; - }); + })); const providers: StaticProvider[] = [ { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts index 20cce79457..2e9a9fb5f9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts @@ -94,12 +94,8 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit { private initializeConfig() { if (this.settings.widgetTitle && this.settings.widgetTitle.length) { - const title = createLabelFromDatasource(this.datasource, this.settings.widgetTitle); - this.ctx.widgetTitle = this.utils.customTranslation(title, title); - } else { - this.ctx.widgetTitle = this.ctx.widgetConfig.title; + this.ctx.widgetTitle = this.settings.widgetTitle; } - if (this.settings.labelValue && this.settings.labelValue.length) { const label = createLabelFromDatasource(this.datasource, this.settings.labelValue); this.labelValue = this.utils.customTranslation(label, label); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index 6f29a495cf..f667c785c1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -202,10 +202,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni private initializeConfig() { if (this.settings.widgetTitle && this.settings.widgetTitle.length) { - const titlePatternText = this.utils.customTranslation(this.settings.widgetTitle, this.settings.widgetTitle); - this.ctx.widgetTitle = createLabelFromDatasource(this.datasources[0], titlePatternText); - } else { - this.ctx.widgetTitle = this.ctx.widgetConfig.title; + this.ctx.widgetTitle = this.settings.widgetTitle; } this.settings.groupTitle = this.settings.groupTitle || '${entityName}'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html index 71a9b60118..73ee11f393 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html @@ -50,6 +50,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html index 36d488d766..9fe3273f74 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html @@ -72,6 +72,12 @@
+
+
widgets.widget-font.line-height
+ + + +
widgets.widget-font.preview
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts index 2f86394f44..a0e77ef380 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts @@ -101,7 +101,8 @@ export class FontSettingsPanelComponent extends PageComponent implements OnInit sizeUnit: [(this.font?.sizeUnit || 'px'), []], family: [this.font?.family, []], weight: [this.font?.weight, []], - style: [this.font?.style, []] + style: [this.font?.style, []], + lineHeight: [this.font?.lineHeight, []] } ); this.updatePreviewStyle(this.font); @@ -146,7 +147,7 @@ export class FontSettingsPanelComponent extends PageComponent implements OnInit } private updatePreviewStyle(font: Font) { - this.previewStyle = {...(this.initialPreviewStyle || {}), ...textStyle(font, '1')}; + this.previewStyle = {...(this.initialPreviewStyle || {}), ...textStyle(font)}; } } 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 d3dbb9853c..1b73ccbe4a 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 @@ -227,7 +227,7 @@ export class WidgetComponentService { } public clearWidgetInfo(widgetInfo: WidgetInfo, bundleAlias: string, widgetTypeAlias: string, isSystem: boolean): void { - this.dynamicComponentFactoryService.destroyDynamicComponentFactory(widgetInfo.componentFactory); + this.dynamicComponentFactoryService.destroyDynamicComponent(widgetInfo.componentType); this.widgetService.deleteWidgetInfoFromCache(bundleAlias, widgetTypeAlias, isSystem); } @@ -362,13 +362,14 @@ export class WidgetComponentService { return of(resolvedModules); } else { this.registerWidgetSettingsForms(widgetInfo, resolvedModules.factories); - return this.dynamicComponentFactoryService.createDynamicComponentFactory( + return this.dynamicComponentFactoryService.createDynamicComponent( class DynamicWidgetComponentInstance extends DynamicWidgetComponent {}, widgetInfo.templateHtml, resolvedModules.modules ).pipe( - map((factory) => { - widgetInfo.componentFactory = factory; + map((componentData) => { + widgetInfo.componentType = componentData.componentType; + widgetInfo.componentModuleRef = componentData.componentModuleRef; return null; }), catchError(e => { @@ -546,8 +547,8 @@ export class WidgetComponentService { if (isUndefined(result.typeParameters.previewHeight)) { result.typeParameters.previewHeight = '70%'; } - if (isUndefined(result.typeParameters.absoluteHeader)) { - result.typeParameters.absoluteHeader = false; + if (isUndefined(result.typeParameters.embedTitlePanel)) { + result.typeParameters.embedTitlePanel = false; } if (isFunction(widgetTypeInstance.actionSources)) { result.actionSources = widgetTypeInstance.actionSources(); 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 5f54970859..23440260d4 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 @@ -70,6 +70,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index da35390ffd..2bdf662469 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -369,7 +369,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe this.dataSettings.addControl('timewindowConfig', this.fb.control({ useDashboardTimewindow: true, displayTimewindow: true, - timewindow: null + timewindow: null, + timewindowStyle: null })); if (this.widgetType === widgetType.alarm) { this.dataSettings.addControl('alarmFilterConfig', this.fb.control(null)); @@ -517,7 +518,8 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe useDashboardTimewindow, displayTimewindow: isDefined(config.displayTimewindow) ? config.displayTimewindow : true, - timewindow: config.timewindow + timewindow: config.timewindow, + timewindowStyle: config.timewindowStyle }, {emitEvent: false}); } if (this.modelValue.isDataEnabled) { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html index 43b54884ec..1e3fd33171 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.html @@ -32,34 +32,13 @@ (click)="onClicked($event)" (contextmenu)="onContextMenu($event)">
-
- - {{widget.titleIcon}} - {{widget.customTranslatedTitle}} - - - -
+ class="tb-widget-header"> + + +
+ +
+
+ {{widget.titleIcon}} +
+ {{widget.title$ | async}} +
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss index 52caeb2a5c..a61dc463db 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss @@ -37,13 +37,6 @@ div.tb-widget { flex-direction: row; place-content: flex-start space-between; align-items: flex-start; - &-absolute { - position: absolute; - top: 0; - right: 0; - left: 0; - z-index: 1; - } } .tb-widget-title { @@ -59,23 +52,24 @@ div.tb-widget { tb-timewindow { font-size: 14px; opacity: .85; - margin: 0; } - .title { + .title-row { + display: flex; + flex-direction: row; + place-content: center flex-start; + align-items: center; + gap: 4px; width: 100%; + } + + .title { overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; line-height: 24px; - letter-spacing: .01em; + letter-spacing: normal; margin: 0; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - - &.single-row{ - -webkit-line-clamp: 1; - } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.ts index 41f3fe7e4f..bc298734fc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-preview.component.ts @@ -77,13 +77,15 @@ export class WidgetPreviewComponent extends PageComponent implements OnInit, OnC } private loadPreviewWidget() { - const widget = deepClone(this.widget); - widget.sizeX = 24; - widget.sizeY = this.widget.sizeY * 2; - widget.row = 0; - widget.col = 0; - widget.config = this.widgetConfig; - this.widgets = [widget]; + if (this.widget) { + const widget = deepClone(this.widget); + widget.sizeX = 24; + widget.sizeY = this.widget.sizeY * 2; + widget.row = 0; + widget.col = 0; + widget.config = this.widgetConfig; + this.widgets = [widget]; + } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index c276999d83..fe8bcd78c1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -32,6 +32,7 @@ import { Optional, Renderer2, SimpleChanges, + TemplateRef, Type, ViewChild, ViewContainerRef, @@ -125,6 +126,9 @@ import { IModulesMap } from '@modules/common/modules-map.models'; }) export class WidgetComponent extends PageComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { + @Input() + widgetTitlePanel: TemplateRef; + @Input() isEdit: boolean; @@ -308,9 +312,6 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI this.loadFromWidgetInfo(); } ); - setTimeout(() => { - this.dashboardWidget.updateWidgetParams(); - }, 0); const noDataDisplayMessage = this.widget.config.noDataDisplayMessage; if (isNotEmptyStr(noDataDisplayMessage)) { @@ -387,7 +388,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI this.handleWidgetException(e); } } - this.widgetContext.destroyed = true; + this.widgetContext.destroy(); this.destroyDynamicWidgetComponent(); } } @@ -409,7 +410,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI elem.classList.add(this.widgetContext.widgetNamespace); this.widgetType = this.widgetInfo.widgetTypeFunction; this.typeParameters = this.widgetInfo.typeParameters; - this.widgetContext.absoluteHeader = this.typeParameters.absoluteHeader; + this.widgetContext.embedTitlePanel = this.typeParameters.embedTitlePanel; if (!this.widgetType) { this.widgetTypeInstance = {}; @@ -480,6 +481,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI } if (!this.widgetContext.inited && this.isReady()) { this.widgetContext.inited = true; + this.dashboardWidget.updateWidgetParams(); this.widgetContext.detectContainerChanges(); if (this.cafs.init) { this.cafs.init(); @@ -493,7 +495,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI if (this.dataUpdatePending) { this.widgetTypeInstance.onDataUpdated(); setTimeout(() => { - this.dashboardWidget.updateCustomHeaderActions(true); + this.dashboardWidget.updateParamsFromData(true); }, 0); this.dataUpdatePending = false; } @@ -735,6 +737,10 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI { provide: 'errorMessages', useValue: this.errorMessages + }, + { + provide: 'widgetTitlePanel', + useValue: this.widgetTitlePanel } ], parent: this.injector @@ -745,7 +751,8 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI this.widgetContext.$containerParent = $(containerElement); try { - this.dynamicWidgetComponentRef = this.widgetContentContainer.createComponent(this.widgetInfo.componentFactory, 0, injector); + this.dynamicWidgetComponentRef = this.widgetContentContainer.createComponent(this.widgetInfo.componentType, + {index: 0, injector, ngModuleRef: this.widgetInfo.componentModuleRef}); this.cd.detectChanges(); } catch (e) { if (this.dynamicWidgetComponentRef) { @@ -845,7 +852,7 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI if (this.widgetInstanceInited) { this.widgetTypeInstance.onDataUpdated(); setTimeout(() => { - this.dashboardWidget.updateCustomHeaderActions(true); + this.dashboardWidget.updateParamsFromData(true); }, 0); } else { this.dataUpdatePending = true; diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 5bae1ad256..364973d013 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -33,7 +33,7 @@ import { IAliasController, IStateController } from '@app/core/api/widget-api.mod import { enumerable } from '@shared/decorators/enumerable'; import { UtilsService } from '@core/services/utils.service'; import { TbPopoverComponent } from '@shared/components/popover.component'; -import { ComponentStyle, textStyle } from '@shared/models/widget-settings.models'; +import { ComponentStyle, iconStyle, textStyle } from '@shared/models/widget-settings.models'; export interface WidgetsData { widgets: Array; @@ -331,8 +331,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { margin: string; borderRadius: string; - title: string; - customTranslatedTitle: string; + title$: Observable; titleTooltip: string; showTitle: boolean; titleStyle: ComponentStyle; @@ -431,30 +430,23 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { this.margin = this.widget.config.margin || '0px'; this.borderRadius = this.widget.config.borderRadius; - this.title = isDefined(this.widgetContext.widgetTitle) + const title = isDefined(this.widgetContext.widgetTitle) && this.widgetContext.widgetTitle.length ? this.widgetContext.widgetTitle : this.widget.config.title; - this.customTranslatedTitle = this.dashboard.utils.customTranslation(this.title, this.title); + this.title$ = this.widgetContext.registerLabelPattern('widgetTitle', title); this.titleTooltip = isDefined(this.widgetContext.widgetTitleTooltip) && this.widgetContext.widgetTitleTooltip.length ? this.widgetContext.widgetTitleTooltip : this.widget.config.titleTooltip; this.titleTooltip = this.dashboard.utils.customTranslation(this.titleTooltip, this.titleTooltip); this.showTitle = isDefined(this.widget.config.showTitle) ? this.widget.config.showTitle : true; - this.titleStyle = {...(this.widget.config.titleStyle || {}), ...textStyle(this.widget.config.titleFont, '24px', '0.01em')}; + this.titleStyle = {...(this.widget.config.titleStyle || {}), ...textStyle(this.widget.config.titleFont, 'normal')}; if (this.widget.config.titleColor) { this.titleStyle.color = this.widget.config.titleColor; } this.titleIcon = isDefined(this.widget.config.titleIcon) ? this.widget.config.titleIcon : ''; this.showTitleIcon = isDefined(this.widget.config.showTitleIcon) ? this.widget.config.showTitleIcon : false; - this.titleIconStyle = {}; + this.titleIconStyle = this.widget.config.iconSize ? iconStyle(this.widget.config.iconSize) : {}; if (this.widget.config.iconColor) { this.titleIconStyle.color = this.widget.config.iconColor; } - if (this.widget.config.iconSize) { - this.titleIconStyle.width = this.widget.config.iconSize; - this.titleIconStyle.height = this.widget.config.iconSize; - this.titleIconStyle.fontSize = this.widget.config.iconSize; - this.titleIconStyle.lineHeight = this.widget.config.iconSize; - } - this.dropShadow = isDefined(this.widget.config.dropShadow) ? this.widget.config.dropShadow : true; this.enableFullscreen = isDefined(this.widget.config.enableFullscreen) ? this.widget.config.enableFullscreen : true; @@ -497,14 +489,22 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { this.showWidgetActions = !this.widgetContext.hideTitlePanel; - this.updateCustomHeaderActions(); + this.updateParamsFromData(); this.widgetActions = this.widgetContext.widgetActions ? this.widgetContext.widgetActions : []; if (detectChanges) { this.widgetContext.detectContainerChanges(); } } - updateCustomHeaderActions(detectChanges = false) { + updateParamsFromData(detectChanges = false) { + this.widgetContext.updateLabelPatterns(); + const update = this.updateCustomHeaderActions(); + if (update && detectChanges) { + this.widgetContext.detectContainerChanges(); + } + } + + private updateCustomHeaderActions(): boolean { let customHeaderActions: Array; if (this.widgetContext.customHeaderActions) { let data: FormattedData[] = []; @@ -517,10 +517,9 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { } if (!isEqual(this.customHeaderActions, customHeaderActions)) { this.customHeaderActions = customHeaderActions; - if (detectChanges) { - this.widgetContext.detectContainerChanges(); - } + return true; } + return false; } private filterCustomHeaderAction(action: WidgetHeaderAction, data: FormattedData[]): boolean { diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index 18c8ccd19e..02086e57ef 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -45,13 +45,13 @@ import { WidgetActionsApi, WidgetSubscriptionApi } from '@core/api/widget-api.models'; -import { ChangeDetectorRef, ComponentFactory, Injector, NgZone, Type } from '@angular/core'; +import { ChangeDetectorRef, Injector, NgModuleRef, NgZone, Type } from '@angular/core'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { RafService } from '@core/services/raf.service'; import { WidgetTypeId } from '@shared/models/id/widget-type-id'; import { TenantId } from '@shared/models/id/tenant-id'; import { WidgetLayout } from '@shared/models/dashboard.models'; -import { formatValue, isDefined } from '@core/utils'; +import { createLabelFromDatasource, formatValue, hasDatasourceLabelsVariables, isDefined } from '@core/utils'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { @@ -87,10 +87,12 @@ import * as RxJS from 'rxjs'; import * as RxJSOperators from 'rxjs/operators'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { EntityId } from '@shared/models/id/entity-id'; -import { AlarmQuery, AlarmSearchStatus, AlarmStatus} from '@app/shared/models/alarm.models'; +import { AlarmQuery, AlarmSearchStatus, AlarmStatus } from '@app/shared/models/alarm.models'; import { MillisecondsToTimeStringPipe, TelemetrySubscriber } from '@app/shared/public-api'; import { UserId } from '@shared/models/id/user-id'; import { UserSettingsService } from '@core/http/user-settings.service'; +import { DynamicComponentModule } from '@core/services/dynamic-component-factory.service'; +import { BehaviorSubject, Observable } from 'rxjs'; export interface IWidgetAction { name: string; @@ -200,6 +202,8 @@ export class WidgetContext { subscriptions: {[id: string]: IWidgetSubscription} = {}; defaultSubscription: IWidgetSubscription = null; + labelPatterns: {[id: string]: LabelVariablePattern} = {}; + timewindowFunctions: TimewindowFunctions = { onUpdateTimewindow: (startTimeMs, endTimeMs, interval) => { if (this.defaultSubscription) { @@ -265,7 +269,7 @@ export class WidgetContext { hiddenData?: Array<{data: DataSet}>; timeWindow?: WidgetTimewindow; - absoluteHeader?: boolean; + embedTitlePanel?: boolean; hideTitlePanel = false; @@ -312,6 +316,23 @@ export class WidgetContext { }); } + registerLabelPattern(id: string, label: string): Observable { + let labelPattern = this.labelPatterns[id]; + if (labelPattern) { + labelPattern.setupPattern(label); + } else { + labelPattern = new LabelVariablePattern(label, this); + this.labelPatterns[id] = labelPattern; + } + return labelPattern.label$; + } + + updateLabelPatterns() { + for (const key of Object.keys(this.labelPatterns)) { + this.labelPatterns[key].update(); + } + } + showSuccessToast(message: string, duration: number = 1000, verticalPosition: NotificationVerticalPosition = 'bottom', horizontalPosition: NotificationHorizontalPosition = 'left', @@ -406,6 +427,14 @@ export class WidgetContext { this.widgetActions = undefined; } + destroy() { + for (const key of Object.keys(this.labelPatterns)) { + this.labelPatterns[key].destroy(); + } + this.labelPatterns = {}; + this.destroyed = true; + } + closeDialog(resultData: any = null) { const dialogRef = this.$scope.dialogRef || this.stateController.dashboardCtrl.dashboardCtx.getDashboard().dialogRef; if (dialogRef) { @@ -426,6 +455,41 @@ export class WidgetContext { } } +export class LabelVariablePattern { + + private pattern: string; + private hasVariables: boolean; + + private labelSubject = new BehaviorSubject(''); + + public label$ = this.labelSubject.asObservable(); + + constructor(label: string, + private ctx: WidgetContext) { + this.setupPattern(label); + } + + setupPattern(label: string) { + this.pattern = this.ctx.dashboard.utils.customTranslation(label, label); + this.hasVariables = hasDatasourceLabelsVariables(this.pattern); + this.update(); + } + + update() { + let label = this.pattern; + if (this.hasVariables && this.ctx.defaultSubscription?.datasources?.length) { + label = createLabelFromDatasource(this.ctx.defaultSubscription.datasources[0], label); + } + if (this.labelSubject.value !== label) { + this.labelSubject.next(label); + } + } + + destroy() { + this.labelSubject.complete(); + } +} + export interface IDynamicWidgetComponent { readonly ctx: WidgetContext; readonly errorMessages: string[]; @@ -446,7 +510,8 @@ export interface WidgetInfo extends WidgetTypeDescriptor, WidgetControllerDescri typeLatestDataKeySettingsSchema?: string | any; image?: string; description?: string; - componentFactory?: ComponentFactory; + componentType?: Type; + componentModuleRef?: NgModuleRef; } export interface WidgetConfigComponentData { diff --git a/ui-ngx/src/app/shared/components/color-input.component.ts b/ui-ngx/src/app/shared/components/color-input.component.ts index 2f0b7b1dae..834fcb8176 100644 --- a/ui-ngx/src/app/shared/components/color-input.component.ts +++ b/ui-ngx/src/app/shared/components/color-input.component.ts @@ -153,10 +153,10 @@ export class ColorInputComponent extends PageComponent implements OnInit, Contro $event.stopPropagation(); this.dialogs.colorPicker(this.colorFormGroup.get('color').value, this.colorClearButton).subscribe( - (color) => { - if (color) { + (result) => { + if (!result?.canceled) { this.colorFormGroup.patchValue( - {color}, {emitEvent: true} + {color: result?.color}, {emitEvent: true} ); this.cd.markForCheck(); } diff --git a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts index 06d24f026b..38fcedf406 100644 --- a/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/color-picker-dialog.component.ts @@ -26,12 +26,17 @@ export interface ColorPickerDialogData { colorClearButton: boolean; } +export interface ColorPickerDialogResult { + color?: string; + canceled?: boolean; +} + @Component({ selector: 'tb-color-picker-dialog', templateUrl: './color-picker-dialog.component.html', styleUrls: ['./color-picker-dialog.component.scss'] }) -export class ColorPickerDialogComponent extends DialogComponent { +export class ColorPickerDialogComponent extends DialogComponent { color: string; colorClearButton: boolean; @@ -39,18 +44,18 @@ export class ColorPickerDialogComponent extends DialogComponent, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: ColorPickerDialogData, - public dialogRef: MatDialogRef) { + public dialogRef: MatDialogRef) { super(store, router, dialogRef); this.color = data.color; this.colorClearButton = data.colorClearButton; } selectColor(color: string) { - this.dialogRef.close(color); + this.dialogRef.close({color}); } cancel(): void { - this.dialogRef.close(null); + this.dialogRef.close({canceled: true}); } } diff --git a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.html index 1051be6525..632e9216be 100644 --- a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.html @@ -23,6 +23,7 @@ close
diff --git a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts index b6321c966d..53aec6d74f 100644 --- a/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/material-icons-dialog.component.ts @@ -23,6 +23,12 @@ import { DialogComponent } from '@shared/components/dialog.component'; export interface MaterialIconsDialogData { icon: string; + iconClearButton: boolean; +} + +export interface MaterialIconsDialogResult { + icon?: string; + canceled?: boolean; } @Component({ @@ -31,24 +37,26 @@ export interface MaterialIconsDialogData { providers: [], styleUrls: ['./material-icons-dialog.component.scss'] }) -export class MaterialIconsDialogComponent extends DialogComponent { +export class MaterialIconsDialogComponent extends DialogComponent { selectedIcon: string; + iconClearButton: boolean; constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: MaterialIconsDialogData, - public dialogRef: MatDialogRef) { + public dialogRef: MatDialogRef) { super(store, router, dialogRef); this.selectedIcon = data.icon; + this.iconClearButton = data.iconClearButton; } selectIcon(icon: string) { - this.dialogRef.close(icon); + this.dialogRef.close({icon}); } cancel(): void { - this.dialogRef.close(null); + this.dialogRef.close({canceled: true}); } } diff --git a/ui-ngx/src/app/shared/components/icon.component.ts b/ui-ngx/src/app/shared/components/icon.component.ts index d1e2c6ddcd..fcc7b70081 100644 --- a/ui-ngx/src/app/shared/components/icon.component.ts +++ b/ui-ngx/src/app/shared/components/icon.component.ts @@ -120,7 +120,7 @@ export class TbIconComponent extends _TbIconBase this._contentChanges = this.contentObserver.observe(this._iconNameContent.nativeElement) .subscribe(() => { const content = this.viewValue; - if (content && this.icon !== content) { + if (this.icon !== content) { this.icon = content; this._updateIcon(); } diff --git a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts b/ui-ngx/src/app/shared/components/json-form/json-form.component.ts index 6ed1d133ae..6da145d826 100644 --- a/ui-ngx/src/app/shared/components/json-form/json-form.component.ts +++ b/ui-ngx/src/app/shared/components/json-form/json-form.component.ts @@ -216,9 +216,9 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato private onColorClick(key: (string | number)[], val: tinycolor.ColorFormats.RGBA, colorSelectedFn: (color: tinycolor.ColorFormats.RGBA) => void) { - this.dialogs.colorPicker(tinycolor(val).toRgbString()).subscribe((color) => { - if (color && colorSelectedFn) { - colorSelectedFn(tinycolor(color).toRgb()); + this.dialogs.colorPicker(tinycolor(val).toRgbString()).subscribe((result) => { + if (!result?.canceled && colorSelectedFn) { + colorSelectedFn(tinycolor(result?.color).toRgb()); } }); } @@ -226,9 +226,9 @@ export class JsonFormComponent implements OnInit, ControlValueAccessor, Validato private onIconClick(key: (string | number)[], val: string, iconSelectedFn: (icon: string) => void) { - this.dialogs.materialIconPicker(val).subscribe((icon) => { - if (icon && iconSelectedFn) { - iconSelectedFn(icon); + this.dialogs.materialIconPicker(val).subscribe((result) => { + if (!result?.canceled && iconSelectedFn) { + iconSelectedFn(result?.icon); } }); } diff --git a/ui-ngx/src/app/shared/components/markdown.component.ts b/ui-ngx/src/app/shared/components/markdown.component.ts index cd03959fad..7936d2f51a 100644 --- a/ui-ngx/src/app/shared/components/markdown.component.ts +++ b/ui-ngx/src/app/shared/components/markdown.component.ts @@ -17,7 +17,6 @@ import { ChangeDetectorRef, Component, - ComponentFactory, ComponentRef, ElementRef, EventEmitter, @@ -91,7 +90,7 @@ export class TbMarkdownComponent implements OnChanges { error = null; private tbMarkdownInstanceComponentRef: ComponentRef; - private tbMarkdownInstanceComponentFactory: ComponentFactory; + private tbMarkdownInstanceComponentType: Type; constructor(private help: HelpService, private cd: ChangeDetectorRef, @@ -153,7 +152,7 @@ export class TbMarkdownComponent implements OnChanges { if (this.additionalCompileModules) { compileModules = compileModules.concat(this.additionalCompileModules); } - this.dynamicComponentFactoryService.createDynamicComponentFactory( + this.dynamicComponentFactoryService.createDynamicComponent( class TbMarkdownInstance { ngOnDestroy(): void { parent.destroyMarkdownInstanceResources(); @@ -162,12 +161,13 @@ export class TbMarkdownComponent implements OnChanges { template, compileModules, true, 1, styles - ).subscribe((factory) => { - this.tbMarkdownInstanceComponentFactory = factory; + ).subscribe((componentData) => { + this.tbMarkdownInstanceComponentType = componentData.componentType; const injector: Injector = Injector.create({providers: [], parent: this.markdownContainer.injector}); try { this.tbMarkdownInstanceComponentRef = - this.markdownContainer.createComponent(this.tbMarkdownInstanceComponentFactory, 0, injector); + this.markdownContainer.createComponent(this.tbMarkdownInstanceComponentType, + {index: 0, injector, ngModuleRef: componentData.componentModuleRef}); if (this.context) { for (const propName of Object.keys(this.context)) { this.tbMarkdownInstanceComponentRef.instance[propName] = this.context[propName]; @@ -261,9 +261,9 @@ export class TbMarkdownComponent implements OnChanges { } private destroyMarkdownInstanceResources() { - if (this.tbMarkdownInstanceComponentFactory) { - this.dynamicComponentFactoryService.destroyDynamicComponentFactory(this.tbMarkdownInstanceComponentFactory); - this.tbMarkdownInstanceComponentFactory = null; + if (this.tbMarkdownInstanceComponentType) { + this.dynamicComponentFactoryService.destroyDynamicComponent(this.tbMarkdownInstanceComponentType); + this.tbMarkdownInstanceComponentType = null; } this.tbMarkdownInstanceComponentRef = null; } diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.ts b/ui-ngx/src/app/shared/components/material-icon-select.component.ts index 740bb4545a..255aeb0668 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.ts +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.ts @@ -54,17 +54,9 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit @Input() disabled: boolean; - private iconClearButtonValue: boolean; - get iconClearButton(): boolean { - return this.iconClearButtonValue; - } @Input() - set iconClearButton(value: boolean) { - const newVal = coerceBooleanProperty(value); - if (this.iconClearButtonValue !== newVal) { - this.iconClearButtonValue = newVal; - } - } + @coerceBoolean() + iconClearButton = false; private requiredValue: boolean; get required(): boolean { @@ -135,11 +127,12 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit openIconDialog() { if (!this.disabled) { - this.dialogs.materialIconPicker(this.materialIconFormGroup.get('icon').value).subscribe( - (icon) => { - if (icon) { + this.dialogs.materialIconPicker(this.materialIconFormGroup.get('icon').value, + this.iconClearButton).subscribe( + (result) => { + if (!result?.canceled) { this.materialIconFormGroup.patchValue( - {icon}, {emitEvent: true} + {icon: result?.icon}, {emitEvent: true} ); this.cd.markForCheck(); } @@ -159,7 +152,8 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit const materialIconsPopover = this.popoverService.displayPopover(trigger, this.renderer, this.viewContainerRef, MaterialIconsComponent, 'left', true, null, { - selectedIcon: this.materialIconFormGroup.get('icon').value + selectedIcon: this.materialIconFormGroup.get('icon').value, + iconClearButton: this.iconClearButton }, {}, {}, {}, true); diff --git a/ui-ngx/src/app/shared/components/material-icons.component.html b/ui-ngx/src/app/shared/components/material-icons.component.html index d31a73ddb5..79476572f6 100644 --- a/ui-ngx/src/app/shared/components/material-icons.component.html +++ b/ui-ngx/src/app/shared/components/material-icons.component.html @@ -62,4 +62,13 @@
{{ 'icon.no-icons-found' | translate:{iconSearch: searchIconControl.value} }}
+
+ +
diff --git a/ui-ngx/src/app/shared/components/material-icons.component.scss b/ui-ngx/src/app/shared/components/material-icons.component.scss index 23b959d118..8cf84e0687 100644 --- a/ui-ngx/src/app/shared/components/material-icons.component.scss +++ b/ui-ngx/src/app/shared/components/material-icons.component.scss @@ -58,4 +58,12 @@ margin: 0; } } + .tb-material-icons-panel-buttons { + height: 40px; + display: flex; + flex-direction: row; + gap: 16px; + align-items: flex-start; + align-self: flex-start; + } } diff --git a/ui-ngx/src/app/shared/components/material-icons.component.ts b/ui-ngx/src/app/shared/components/material-icons.component.ts index 9347243af2..1d826816b7 100644 --- a/ui-ngx/src/app/shared/components/material-icons.component.ts +++ b/ui-ngx/src/app/shared/components/material-icons.component.ts @@ -36,6 +36,7 @@ import { ResourcesService } from '@core/services/resources.service'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { BreakpointObserver } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-material-icons', @@ -52,6 +53,10 @@ export class MaterialIconsComponent extends PageComponent implements OnInit { @Input() selectedIcon: string; + @Input() + @coerceBoolean() + iconClearButton = false; + @Input() popover: TbPopoverComponent; @@ -123,6 +128,10 @@ export class MaterialIconsComponent extends PageComponent implements OnInit { this.iconSelected.emit(icon.name); } + clearIcon() { + this.iconSelected.emit(null); + } + private calculatePanelSize(iconsRowSize: number, iconRows = 4) { this.iconsPanelHeight = Math.min(iconRows * this.iconsRowHeight, 10 * this.iconsRowHeight) + 'px'; this.iconsPanelWidth = (iconsRowSize * 36 + (iconsRowSize - 1) * 12 + 6) + 'px'; 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 e445e99c98..a53ea656fc 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.html +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.html @@ -41,26 +41,16 @@
- - + [class]="{'no-padding': noPadding}" + matTooltip="{{ 'timewindow.edit' | translate }}" + [matTooltipPosition]="tooltipPosition" + [style]="timewindowComponentStyle" + (click)="toggleTimewindow($event)"> + {{ computedTimewindowStyle.icon }} +
{{innerValue?.displayValue}} | {{innerValue?.displayTimezoneAbbr}} - - +
+ {{ computedTimewindowStyle.icon }}
diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.scss b/ui-ngx/src/app/shared/components/time/timewindow.component.scss index af3feec6eb..a00fe5bdc1 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.scss +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.scss @@ -24,15 +24,24 @@ max-width: 100%; } section.tb-timewindow { - min-height: 32px; padding: 0 8px; + &.no-padding { + padding: 0; + } + line-height: 32px; + pointer-events: all; + cursor: pointer; + display: flex; + flex-direction: row; + place-content: center flex-start; + align-items: center; + gap: 4px; + width: 100%; - span { + .tb-timewindow-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - pointer-events: all; - cursor: pointer; } .timezone-abbr { diff --git a/ui-ngx/src/app/shared/components/time/timewindow.component.ts b/ui-ngx/src/app/shared/components/time/timewindow.component.ts index ff39e54fc7..ba8b4ba114 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow.component.ts +++ b/ui-ngx/src/app/shared/components/time/timewindow.component.ts @@ -20,7 +20,7 @@ import { ElementRef, forwardRef, HostBinding, Injector, - Input, + Input, OnChanges, OnInit, SimpleChanges, StaticProvider, ViewContainerRef } from '@angular/core'; @@ -50,6 +50,12 @@ import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay'; import { ComponentPortal } from '@angular/cdk/portal'; import { coerceBoolean } from '@shared/decorators/coercion'; +import { + ComponentStyle, + defaultTimewindowStyle, iconStyle, + textStyle, + TimewindowStyle +} from '@shared/models/widget-settings.models'; // @dynamic @Component({ @@ -64,7 +70,7 @@ import { coerceBoolean } from '@shared/decorators/coercion'; } ] }) -export class TimewindowComponent implements ControlValueAccessor { +export class TimewindowComponent implements ControlValueAccessor, OnInit, OnChanges { historyOnlyValue = false; @@ -88,6 +94,14 @@ export class TimewindowComponent implements ControlValueAccessor { @coerceBoolean() noMargin = false; + @Input() + @coerceBoolean() + noPadding = false; + + @Input() + @coerceBoolean() + disablePanel = false; + @Input() @coerceBoolean() forAllTimeEnabled = false; @@ -145,10 +159,10 @@ export class TimewindowComponent implements ControlValueAccessor { } @Input() - direction: 'left' | 'right' = 'left'; + tooltipPosition: TooltipPosition = 'above'; @Input() - tooltipPosition: TooltipPosition = 'above'; + timewindowStyle: TimewindowStyle; @Input() @coerceBoolean() @@ -158,6 +172,10 @@ export class TimewindowComponent implements ControlValueAccessor { timewindowDisabled: boolean; + computedTimewindowStyle: TimewindowStyle; + timewindowComponentStyle: ComponentStyle; + timewindowIconStyle: ComponentStyle; + private propagateChange = (_: any) => {}; constructor(private overlay: Overlay, @@ -170,10 +188,28 @@ export class TimewindowComponent implements ControlValueAccessor { public viewContainerRef: ViewContainerRef) { } + ngOnInit() { + this.updateTimewindowStyle(); + } + + ngOnChanges(changes: SimpleChanges): void { + for (const propName of Object.keys(changes)) { + const change = changes[propName]; + if (!change.firstChange && change.currentValue !== change.previousValue) { + if (propName === 'timewindowStyle') { + this.updateTimewindowStyle(); + } + } + } + } + toggleTimewindow($event: Event) { if ($event) { $event.stopPropagation(); } + if (this.disablePanel) { + return; + } const config = new OverlayConfig({ panelClass: 'tb-timewindow-panel', backdropClass: 'cdk-overlay-transparent-backdrop', @@ -226,6 +262,17 @@ export class TimewindowComponent implements ControlValueAccessor { this.cd.detectChanges(); } + private updateTimewindowStyle() { + if (!this.asButton) { + this.computedTimewindowStyle = {...defaultTimewindowStyle, ...(this.timewindowStyle || {})}; + this.timewindowComponentStyle = textStyle(this.computedTimewindowStyle.font); + if (this.computedTimewindowStyle.color) { + this.timewindowComponentStyle.color = this.computedTimewindowStyle.color; + } + this.timewindowIconStyle = this.computedTimewindowStyle.iconSize ? iconStyle(this.computedTimewindowStyle.iconSize) : {}; + } + } + private onHistoryOnlyChanged(): boolean { if (this.historyOnlyValue && this.innerValue && this.innerValue.selectedTab !== TimewindowType.HISTORY) { this.innerValue.selectedTab = TimewindowType.HISTORY; diff --git a/ui-ngx/src/app/shared/models/widget-settings.models.ts b/ui-ngx/src/app/shared/models/widget-settings.models.ts index f7c1b6746e..18782cdd93 100644 --- a/ui-ngx/src/app/shared/models/widget-settings.models.ts +++ b/ui-ngx/src/app/shared/models/widget-settings.models.ts @@ -60,6 +60,7 @@ export interface Font { family: string; weight: fontWeight; style: fontStyle; + lineHeight: string; } export enum ColorType { @@ -89,6 +90,22 @@ export interface ColorSettings { colorFunction?: string; } +export interface TimewindowStyle { + showIcon: boolean; + icon: string; + iconSize: string; + iconPosition: 'left' | 'right'; + font?: Font; + color?: string; +} + +export const defaultTimewindowStyle: TimewindowStyle = { + showIcon: true, + icon: 'query_builder', + iconSize: '24px', + iconPosition: 'left' +}; + export const constantColor = (color: string): ColorSettings => ({ type: ColorType.constant, color, @@ -298,19 +315,19 @@ export interface BackgroundSettings { overlay: OverlaySettings; } -export const iconStyle = (size: number, sizeUnit: cssUnit): ComponentStyle => { - const iconSize = size + sizeUnit; +export const iconStyle = (size: number | string, sizeUnit: cssUnit = 'px'): ComponentStyle => { + const iconSize = typeof size === 'number' ? size + sizeUnit : size; return { width: iconSize, + minWidth: iconSize, height: iconSize, fontSize: iconSize, lineHeight: iconSize }; }; -export const textStyle = (font?: Font, lineHeight = '1.5', letterSpacing = '0.25px'): ComponentStyle => { +export const textStyle = (font?: Font, letterSpacing = 'normal'): ComponentStyle => { const style: ComponentStyle = { - lineHeight, letterSpacing }; if (font?.style) { @@ -319,6 +336,9 @@ export const textStyle = (font?: Font, lineHeight = '1.5', letterSpacing = '0.25 if (font?.weight) { style.fontWeight = font.weight; } + if (font?.lineHeight) { + style.lineHeight = font.lineHeight; + } if (font?.size) { style.fontSize = (font.size + (font.sizeUnit || 'px')); } diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index c3b23048d1..3a566d8b9c 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -40,7 +40,7 @@ import { Dashboard } from '@shared/models/dashboard.models'; import { IAliasController } from '@core/api/widget-api.models'; import { isEmptyStr } from '@core/utils'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; -import { ComponentStyle, Font } from '@shared/models/widget-settings.models'; +import { ComponentStyle, Font, TimewindowStyle } from '@shared/models/widget-settings.models'; export enum widgetType { timeseries = 'timeseries', @@ -183,7 +183,7 @@ export interface WidgetTypeParameters { processNoDataByWidget?: boolean; previewWidth?: string; previewHeight?: string; - absoluteHeader?: boolean; + embedTitlePanel?: boolean; } export interface WidgetControllerDescriptor { @@ -633,6 +633,7 @@ export interface WidgetConfig { useDashboardTimewindow?: boolean; displayTimewindow?: boolean; timewindow?: Timewindow; + timewindowStyle?: TimewindowStyle; desktopHide?: boolean; mobileHide?: boolean; mobileHeight?: number; 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 026ebf857e..95d5199947 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3902,7 +3902,15 @@ "interval": "Interval", "just-now": "Just now", "just-now-lower": "just now", - "ago": "ago" + "ago": "ago", + "style": "Timewindow style", + "icon": "Icon", + "icon-position": "Icon position", + "icon-position-left": "Left", + "icon-position-right": "Right", + "font": "Font", + "color": "Color", + "preview": "Preview" }, "unit": { "millimeter": "Millimeter", @@ -5799,7 +5807,8 @@ "font-weight-lighter": "Lighter", "color": "Color", "shadow-color": "Shadow color", - "preview": "Preview" + "preview": "Preview", + "line-height": "Line height" }, "home": { "no-data-available": "No data available" From 71fe11d54dc4f83123ae61e5f89896795e259815 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 8 Aug 2023 19:08:40 +0300 Subject: [PATCH 394/421] UI: Fix value cards default config. --- .../src/main/data/json/system/widget_bundles/cards.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index b87f2c7b83..dd25e00442 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -244,7 +244,7 @@ "settingsDirective": "tb-value-card-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-value-card-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"constant\",\"color\":\"#5469FF\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" } }, { @@ -265,7 +265,7 @@ "settingsDirective": "tb-value-card-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-value-card-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"constant\",\"color\":\"#5469FF\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" } } ] From 32fae3a4b695871fda9013cf4b7f91772d664604 Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 9 Aug 2023 11:33:22 +0300 Subject: [PATCH 395/421] tbel: add gecodeToJson(String.class) --- .../thingsboard/script/api/tbel/TbUtils.java | 5 +++++ .../script/api/tbel/TbUtilsTest.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index b337612011..bffd60f029 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -57,6 +57,8 @@ public class TbUtils { List.class))); parserConfig.addImport("decodeToJson", new MethodStub(TbUtils.class.getMethod("decodeToJson", ExecutionContext.class, List.class))); + parserConfig.addImport("decodeToJson", new MethodStub(TbUtils.class.getMethod("decodeToJson", + ExecutionContext.class, String.class))); parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes", ExecutionContext.class, String.class))); parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes", @@ -174,6 +176,9 @@ public class TbUtils { public static Object decodeToJson(ExecutionContext ctx, List bytesList) throws IOException { return TbJson.parse(ctx, bytesToString(bytesList)); } + public static Object decodeToJson(ExecutionContext ctx, String jsonStr) throws IOException { + return TbJson.parse(ctx, jsonStr); + } public static String bytesToString(List bytesList) { byte[] bytes = bytesFromList(bytesList); diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java index b6d5395af8..a16a70b962 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java @@ -27,6 +27,7 @@ import org.mvel2.SandboxedParserConfiguration; import org.mvel2.execution.ExecutionArrayList; import org.mvel2.execution.ExecutionHashMap; +import java.io.IOException; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -348,6 +349,24 @@ public class TbUtilsTest { Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleVaList, 0, false))); } + @Test + public void parseBytesDecodeToJson() throws IOException { + String expectedStr = "{\"hello\": \"world\"}"; + ExecutionHashMap expectedJson = new ExecutionHashMap<>(1, ctx); + expectedJson.put("hello", "world"); + List expectedBytes = TbUtils.stringToBytes(ctx, expectedStr); + Object actualJson = TbUtils.decodeToJson(ctx, expectedBytes); + Assert.assertEquals(expectedJson,actualJson); + } + @Test + public void parseStringDecodeToJson() throws IOException { + String expectedStr = "{\"hello\": \"world\"}"; + ExecutionHashMap expectedJson = new ExecutionHashMap<>(1, ctx); + expectedJson.put("hello", "world"); + Object actualJson = TbUtils.decodeToJson(ctx, expectedStr); + Assert.assertEquals(expectedJson,actualJson); + } + private static List toList(byte[] data) { List result = new ArrayList<>(data.length); for (Byte b : data) { From ba85007a2dab10ba2bb8c0839b551e07c6a2f747 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 9 Aug 2023 10:59:13 +0200 Subject: [PATCH 396/421] minor improvements --- .../server/controller/TelemetryController.java | 10 ++++++---- ui-ngx/src/assets/locale/locale.constant-ca_ES.json | 1 + ui-ngx/src/assets/locale/locale.constant-cs_CZ.json | 1 + ui-ngx/src/assets/locale/locale.constant-da_DK.json | 1 + ui-ngx/src/assets/locale/locale.constant-de_DE.json | 1 + ui-ngx/src/assets/locale/locale.constant-el_GR.json | 1 + ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + ui-ngx/src/assets/locale/locale.constant-es_ES.json | 1 + ui-ngx/src/assets/locale/locale.constant-fa_IR.json | 1 + ui-ngx/src/assets/locale/locale.constant-fr_FR.json | 1 + ui-ngx/src/assets/locale/locale.constant-it_IT.json | 1 + ui-ngx/src/assets/locale/locale.constant-ja_JP.json | 1 + ui-ngx/src/assets/locale/locale.constant-ka_GE.json | 1 + ui-ngx/src/assets/locale/locale.constant-ko_KR.json | 1 + ui-ngx/src/assets/locale/locale.constant-lv_LV.json | 1 + ui-ngx/src/assets/locale/locale.constant-pt_BR.json | 1 + ui-ngx/src/assets/locale/locale.constant-ro_RO.json | 1 + ui-ngx/src/assets/locale/locale.constant-sl_SI.json | 1 + ui-ngx/src/assets/locale/locale.constant-tr_TR.json | 1 + ui-ngx/src/assets/locale/locale.constant-uk_UA.json | 1 + ui-ngx/src/assets/locale/locale.constant-zh_CN.json | 1 + ui-ngx/src/assets/locale/locale.constant-zh_TW.json | 1 + 22 files changed, 27 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index 6937fa6c84..2445ee9bb6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -462,7 +462,9 @@ public class TelemetryController extends BaseController { notes = "Delete time-series for selected entity based on entity id, entity type and keys." + " Use 'deleteAllDataForKeys' to delete all time-series data." + " Use 'startTs' and 'endTs' to specify time-range instead. " + - " Use 'rewriteLatestIfDeleted' to rewrite latest value (stored in separate table for performance) after deletion of the time range. " + + " Use 'deleteLatest' to delete latest value (stored in separate table for performance) if the value's timestamp matches the time-range. " + + " Use 'rewriteLatestIfDeleted' to rewrite latest value (stored in separate table for performance) if the value's timestamp matches the time-range and 'deleteLatest' param is true." + + " The replacement value will be fetched from the 'time-series' table, and its timestamp will be the most recent one before the defined time-range. " + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @ApiResponses(value = { @@ -486,10 +488,10 @@ public class TelemetryController extends BaseController { @RequestParam(name = "startTs", required = false) Long startTs, @ApiParam(value = "A long value representing the end timestamp of removal time range in milliseconds.") @RequestParam(name = "endTs", required = false) Long endTs, - @ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.") - @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted, @ApiParam(value = "If the parameter is set to true, the latest telemetry can be removed, otherwise, in case that parameter is set to false the latest value will not removed.") - @RequestParam(name = "deleteLatest", required = false, defaultValue = "true") boolean deleteLatest) throws ThingsboardException { + @RequestParam(name = "deleteLatest", required = false, defaultValue = "true") boolean deleteLatest, + @ApiParam(value = "If the parameter is set to true, the latest telemetry will be rewritten in case that current latest value was removed, otherwise, in case that parameter is set to false the new latest value will not set.") + @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted, deleteLatest); } 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 103d55a79c..34735dc1c5 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -633,6 +633,7 @@ "latest-telemetry": "Última telemetria", "attributes-scope": "Abast dels atributs del dispositiu", "scope-telemetry": "Telemetria", + "scope-latest-telemetry": "Última telemetria", "scope-client": "Atributs del Client", "scope-server": "Atributs del Servidor", "scope-shared": "Atributs Compartits", 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 2a79340240..25325acab7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -446,6 +446,7 @@ "latest-telemetry": "Poslední telemetrie", "attributes-scope": "Rozsah atributů entity", "scope-telemetry": "Telemetrie", + "scope-latest-telemetry": "Poslední telemetrie", "scope-client": "Atributy klienta", "scope-server": "Atributy serveru", "scope-shared": "Sdílené atributy", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 7389ef448d..1c26dd45a7 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -454,6 +454,7 @@ "latest-telemetry": "Seneste telemetri", "attributes-scope": "Omfang af entitetsattributter", "scope-telemetry": "Telemetri", + "scope-latest-telemetry": "Seneste telemetri", "scope-client": "Klientattributter", "scope-server": "Serverattributter", "scope-shared": "Delte attributter", 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 c27d63f4fb..d7b50d51c3 100644 --- a/ui-ngx/src/assets/locale/locale.constant-de_DE.json +++ b/ui-ngx/src/assets/locale/locale.constant-de_DE.json @@ -325,6 +325,7 @@ "latest-telemetry": "Neueste Telemetrie", "attributes-scope": "Entitätseigenschaftsbereich", "scope-telemetry": "Telemetrie", + "scope-latest-telemetry": "Neueste Telemetrie", "scope-client": "Client Eigenschaften", "scope-server": "Server Eigenschaften", "scope-shared": "Gemeinsame Eigenschaften", diff --git a/ui-ngx/src/assets/locale/locale.constant-el_GR.json b/ui-ngx/src/assets/locale/locale.constant-el_GR.json index 36e8e4e000..9c5ac0db54 100644 --- a/ui-ngx/src/assets/locale/locale.constant-el_GR.json +++ b/ui-ngx/src/assets/locale/locale.constant-el_GR.json @@ -292,6 +292,7 @@ "latest-telemetry": "Τελευταία τηλεμετρία", "attributes-scope": "Πεδίο εφαρμογής Χαρακτηριστικών Οντότητας", "scope-telemetry": "Τηλεμετρία", + "scope-latest-telemetry": "Τελευταία τηλεμετρία", "scope-client": "Χαρακτηριστικά Client", "scope-server": "Χαρακτηριστικά Server", "scope-shared": "Κοινόχρηστα Χαρακτηριστικά", 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 30c05e2edb..76484651b0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -700,6 +700,7 @@ "no-latest-telemetry": "No latest telemetry", "attributes-scope": "Entity attributes scope", "scope-telemetry": "Telemetry", + "scope-latest-telemetry": "Latest telemetry", "scope-client": "Client attributes", "scope-server": "Server attributes", "scope-shared": "Shared attributes", 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 ec4f93823b..cbbaf4b5a1 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -668,6 +668,7 @@ "latest-telemetry": "Última telemetría", "attributes-scope": "Alcance de los atributos del dispositivo", "scope-telemetry": "Telemetría", + "scope-latest-telemetry": "Última telemetría", "scope-client": "Atributos de Cliente", "scope-server": "Atributos de Servidor", "scope-shared": "Atributos Compartidos", diff --git a/ui-ngx/src/assets/locale/locale.constant-fa_IR.json b/ui-ngx/src/assets/locale/locale.constant-fa_IR.json index da841a6e53..6ab40820ec 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fa_IR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fa_IR.json @@ -255,6 +255,7 @@ "latest-telemetry": "آخرين سنجش", "attributes-scope": "حوزه ويژگي هاي موجودي", "scope-telemetry": "تله متری", + "scope-latest-telemetry": "آخرين سنجش", "scope-client": "ويژگي هاي مشتري", "scope-server": "ويژگي هاي سِروِر", "scope-shared": "ويژگي هاي مشترک", 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 c021784db7..3db8795df6 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -460,6 +460,7 @@ "prev-widget": "Widget précédent", "scope-client": "Attributs du client", "scope-telemetry": "Télémétrie", + "scope-latest-telemetry": "Dernière télémétrie", "scope-server": "Attributs du serveur", "scope-shared": "Attributs partagés", "selected-attributes": "{count, plural, =1 {1 attribut} other {# attributs} } sélectionnés", diff --git a/ui-ngx/src/assets/locale/locale.constant-it_IT.json b/ui-ngx/src/assets/locale/locale.constant-it_IT.json index 2c093e76a9..61f6554049 100644 --- a/ui-ngx/src/assets/locale/locale.constant-it_IT.json +++ b/ui-ngx/src/assets/locale/locale.constant-it_IT.json @@ -277,6 +277,7 @@ "latest-telemetry": "Ultima telemetria", "attributes-scope": "Visibilità attributi entità", "scope-telemetry": "Telemetria", + "scope-latest-telemetry": "Ultima telemetria", "scope-client": "Attributi client", "scope-server": "Attributi server", "scope-shared": "Attributi condivisi", diff --git a/ui-ngx/src/assets/locale/locale.constant-ja_JP.json b/ui-ngx/src/assets/locale/locale.constant-ja_JP.json index 23145c1f89..56130aabc3 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ja_JP.json +++ b/ui-ngx/src/assets/locale/locale.constant-ja_JP.json @@ -245,6 +245,7 @@ "latest-telemetry": "最新テレメトリ", "attributes-scope": "エンティティ属性のスコープ", "scope-telemetry": "テレメトリー", + "scope-latest-telemetry": "最新テレメトリ", "scope-client": "クライアントの属性", "scope-server": "サーバーの属性", "scope-shared": "共有属性", diff --git a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json index 89d25703e3..55b6e85f66 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json +++ b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json @@ -291,6 +291,7 @@ "latest-telemetry": "უახლესი ტელემეტრია", "attributes-scope": "ობიექტის ატრიბუტების ფარგლები", "scope-telemetry": "ტელემეტრია", + "scope-latest-telemetry": "უახლესი ტელემეტრია", "scope-client": "კლიენტის ატრიბუტები", "scope-server": "სერვერის ატრიბუტები", "scope-shared": "ატრიბუტების გაზიარება", diff --git a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json index c1be51d1db..ae53707a52 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -409,6 +409,7 @@ "latest-telemetry": "최근 데이터", "attributes-scope": "장치 속성 범위", "scope-telemetry": "원격 측정", + "scope-latest-telemetry": "최근 데이터", "scope-client": "클라이언트 속성", "scope-server": "서버 속성", "scope-shared": "공유 속성", diff --git a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json index f4f5befc14..00e6be4714 100644 --- a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json +++ b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json @@ -257,6 +257,7 @@ "latest-telemetry": "Jaunākā telemetrija", "attributes-scope": "Vienības atribūtu darbības joma", "scope-telemetry": "Telemetrija", + "scope-latest-telemetry": "Jaunākā telemetrija", "scope-client": "Klientu atribūti", "scope-server": "Servera atribūti", "scope-shared": "Dalītie atribūti", diff --git a/ui-ngx/src/assets/locale/locale.constant-pt_BR.json b/ui-ngx/src/assets/locale/locale.constant-pt_BR.json index 28c7082df9..12ad7743c4 100644 --- a/ui-ngx/src/assets/locale/locale.constant-pt_BR.json +++ b/ui-ngx/src/assets/locale/locale.constant-pt_BR.json @@ -310,6 +310,7 @@ "latest-telemetry": "Última telemetria", "attributes-scope": "Escopo de atributos de entidade", "scope-telemetry": "Telemetria", + "scope-latest-telemetry": "Última telemetria", "scope-client": "Atributos do cliente", "scope-server": "Atributos do servidor", "scope-shared": "Atributos compartilhados", diff --git a/ui-ngx/src/assets/locale/locale.constant-ro_RO.json b/ui-ngx/src/assets/locale/locale.constant-ro_RO.json index da0012e6f6..4b565d8311 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ro_RO.json +++ b/ui-ngx/src/assets/locale/locale.constant-ro_RO.json @@ -286,6 +286,7 @@ "latest-telemetry": "Ultimele Date Telemetrice", "attributes-scope": "Scop Atribute Entitate", "scope-telemetry": "Telemetrie", + "scope-latest-telemetry": "Ultimele Date Telemetrice", "scope-client": "Atribute Client", "scope-server": "Atribute Server", "scope-shared": "Atribute Partajate", diff --git a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json index 7875163b60..0515b5890e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -409,6 +409,7 @@ "latest-telemetry": "Najnovejša telemetrija", "attributes-scope": "Obseg atributov entitete", "scope-telemetry": "Telemetrija", + "scope-latest-telemetry": "Najnovejša telemetrija", "scope-client": "Atributi odjemalca", "scope-server": "Atributi strežnika", "scope-shared": "Skupni atributi", 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 c56be48c74..8590dd2768 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -446,6 +446,7 @@ "latest-telemetry": "Son telemetri", "attributes-scope": "Varlık öznitelik kapsamı", "scope-telemetry": "telemetri", + "scope-latest-telemetry": "Son telemetri", "scope-client": "İstemci öznitelikler", "scope-server": "Sunucu öznitelikler", "scope-shared": "Paylaşılan öznitelikler", 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 bd608cd709..c7afaad234 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -343,6 +343,7 @@ "latest-telemetry": "Остання телеметрія", "attributes-scope": "Область видимості атрибутів", "scope-telemetry": "Телеметрія", + "scope-latest-telemetry": "Остання телеметрія", "scope-client": "Клієнтські атрибути", "scope-server": "Серверні атрибути", "scope-shared": "Спільні атрибути", 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 2fd73b32bd..6e5bf9a6b6 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -591,6 +591,7 @@ "latest-telemetry": "最新遥测数据", "attributes-scope": "设备属性范围", "scope-telemetry": "遥测", + "scope-latest-telemetry": "最新遥测数据", "scope-client": "客户端属性", "scope-server": "服务端属性", "scope-shared": "共享属性", 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 526597ad70..2b98451f20 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -520,6 +520,7 @@ "latest-telemetry": "最新遙測", "attributes-scope": "設備屬性範圍", "scope-telemetry": "遙測", + "scope-latest-telemetry": "最新遙測", "scope-client": "客戶端屬性", "scope-server": "服務端屬性", "scope-shared": "共享屬性", From ee5bc97330b92c5ef70f35855ad6e968418040ca Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 9 Aug 2023 13:07:16 +0300 Subject: [PATCH 397/421] UI: Minor improvements --- .../data/json/system/widget_bundles/cards.json | 2 +- .../lib/cards/value-card-widget.component.ts | 2 +- .../value-card-widget-settings.component.html | 2 +- .../common/css-unit-select.component.ts | 4 ++-- .../common/date-format-select.component.ts | 4 ++-- .../home/models/dashboard-component.models.ts | 2 +- .../home/models/widget-component.models.ts | 18 +++++++++--------- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index dd25e00442..858d816338 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -265,7 +265,7 @@ "settingsDirective": "tb-value-card-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-value-card-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"constant\",\"color\":\"#5469FF\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"constant\",\"color\":\"#5469FF\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" } } ] diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts index 5505a1e8dd..48d432bcb7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts @@ -107,7 +107,7 @@ export class ValueCardWidgetComponent implements OnInit { this.showLabel = this.settings.showLabel; const label = getLabel(this.ctx.datasources); - this.label$ = this.ctx.registerLabelPattern('valueCardLabel', label); + this.label$ = this.ctx.registerLabelPattern(label, this.label$); this.labelStyle = textStyle(this.settings.labelFont, '0.25px'); this.labelColor = ColorProcessor.fromSettings(this.settings.labelColor); this.valueStyle = textStyle(this.settings.valueFont, '0.13px'); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html index 73ee11f393..f0fd9cdb16 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-card-widget-settings.component.html @@ -44,7 +44,7 @@ {{ 'widgets.value-card.icon' | translate }} -
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts index 3d2658dae1..61a6bc4865 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/css-unit-select.component.ts @@ -67,9 +67,9 @@ export class CssUnitSelectComponent implements OnInit, ControlValueAccessor { setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (this.disabled) { - this.cssUnitFormControl.disable(); + this.cssUnitFormControl.disable({emitEvent: false}); } else { - this.cssUnitFormControl.enable(); + this.cssUnitFormControl.enable({emitEvent: false}); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts index 6393a92054..e4f0b47946 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-select.component.ts @@ -90,9 +90,9 @@ export class DateFormatSelectComponent implements OnInit, ControlValueAccessor { setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (this.disabled) { - this.dateFormatFormControl.disable(); + this.dateFormatFormControl.disable({emitEvent: false}); } else { - this.dateFormatFormControl.enable(); + this.dateFormatFormControl.enable({emitEvent: false}); } } diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 364973d013..8104e80e36 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -432,7 +432,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { const title = isDefined(this.widgetContext.widgetTitle) && this.widgetContext.widgetTitle.length ? this.widgetContext.widgetTitle : this.widget.config.title; - this.title$ = this.widgetContext.registerLabelPattern('widgetTitle', title); + this.title$ = this.widgetContext.registerLabelPattern(title, this.title$); this.titleTooltip = isDefined(this.widgetContext.widgetTitleTooltip) && this.widgetContext.widgetTitleTooltip.length ? this.widgetContext.widgetTitleTooltip : this.widget.config.titleTooltip; this.titleTooltip = this.dashboard.utils.customTranslation(this.titleTooltip, this.titleTooltip); diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index 02086e57ef..11b631dc52 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -202,7 +202,7 @@ export class WidgetContext { subscriptions: {[id: string]: IWidgetSubscription} = {}; defaultSubscription: IWidgetSubscription = null; - labelPatterns: {[id: string]: LabelVariablePattern} = {}; + labelPatterns = new Map, LabelVariablePattern>(); timewindowFunctions: TimewindowFunctions = { onUpdateTimewindow: (startTimeMs, endTimeMs, interval) => { @@ -316,20 +316,20 @@ export class WidgetContext { }); } - registerLabelPattern(id: string, label: string): Observable { - let labelPattern = this.labelPatterns[id]; + registerLabelPattern(label: string, label$: Observable): Observable { + let labelPattern = label$ ? this.labelPatterns.get(label$) : null; if (labelPattern) { labelPattern.setupPattern(label); } else { labelPattern = new LabelVariablePattern(label, this); - this.labelPatterns[id] = labelPattern; + this.labelPatterns.set(labelPattern.label$, labelPattern); } return labelPattern.label$; } updateLabelPatterns() { - for (const key of Object.keys(this.labelPatterns)) { - this.labelPatterns[key].update(); + for (const labelPattern of this.labelPatterns.values()) { + labelPattern.update(); } } @@ -428,10 +428,10 @@ export class WidgetContext { } destroy() { - for (const key of Object.keys(this.labelPatterns)) { - this.labelPatterns[key].destroy(); + for (const labelPattern of this.labelPatterns.values()) { + labelPattern.destroy(); } - this.labelPatterns = {}; + this.labelPatterns.clear(); this.destroyed = true; } From 2ed3d479520c8303f1a64f8c4fcae1e1b081f6e5 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 9 Aug 2023 14:55:40 +0300 Subject: [PATCH 398/421] UI: Fix widget labels pattern processing. --- ui-ngx/src/app/core/api/widget-api.models.ts | 2 ++ ui-ngx/src/app/core/api/widget-subscription.ts | 10 ++++++++++ .../app/modules/home/models/widget-component.models.ts | 5 +++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/core/api/widget-api.models.ts b/ui-ngx/src/app/core/api/widget-api.models.ts index 115bf6e222..d0de3481ed 100644 --- a/ui-ngx/src/app/core/api/widget-api.models.ts +++ b/ui-ngx/src/app/core/api/widget-api.models.ts @@ -284,6 +284,8 @@ export interface IWidgetSubscription { legendData: LegendData; + readonly firstDatasource?: Datasource; + datasourcePages?: PageData[]; dataPages?: PageData>[]; datasources?: Array; diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index 440e61148e..f9a79d8f76 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -160,6 +160,16 @@ export class WidgetSubscription implements IWidgetSubscription { warnOnPageDataOverflow: boolean; ignoreDataUpdateOnIntervalTick: boolean; + get firstDatasource(): Datasource { + if (this.type === widgetType.alarm) { + return this.alarmSource; + } else if (this.datasources?.length) { + return this.datasources[0]; + } else { + return null; + } + } + datasourcePages: PageData[]; dataPages: PageData>[]; entityDataListeners: Array; diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index 11b631dc52..12d3312dbb 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -477,8 +477,9 @@ export class LabelVariablePattern { update() { let label = this.pattern; - if (this.hasVariables && this.ctx.defaultSubscription?.datasources?.length) { - label = createLabelFromDatasource(this.ctx.defaultSubscription.datasources[0], label); + const datasource = this.ctx.defaultSubscription?.firstDatasource; + if (this.hasVariables && datasource) { + label = createLabelFromDatasource(datasource, label); } if (this.labelSubject.value !== label) { this.labelSubject.next(label); From 0612da8ca2623603dae499c3cd75616699f73a33 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 9 Aug 2023 16:07:30 +0300 Subject: [PATCH 399/421] UI: Fixed layout for clear alarm rule --- .../profile/alarm/device-profile-alarm.component.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.scss b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.scss index ad664e3156..1b796ccbda 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.scss +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.scss @@ -16,7 +16,8 @@ :host { display: block; .clear-alarm-rule { - max-width: 100%; + min-width: 0; + margin-right: 8px; border: 2px groove rgba(0, 0, 0, .45); border-radius: 4px; padding: 8px; From 141a7ff0e6be9bb132e788c870b6689f84fb8b5b Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 9 Aug 2023 21:21:15 +0200 Subject: [PATCH 400/421] changed recalculate_delay --- application/src/main/resources/thingsboard.yml | 5 ++++- .../server/queue/discovery/ZkDiscoveryService.java | 2 +- msa/vc-executor/src/main/resources/tb-vc-executor.yml | 2 +- transport/coap/src/main/resources/tb-coap-transport.yml | 2 +- transport/http/src/main/resources/tb-http-transport.yml | 2 +- transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 2 +- transport/mqtt/src/main/resources/tb-mqtt-transport.yml | 2 +- transport/snmp/src/main/resources/tb-snmp-transport.yml | 2 +- 8 files changed, 11 insertions(+), 8 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 1f16fbc414..5b76175fcd 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -96,7 +96,10 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" + # The recalculate_delay property recommended in a microservices architecture setup for rule-engine services. + # This property provides a pause to ensure that when a rule-engine service is restarted, other nodes don't immediately attempt to recalculate their partitions. + # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability. + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" cluster: stats: diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java index 44999d016a..e99817de17 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/ZkDiscoveryService.java @@ -69,7 +69,7 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi private Integer zkSessionTimeout; @Value("${zk.zk_dir}") private String zkDir; - @Value("${zk.recalculate_delay:60000}") + @Value("${zk.recalculate_delay:0}") private Long recalculateDelay; protected final ConcurrentHashMap> delayedTasks; diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 66c6b4d3da..9e57a35e20 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" queue: type: "${TB_QUEUE_TYPE:kafka}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index f4b5e0bc94..a545759f38 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index f92da86b99..1f042fb131 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -68,7 +68,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 05388473f0..ffe815d441 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index e131788929..f7d0209804 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" cache: type: "${CACHE_TYPE:redis}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index a7928eb49f..3ed46dde78 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -41,7 +41,7 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:60000}" + recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" cache: type: "${CACHE_TYPE:redis}" From 3d5cfa0c2ef8a8eee872288765f54bcd69e16c53 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 10 Aug 2023 15:46:01 +0300 Subject: [PATCH 401/421] added internal type to TbMsg to replace if-return blocks with switch-case --- .../server/common/data/msg/TbMsgType.java | 27 ++++++--- .../server/common/data/msg/TbMsgTypeTest.java | 24 ++++++-- .../thingsboard/server/common/msg/TbMsg.java | 59 ++++++++++++++++--- .../engine/filter/TbMsgTypeSwitchNode.java | 2 +- .../filter/TbMsgTypeSwitchNodeTest.java | 3 +- 5 files changed, 91 insertions(+), 24 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java index 206b203682..bd351ffecd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java @@ -76,7 +76,10 @@ public enum TbMsgType { DEVICE_UPDATE_SELF_MSG(null, true), DEDUPLICATION_TIMEOUT_SELF_MSG(null, true), DELAY_TIMEOUT_SELF_MSG(null, true), - MSG_COUNT_SELF_MSG(null, true); + MSG_COUNT_SELF_MSG(null, true), + + // Custom or N/A type: + CUSTOM_OR_NA_TYPE(null, false, true); public static final List NODE_CONNECTIONS = EnumSet.allOf(TbMsgType.class).stream() .filter(tbMsgType -> !tbMsgType.isTellSelfOnly()) @@ -90,26 +93,32 @@ public enum TbMsgType { @Getter private final boolean tellSelfOnly; + @Getter + private final boolean customType; + + TbMsgType(String ruleNodeConnection, boolean tellSelfOnly, boolean customType) { + this.ruleNodeConnection = ruleNodeConnection; + this.tellSelfOnly = tellSelfOnly; + this.customType = customType; + } + TbMsgType(String ruleNodeConnection, boolean tellSelfOnly) { this.ruleNodeConnection = ruleNodeConnection; this.tellSelfOnly = tellSelfOnly; + this.customType = false; } TbMsgType(String ruleNodeConnection) { this.ruleNodeConnection = ruleNodeConnection; this.tellSelfOnly = false; + this.customType = false; } - public static String getRuleNodeConnectionOrElseOther(String msgType) { - if (msgType == null) { + public static String getRuleNodeConnectionOrElseOther(TbMsgType msgType) { + if (msgType == null || msgType.isCustomType() || msgType.isTellSelfOnly()) { return TbNodeConnectionType.OTHER; - } else { - return Arrays.stream(TbMsgType.values()) - .filter(type -> type.name().equals(msgType)) - .findFirst() - .map(TbMsgType::getRuleNodeConnection) - .orElse(TbNodeConnectionType.OTHER); } + return Objects.requireNonNullElse(msgType.getRuleNodeConnection(), TbNodeConnectionType.OTHER); } } diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java index a37eb31d72..ff41505266 100644 --- a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java +++ b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java @@ -22,6 +22,7 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM; import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE; +import static org.thingsboard.server.common.data.msg.TbMsgType.CUSTOM_OR_NA_TYPE; import static org.thingsboard.server.common.data.msg.TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG; import static org.thingsboard.server.common.data.msg.TbMsgType.DELAY_TIMEOUT_SELF_MSG; import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED_TO_EDGE; @@ -51,11 +52,12 @@ class TbMsgTypeTest { DEVICE_UPDATE_SELF_MSG, DEDUPLICATION_TIMEOUT_SELF_MSG, DELAY_TIMEOUT_SELF_MSG, - MSG_COUNT_SELF_MSG + MSG_COUNT_SELF_MSG, + CUSTOM_OR_NA_TYPE ); // backward-compatibility tests - + @Test void getRuleNodeConnectionsTest() { var tbMsgTypes = TbMsgType.values(); @@ -75,13 +77,25 @@ class TbMsgTypeTest { var tbMsgTypes = TbMsgType.values(); for (var type : tbMsgTypes) { if (typesWithNullRuleNodeConnection.contains(type)) { - assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type.name())) + assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type)) .isEqualTo(TbNodeConnectionType.OTHER); } else { - assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type.name())).isNotNull() + assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type)).isNotNull() .isNotEqualTo(TbNodeConnectionType.OTHER); } } } - + + @Test + void getCustomTypeTest() { + var tbMsgTypes = TbMsgType.values(); + for (var type : tbMsgTypes) { + if (type.equals(CUSTOM_OR_NA_TYPE)) { + assertThat(type.isCustomType()).isTrue(); + continue; + } + assertThat(type.isCustomType()).isFalse(); + } + } + } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index a987a4a253..b4f6ccd584 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -52,6 +52,7 @@ public final class TbMsg implements Serializable { private final UUID id; private final long ts; private final String type; + private final TbMsgType internalType; private final EntityId originator; private final CustomerId customerId; private final TbMsgMetaData metaData; @@ -117,7 +118,7 @@ public final class TbMsg implements Serializable { } public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId, + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); } @@ -126,7 +127,7 @@ public final class TbMsg implements Serializable { } public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); } @@ -205,12 +206,12 @@ public final class TbMsg implements Serializable { } public static TbMsg newMsg(String queueName, TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId, + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); } public static TbMsg newMsg(TbMsgType type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, customerId, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY); } @@ -255,17 +256,17 @@ public final class TbMsg implements Serializable { } public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, null, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); } public static TbMsg newMsg(TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type.name(), originator, null, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback); } public static TbMsg transformMsg(TbMsg tbMsg, TbMsgType type, EntityId originator, TbMsgMetaData metaData, String data) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type.name(), originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback); } @@ -315,6 +316,36 @@ public final class TbMsg implements Serializable { tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, tbMsg.ctx.copy(), TbMsgCallback.EMPTY); } + private TbMsg(String queueName, UUID id, long ts, TbMsgType internalType, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, + RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgProcessingCtx ctx, TbMsgCallback callback) { + this.id = id; + this.queueName = queueName; + if (ts > 0) { + this.ts = ts; + } else { + this.ts = System.currentTimeMillis(); + } + this.internalType = internalType; + this.type = internalType.name(); + this.originator = originator; + if (customerId == null || customerId.isNullUid()) { + if (originator != null && originator.getEntityType() == EntityType.CUSTOMER) { + this.customerId = (CustomerId) originator; + } else { + this.customerId = null; + } + } else { + this.customerId = customerId; + } + this.metaData = metaData; + this.dataType = dataType; + this.data = data; + this.ruleChainId = ruleChainId; + this.ruleNodeId = ruleNodeId; + this.ctx = ctx != null ? ctx : new TbMsgProcessingCtx(); + this.callback = Objects.requireNonNullElse(callback, TbMsgCallback.EMPTY); + } + private TbMsg(String queueName, UUID id, long ts, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgProcessingCtx ctx, TbMsgCallback callback) { this.id = id; @@ -325,6 +356,7 @@ public final class TbMsg implements Serializable { this.ts = System.currentTimeMillis(); } this.type = type; + this.internalType = getInternalType(); this.originator = originator; if (customerId == null || customerId.isNullUid()) { if (originator != null && originator.getEntityType() == EntityType.CUSTOMER) { @@ -468,8 +500,19 @@ public final class TbMsg implements Serializable { return ts; } + public TbMsgType getInternalType() { + if (internalType != null) { + return internalType; + } + try { + return TbMsgType.valueOf(type); + } catch (IllegalArgumentException e) { + return TbMsgType.CUSTOM_OR_NA_TYPE; + } + } + public boolean isTypeOf(TbMsgType tbMsgType) { - return tbMsgType != null && tbMsgType.name().equals(this.type); + return tbMsgType != null && tbMsgType.equals(getInternalType()); } public boolean isTypeOneOf(TbMsgType... types) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java index 2121e0c5fa..068d342ea7 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java @@ -50,7 +50,7 @@ public class TbMsgTypeSwitchNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - ctx.tellNext(msg, TbMsgType.getRuleNodeConnectionOrElseOther(msg.getType())); + ctx.tellNext(msg, TbMsgType.getRuleNodeConnectionOrElseOther(msg.getInternalType())); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java index c4fc8cd76d..7861b2f489 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java @@ -81,9 +81,10 @@ class TbMsgTypeSwitchNodeTest { var msg = resultMsgs.get(i); assertThat(msg).isNotNull(); assertThat(msg.getType()).isNotNull(); + assertThat(msg.getType()).isEqualTo(msg.getInternalType().name()); assertThat(msg).isSameAs(tbMsgList.get(i)); assertThat(resultNodeConnections.get(i)) - .isEqualTo(TbMsgType.getRuleNodeConnectionOrElseOther(msg.getType())); + .isEqualTo(TbMsgType.getRuleNodeConnectionOrElseOther(msg.getInternalType())); } } From cba324f5bae50233c1110b6fd4696d34f98f53a7 Mon Sep 17 00:00:00 2001 From: kalytka Date: Thu, 10 Aug 2023 16:41:15 +0300 Subject: [PATCH 402/421] UI: Refactoring component for used filter and enrichment rule nodes --- .../relation/relation-filters.component.html | 70 +++++++++---------- .../relation/relation-filters.component.scss | 44 +++--------- .../basic/common/data-key-row.component.html | 2 +- .../common/data-keys-panel.component.html | 4 +- .../add-rule-node-dialog.component.scss | 4 ++ .../rule-node-details.component.scss | 5 +- .../entity/entity-subtype-list.component.html | 13 ++-- .../entity/entity-subtype-list.component.ts | 48 ++++++++----- .../entity/entity-type-list.component.html | 9 ++- .../entity/entity-type-list.component.ts | 57 ++++++++++----- .../components/help-popup.component.html | 10 +-- .../components/help-popup.component.scss | 18 +++++ .../shared/components/help-popup.component.ts | 6 ++ .../relation-type-autocomplete.component.html | 3 +- .../relation-type-autocomplete.component.ts | 24 ++++--- .../string-items-list.component.html | 10 ++- .../assets/locale/locale.constant-en_US.json | 1 + ui-ngx/src/form.scss | 14 +++- ui-ngx/src/styles.scss | 6 ++ 19 files changed, 206 insertions(+), 142 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html index b052a1816c..1f4d6f9377 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html @@ -15,49 +15,47 @@ limitations under the License. --> -
-
-
-
+
+
+
{{ 'relation.type' | translate }}
+
{{ 'entity.entity-types' | translate }}
+
+
+
+
-
-
- - - - -
- +
+
+
+ relation.any-relation
-
- relation.any-relation +
+
-
diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss index a2d4232f24..648076be4c 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.scss @@ -14,43 +14,15 @@ * limitations under the License. */ :host { - .tb-relation-filters { - max-width: calc(100vw - 48px); - margin-top: 2px; - overflow: hidden; - - .container{ - width: 100%; - } - - .map-label { - font-weight: 400; - font-size: 12px; - } - - .body { - max-height: 363px; - overflow: auto; - - .row { - padding-top: 5px; - - .input-block { - border: 1px solid #E0E0E0; - width: 100%; - border-radius: 6px; - padding: 24px; - align-items: center; - } - } - } + .flex-50 { + flex: 1 1 50%; + } - .any-filter{ - margin: 10px 0 20px; - } + .actions-header { + width: 40px + } - .add-button { - margin: 5px 0px 15px; - } + .entity-type-list { + display: flex; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html index 63f936195a..05275e0a70 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
{{ 'datakey.timeseries' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html index 0b3ba50927..4c2c9a834a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html @@ -18,7 +18,7 @@
{{ panelTitle }}
-
+
datakey.source
datakey.key
datakey.label
@@ -32,7 +32,7 @@ [cdkDropListDisabled]="!dragEnabled" (cdkDropListDropped)="keyDrop($event)">
- + {{ label }} - +
+ +
{{ subtypeListEmptyText | translate }} diff --git a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts index 1442b44cfd..a10bf7e3e2 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-subtype-list.component.ts @@ -15,7 +15,7 @@ /// import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { Observable, Subscription, throwError } from 'rxjs'; import { map, mergeMap, publishReplay, refCount, share } from 'rxjs/operators'; import { Store } from '@ngrx/store'; @@ -23,14 +23,15 @@ import { AppState } from '@app/core/core.state'; import { TranslateService } from '@ngx-translate/core'; import { EntitySubtype, EntityType } from '@shared/models/entity-type.models'; import { MatAutocomplete, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; -import { MatChipInputEvent, MatChipGrid } from '@angular/material/chips'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { MatChipGrid, MatChipInputEvent } from '@angular/material/chips'; import { AssetService } from '@core/http/asset.service'; import { DeviceService } from '@core/http/device.service'; import { EdgeService } from '@core/http/edge.service'; import { EntityViewService } from '@core/http/entity-view.service'; import { BroadcastService } from '@core/services/broadcast.service'; import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { FloatLabelType } from '@angular/material/form-field'; @Component({ selector: 'tb-entity-subtype-list', @@ -46,32 +47,43 @@ import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes'; }) export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, AfterViewInit, OnDestroy { - entitySubtypeListFormGroup: UntypedFormGroup; + entitySubtypeListFormGroup: FormGroup; modelValue: Array | null; private requiredValue: boolean; + get required(): boolean { return this.requiredValue; } - @Input() label: string; - @Input() + @coerceBoolean() set required(value: boolean) { - const newVal = coerceBooleanProperty(value); - if (this.requiredValue !== newVal) { - this.requiredValue = newVal; + if (this.requiredValue !== value) { + this.requiredValue = value; this.updateValidators(); } } + @Input() + floatLabel: FloatLabelType = 'auto'; + + @Input() + label: string; + @Input() disabled: boolean; @Input() entityType: EntityType; + @Input() + emptyInputPlaceholder: string; + + @Input() + filledInputPlaceholder: string; + @ViewChild('entitySubtypeInput') entitySubtypeInput: ElementRef; @ViewChild('entitySubtypeAutocomplete') entitySubtypeAutocomplete: MatAutocomplete; @ViewChild('chipList', {static: true}) chipList: MatChipGrid; @@ -102,13 +114,14 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, private deviceService: DeviceService, private edgeService: EdgeService, private entityViewService: EntityViewService, - private fb: UntypedFormBuilder) { + private fb: FormBuilder) { this.entitySubtypeListFormGroup = this.fb.group({ entitySubtypeList: [this.entitySubtypeList, this.required ? [Validators.required] : []], entitySubtype: [null] }); } + updateValidators() { this.entitySubtypeListFormGroup.get('entitySubtypeList').setValidators(this.required ? [Validators.required] : []); this.entitySubtypeListFormGroup.get('entitySubtypeList').updateValueAndValidity(); @@ -122,7 +135,6 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, } ngOnInit() { - switch (this.entityType) { case EntityType.ASSET: this.placeholder = this.required ? this.translate.instant('asset.enter-asset-type') @@ -166,6 +178,13 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, break; } + if (this.emptyInputPlaceholder) { + this.placeholder = this.emptyInputPlaceholder; + } + if (this.filledInputPlaceholder) { + this.secondaryPlaceholder = this.filledInputPlaceholder; + } + this.filteredEntitySubtypeList = this.entitySubtypeListFormGroup.get('entitySubtype').valueChanges .pipe( map(value => value ? value : ''), @@ -225,13 +244,6 @@ export class EntitySubTypeListComponent implements ControlValueAccessor, OnInit, } this.clear(''); } - - clearChipGrid() { - this.entitySubtypeList = []; - this.modelValue = null; - this.entitySubtypeListFormGroup.get('entitySubtypeList').patchValue([], {emitEvent: true}); - } - remove(entitySubtype: string) { const index = this.entitySubtypeList.indexOf(entitySubtype); if (index >= 0) { diff --git a/ui-ngx/src/app/shared/components/entity/entity-type-list.component.html b/ui-ngx/src/app/shared/components/entity/entity-type-list.component.html index 0503ce836b..e9168d1f29 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-type-list.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-type-list.component.html @@ -15,7 +15,11 @@ limitations under the License. --> - + {{ label }} +
+ +
{{ 'entity.entity-type-list-empty' | translate }} diff --git a/ui-ngx/src/app/shared/components/entity/entity-type-list.component.ts b/ui-ngx/src/app/shared/components/entity/entity-type-list.component.ts index 17f908b2e0..7bb52d0948 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-type-list.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-type-list.component.ts @@ -15,7 +15,7 @@ /// import { AfterViewInit, Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, UntypedFormBuilder, UntypedFormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Observable, of } from 'rxjs'; import { filter, map, mergeMap, share, tap } from 'rxjs/operators'; import { Store } from '@ngrx/store'; @@ -25,9 +25,8 @@ import { AliasEntityType, EntityType, entityTypeTranslations } from '@shared/mod import { EntityService } from '@core/http/entity.service'; import { MatAutocomplete } from '@angular/material/autocomplete'; import { MatChipGrid } from '@angular/material/chips'; -import { coerceBooleanProperty } from '@angular/cdk/coercion'; -import { FloatLabelType, SubscriptSizing } from '@angular/material/form-field'; -import { coerceBoolean } from '@shared/decorators/coercion'; +import { FloatLabelType, MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field'; +import { coerceArray, coerceBoolean } from '@shared/decorators/coercion'; interface EntityTypeInfo { name: string; @@ -48,7 +47,7 @@ interface EntityTypeInfo { }) export class EntityTypeListComponent implements ControlValueAccessor, OnInit, AfterViewInit { - entityTypeListFormGroup: UntypedFormGroup; + entityTypeListFormGroup: FormGroup; modelValue: Array | null; @@ -57,19 +56,28 @@ export class EntityTypeListComponent implements ControlValueAccessor, OnInit, Af return this.requiredValue; } - @Input() label: string; - - @Input() floatLabel: FloatLabelType = 'auto'; - @Input() + @coerceBoolean() set required(value: boolean) { - const newVal = coerceBooleanProperty(value); - if (this.requiredValue !== newVal) { - this.requiredValue = newVal; + if (this.requiredValue !== value) { + this.requiredValue = value; this.updateValidators(); } } + @Input() + @coerceArray() + additionalClasses: Array; + + @Input() + appearance: MatFormFieldAppearance = 'fill'; + + @Input() + label: string; + + @Input() + floatLabel: FloatLabelType = 'auto'; + @Input() disabled: boolean; @@ -79,6 +87,12 @@ export class EntityTypeListComponent implements ControlValueAccessor, OnInit, Af @Input() allowedEntityTypes: Array; + @Input() + emptyInputPlaceholder: string; + + @Input() + filledInputPlaceholder: string; + @Input() @coerceBoolean() ignoreAuthorityFilter: boolean; @@ -103,7 +117,7 @@ export class EntityTypeListComponent implements ControlValueAccessor, OnInit, Af constructor(private store: Store, public translate: TranslateService, private entityService: EntityService, - private fb: UntypedFormBuilder) { + private fb: FormBuilder) { this.entityTypeListFormGroup = this.fb.group({ entityTypeList: [this.entityTypeList, this.required ? [Validators.required] : []], entityType: [null] @@ -123,11 +137,17 @@ export class EntityTypeListComponent implements ControlValueAccessor, OnInit, Af } ngOnInit() { - - this.placeholder = this.required ? this.translate.instant('entity.enter-entity-type') - : this.translate.instant('entity.any-entity'); - this.secondaryPlaceholder = '+' + this.translate.instant('entity.entity-type'); - + if (this.emptyInputPlaceholder) { + this.placeholder = this.emptyInputPlaceholder; + } else { + this.placeholder = this.required ? this.translate.instant('entity.enter-entity-type') : + this.translate.instant('entity.any-entity'); + } + if (this.filledInputPlaceholder) { + this.secondaryPlaceholder = this.filledInputPlaceholder; + } else { + this.secondaryPlaceholder = '+' + this.translate.instant('entity.entity-type'); + } let entityTypes: Array; if (this.ignoreAuthorityFilter && this.allowedEntityTypes && this.allowedEntityTypes.length) { @@ -250,5 +270,4 @@ export class EntityTypeListComponent implements ControlValueAccessor, OnInit, Af this.entityTypeInput.nativeElement.focus(); }, 0); } - } diff --git a/ui-ngx/src/app/shared/components/help-popup.component.html b/ui-ngx/src/app/shared/components/help-popup.component.html index 1a9fe5541a..730d054b8b 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.html +++ b/ui-ngx/src/app/shared/components/help-popup.component.html @@ -30,19 +30,21 @@
-
+
diff --git a/ui-ngx/src/app/shared/components/help-popup.component.scss b/ui-ngx/src/app/shared/components/help-popup.component.scss index 2ec26a3c0f..6be4d9b71c 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.scss +++ b/ui-ngx/src/app/shared/components/help-popup.component.scss @@ -17,6 +17,9 @@ width: initial; display: inline-block; vertical-align: middle; + &.hint-button { + line-height: 1; + } } .tb-help-popup-button { @@ -65,4 +68,19 @@ vertical-align: middle; } } + &.hint-button { + padding: 2px 3px; + line-height: 1; + &.mat-mdc-outlined-button { + padding: 1px 2px; + } + .mdc-button__label > span { + .mat-icon { + margin-right: 0; + } + .mat-mdc-progress-spinner { + margin-right: 0; + } + } + } } diff --git a/ui-ngx/src/app/shared/components/help-popup.component.ts b/ui-ngx/src/app/shared/components/help-popup.component.ts index 08be61f728..64722348a2 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.ts +++ b/ui-ngx/src/app/shared/components/help-popup.component.ts @@ -28,6 +28,7 @@ import { TbPopoverService } from '@shared/components/popover.service'; import { PopoverPlacement } from '@shared/components/popover.models'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { isDefinedAndNotNull } from '@core/utils'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector @@ -62,6 +63,11 @@ export class HelpPopupComponent implements OnChanges, OnDestroy { popoverVisible = false; popoverReady = true; + + @Input() + @coerceBoolean() + hintMode = false; + triggerSafeHtml: SafeHtml = null; textMode = false; diff --git a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html index c057f1df09..99a650098e 100644 --- a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html @@ -15,7 +15,8 @@ limitations under the License. --> - + {{ label }} ; - @Input() floatLabel: FloatLabelType = 'auto'; + @Input() + appearance: MatFormFieldAppearance = 'fill'; @Input() - set required(value: boolean) { - this.requiredValue = coerceBooleanProperty(value); - } + floatLabel: FloatLabelType = 'auto'; + + @Input() + @coerceBoolean() + required: boolean; @Input() disabled: boolean; diff --git a/ui-ngx/src/app/shared/components/string-items-list.component.html b/ui-ngx/src/app/shared/components/string-items-list.component.html index 4677cbc3de..7416e96870 100644 --- a/ui-ngx/src/app/shared/components/string-items-list.component.html +++ b/ui-ngx/src/app/shared/components/string-items-list.component.html @@ -54,7 +54,15 @@ {{ 'common.not-found' | translate }} - {{ hint }} + + {{ hint }} + + + + +
+ +
{{ requiredText }} 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 f90a34fe8e..60213184eb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2031,6 +2031,7 @@ "entity-types": "Entity types", "entity-type-list": "Entity type list", "any-entity": "Any entity", + "add-entity-type": "Add entity type", "enter-entity-type": "Enter entity type", "no-entities-matching": "No entities matching '{{entity}}' were found.", "no-entity-types-matching": "No entity types matching '{{entityType}}' were found.", diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index bef8bf621e..79f141e9d5 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -307,6 +307,10 @@ } } &.tb-chips { + &.flex { + flex: 1; + width: auto; + } .mat-mdc-text-field-wrapper { &.mdc-text-field--outlined, &:not(.mdc-text-field--outlined) { .mat-mdc-form-field-infix { @@ -357,7 +361,7 @@ } .tb-prompt { - height: 38px; + height: 40px; } } @@ -366,11 +370,19 @@ flex-direction: row; gap: 8px; padding-left: 8px; + padding-right: 8px; place-content: center flex-start; align-items: center; + &.no-padding-right { + padding-right: 0; + } @media #{$mat-gt-md} { gap: 12px; padding-left: 12px; + padding-right: 12px; + &.no-padding-right { + padding-right: 0; + } } &-cell { font-weight: 400; diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index ec6060823d..8e6a9dde75 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -855,6 +855,9 @@ mat-label { svg { vertical-align: inherit; } + &.tb-mat-12 { + @include tb-mat-icon-size(12); + } &.tb-mat-16 { @include tb-mat-icon-size(16); } @@ -1208,4 +1211,7 @@ mat-label { color: inherit; } + .cursor-pointer { + cursor: pointer; + } } From b38165e7455e8761f31e1036f73473483c68c055 Mon Sep 17 00:00:00 2001 From: kalytka Date: Thu, 10 Aug 2023 18:20:58 +0300 Subject: [PATCH 403/421] Add translation --- .../home/components/relation/relation-filters.component.html | 2 +- ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html index 1f4d6f9377..57c5ecf621 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html @@ -42,7 +42,7 @@ mat-icon-button (click)="removeFilter($index)" [disabled]="isLoading$ | async" - matTooltip="{{ 'tb.key-val.remove-mapping-entry' | translate }}" + matTooltip="{{ 'relation.remove-filter' | translate }}" matTooltipPosition="above"> delete 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 60213184eb..ecad69fe24 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3326,6 +3326,7 @@ "delete-from-relations-title": "Are you sure you want to delete { count, plural, =1 {1 relation} other {# relations} }?", "delete-from-relations-text": "Be careful, after the confirmation all selected relations will be removed and current entity will be unrelated from the corresponding entities.", "remove-relation-filter": "Remove relation filter", + "remove-filter": "Remove filter", "add-relation-filter": "Add relation filter", "any-relation": "Any relation", "relation-filters": "Relation filters", From 7de5e6b08491feb584386f21d70144c459d27a9d Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 11 Aug 2023 12:49:32 +0300 Subject: [PATCH 404/421] updated default config for math node --- .../rule/engine/math/TbMathNodeConfiguration.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java index 1636898b8c..f4fccd3ae6 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java @@ -32,9 +32,10 @@ public class TbMathNodeConfiguration implements NodeConfiguration Date: Fri, 11 Aug 2023 16:15:34 +0300 Subject: [PATCH 405/421] replace x with t --- .../thingsboard/rule/engine/math/TbMathNodeConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java index f4fccd3ae6..e1a3523cf0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNodeConfiguration.java @@ -33,8 +33,8 @@ public class TbMathNodeConfiguration implements NodeConfiguration Date: Fri, 11 Aug 2023 19:23:51 +0300 Subject: [PATCH 406/421] PROD-2339: fix getFeatureType method to handle RPC server-side response over DTLS --- .../transport/coap/CoapTransportResource.java | 11 +- .../coap/CoapTransportResourceTest.java | 352 ++++++++++++++++++ 2 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index d6958137c7..bd02d9fcc4 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java @@ -30,6 +30,7 @@ import org.thingsboard.server.coapserver.TbCoapDtlsSessionInfo; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.security.DeviceTokenCredentials; import org.thingsboard.server.common.msg.session.FeatureType; @@ -379,12 +380,16 @@ public class CoapTransportResource extends AbstractCoapTransportResource { } } - private Optional getFeatureType(Request request) { + protected Optional getFeatureType(Request request) { List uriPath = request.getOptions().getUriPath(); try { - if (uriPath.size() >= FEATURE_TYPE_POSITION) { + int size = uriPath.size(); + if (size >= FEATURE_TYPE_POSITION) { + if (size == FEATURE_TYPE_POSITION && StringUtils.isNumeric(uriPath.get(size - 1))) { + return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 2).toUpperCase())); + } return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase())); - } else if (uriPath.size() >= FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST) { + } else if (size == FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST) { if (uriPath.contains(DataConstants.PROVISION)) { return Optional.of(FeatureType.valueOf(DataConstants.PROVISION.toUpperCase())); } diff --git a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java new file mode 100644 index 0000000000..666f6c95df --- /dev/null +++ b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java @@ -0,0 +1,352 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.coap; + +import org.eclipse.californium.core.coap.CoAP; +import org.eclipse.californium.core.coap.OptionSet; +import org.eclipse.californium.core.coap.Request; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.thingsboard.server.coapserver.CoapServerService; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.msg.session.FeatureType; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.queue.scheduler.SchedulerComponent; +import org.thingsboard.server.transport.coap.client.CoapClientContext; + +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class CoapTransportResourceTest { + + private static final String V1 = "v1"; + private static final String API = "api"; + private static final String TELEMETRY = "telemetry"; + private static final String ATTRIBUTES = "attributes"; + private static final String RPC = "rpc"; + private static final String CLAIM = "claim"; + private static final String PROVISION = "provision"; + private static final String GET_ATTRIBUTES_URI_QUERY = "clientKeys=attribute1,attribute2&sharedKeys=shared1,shared2"; + + private static final Random RANDOM = new Random(); + + private CoapTransportResource coapTransportResource; + + @BeforeEach + void setUp() { + + var ctxMock = mock(CoapTransportContext.class); + var coapServerServiceMock = mock(CoapServerService.class); + var transportServiceMock = mock(TransportService.class); + var clientContextMock = mock(CoapClientContext.class); + var schedulerComponentMock = mock(SchedulerComponent.class); + + when(ctxMock.getTransportService()).thenReturn(transportServiceMock); + when(ctxMock.getClientContext()).thenReturn(clientContextMock); + when(ctxMock.getSessionReportTimeout()).thenReturn(1L); + when(ctxMock.getScheduler()).thenReturn(schedulerComponentMock); + + coapTransportResource = new CoapTransportResource(ctxMock, coapServerServiceMock, V1); + } + + @AfterEach + void tearDown() { + } + + // accessToken based tests + + @Test + void givenPostTelemetryAccessTokenRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { + // GIVEN + var request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), TELEMETRY); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.TELEMETRY, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenPostAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), ATTRIBUTES); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenGetAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + Request request = toGetAttributesAccessTokenRequest(StringUtils.randomAlphanumeric(20)); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenSubscribeForAttributesUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.GET, StringUtils.randomAlphanumeric(20), ATTRIBUTES); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenSubscribeForRpcUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.GET, StringUtils.randomAlphanumeric(20), RPC); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenRpcResponseAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toRpcResponseAccessTokenRequest(StringUtils.randomAlphanumeric(20), RANDOM.nextInt(100)); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenClientSideRpcAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), RPC); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenClaimingAccessTokenRequest_whenGetFeatureType_thenFeatureTypeClaim() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), CLAIM); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.CLAIM, featureTypeOptional.get(), "Feature type is invalid"); + } + + // certificate based tests + + @Test + void givenPostTelemetryCertificateRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { + // GIVEN + var request = toCertificateRequest(CoAP.Code.POST, TELEMETRY); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.TELEMETRY, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenPostAttributesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + var request = toCertificateRequest(CoAP.Code.POST, ATTRIBUTES); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenGetAttributesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + var request = toGetAttributesCertificateRequest(); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenSubscribeForAttributesUpdatesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + var request = toCertificateRequest(CoAP.Code.GET, ATTRIBUTES); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenSubscribeForRpcUpdatesCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + var request = toCertificateRequest(CoAP.Code.GET, RPC); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenRpcResponseCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toRpcResponseCertificateRequest(RANDOM.nextInt(100)); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenClientSideRpcCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toCertificateRequest(CoAP.Code.POST, RPC); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenClaimingCertificateRequest_whenGetFeatureType_thenFeatureTypeClaim() { + // GIVEN + Request request = toCertificateRequest(CoAP.Code.POST, CLAIM); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.CLAIM, featureTypeOptional.get(), "Feature type is invalid"); + } + + // provision request + + @Test + void givenProvisionRequest_whenGetFeatureType_thenFeatureTypeProvision() { + // GIVEN + Request request = toCertificateRequest(CoAP.Code.POST, PROVISION); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.PROVISION, featureTypeOptional.get(), "Feature type is invalid"); + } + + private Request toAccessTokenRequest(CoAP.Code method, String accessToken, String featureType) { + return getAccessTokenRequest(method, accessToken, featureType, null, null); + } + + private Request toGetAttributesAccessTokenRequest(String accessToken) { + return getAccessTokenRequest(CoAP.Code.GET, accessToken, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); + } + + private Request toRpcResponseAccessTokenRequest(String accessToken, Integer requestId) { + return getAccessTokenRequest(CoAP.Code.POST, accessToken, CoapTransportResourceTest.RPC, requestId, null); + } + + private Request toCertificateRequest(CoAP.Code method, String featureType) { + return getCertificateRequest(method, featureType, null, null); + } + + private Request toGetAttributesCertificateRequest() { + return getCertificateRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); + } + + private Request toRpcResponseCertificateRequest(Integer requestId) { + return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, requestId, null); + } + + private Request getAccessTokenRequest(CoAP.Code method, String accessToken, String featureType, Integer requestId, String uriQuery) { + var request = new Request(method); + var options = new OptionSet(); + options.addUriPath(API); + options.addUriPath(V1); + options.addUriPath(accessToken); + options.addUriPath(featureType); + if (requestId != null) { + options.addUriPath(String.valueOf(requestId)); + } + if (uriQuery != null) { + options.setUriQuery(uriQuery); + } + request.setOptions(options); + return request; + } + + private Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + var request = new Request(method); + var options = new OptionSet(); + options.addUriPath(API); + options.addUriPath(V1); + options.addUriPath(featureType); + if (requestId != null) { + options.addUriPath(String.valueOf(requestId)); + } + if (uriQuery != null) { + options.setUriQuery(uriQuery); + } + request.setOptions(options); + return request; + } + + +} From cebe1040d4f25b11fd9d3613fd3c15e81c6a9359 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 11 Aug 2023 20:27:54 +0300 Subject: [PATCH 407/421] refactoring after review --- .../server/common/data/msg/TbMsgType.java | 30 ++------ .../server/common/data/msg/TbMsgTypeTest.java | 22 +----- .../thingsboard/server/common/msg/TbMsg.java | 76 ++++++------------- .../engine/filter/TbMsgTypeSwitchNode.java | 3 +- .../filter/TbMsgTypeSwitchNodeTest.java | 2 +- 5 files changed, 35 insertions(+), 98 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java index bd351ffecd..f7c9a5b05f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java @@ -16,11 +16,10 @@ package org.thingsboard.server.common.data.msg; import lombok.Getter; +import org.thingsboard.server.common.data.StringUtils; -import java.util.Arrays; import java.util.EnumSet; import java.util.List; -import java.util.Objects; import java.util.stream.Collectors; public enum TbMsgType { @@ -79,12 +78,12 @@ public enum TbMsgType { MSG_COUNT_SELF_MSG(null, true), // Custom or N/A type: - CUSTOM_OR_NA_TYPE(null, false, true); + CUSTOM_OR_NA_TYPE(null, false); public static final List NODE_CONNECTIONS = EnumSet.allOf(TbMsgType.class).stream() .filter(tbMsgType -> !tbMsgType.isTellSelfOnly()) .map(TbMsgType::getRuleNodeConnection) - .filter(Objects::nonNull) + .filter(connection -> !TbNodeConnectionType.OTHER.equals(connection)) .collect(Collectors.toUnmodifiableList()); @Getter @@ -93,32 +92,13 @@ public enum TbMsgType { @Getter private final boolean tellSelfOnly; - @Getter - private final boolean customType; - - TbMsgType(String ruleNodeConnection, boolean tellSelfOnly, boolean customType) { - this.ruleNodeConnection = ruleNodeConnection; - this.tellSelfOnly = tellSelfOnly; - this.customType = customType; - } - TbMsgType(String ruleNodeConnection, boolean tellSelfOnly) { - this.ruleNodeConnection = ruleNodeConnection; + this.ruleNodeConnection = StringUtils.isNotEmpty(ruleNodeConnection) ? ruleNodeConnection : TbNodeConnectionType.OTHER; this.tellSelfOnly = tellSelfOnly; - this.customType = false; } TbMsgType(String ruleNodeConnection) { - this.ruleNodeConnection = ruleNodeConnection; - this.tellSelfOnly = false; - this.customType = false; - } - - public static String getRuleNodeConnectionOrElseOther(TbMsgType msgType) { - if (msgType == null || msgType.isCustomType() || msgType.isTellSelfOnly()) { - return TbNodeConnectionType.OTHER; - } - return Objects.requireNonNullElse(msgType.getRuleNodeConnection(), TbNodeConnectionType.OTHER); + this(ruleNodeConnection, false); } } diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java index ff41505266..c77d109814 100644 --- a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java +++ b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java @@ -63,39 +63,25 @@ class TbMsgTypeTest { var tbMsgTypes = TbMsgType.values(); for (var type : tbMsgTypes) { if (typesWithNullRuleNodeConnection.contains(type)) { - assertThat(type.getRuleNodeConnection()).isNull(); + assertThat(type.getRuleNodeConnection()).isEqualTo(TbNodeConnectionType.OTHER); } else { - assertThat(type.getRuleNodeConnection()).isNotNull(); + assertThat(type.getRuleNodeConnection()).isNotEqualTo(TbNodeConnectionType.OTHER); } } } @Test void getRuleNodeConnectionOrElseOtherTest() { - assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(null)) - .isEqualTo(TbNodeConnectionType.OTHER); var tbMsgTypes = TbMsgType.values(); for (var type : tbMsgTypes) { if (typesWithNullRuleNodeConnection.contains(type)) { - assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type)) + assertThat(type.getRuleNodeConnection()) .isEqualTo(TbNodeConnectionType.OTHER); } else { - assertThat(TbMsgType.getRuleNodeConnectionOrElseOther(type)).isNotNull() + assertThat(type.getRuleNodeConnection()).isNotNull() .isNotEqualTo(TbNodeConnectionType.OTHER); } } } - @Test - void getCustomTypeTest() { - var tbMsgTypes = TbMsgType.values(); - for (var type : tbMsgTypes) { - if (type.equals(CUSTOM_OR_NA_TYPE)) { - assertThat(type.isCustomType()).isTrue(); - continue; - } - assertThat(type.isCustomType()).isFalse(); - } - } - } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index b4f6ccd584..afd3d0268c 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -98,7 +98,7 @@ public final class TbMsg implements Serializable { */ @Deprecated(since = "3.5.2") public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); } @@ -109,7 +109,7 @@ public final class TbMsg implements Serializable { @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); } @@ -171,13 +171,13 @@ public final class TbMsg implements Serializable { */ @Deprecated(since = "3.5.2") public static TbMsg newMsg(String queueName, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, String data) { - return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, customerId, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, TbMsgCallback.EMPTY); } @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, customerId, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, customerId, metaData.copy(), dataType, data, null, null, null, TbMsgCallback.EMPTY); } @@ -223,13 +223,13 @@ public final class TbMsg implements Serializable { @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, null, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, null, TbMsgCallback.EMPTY); } @Deprecated(since = "3.5.2", forRemoval = true) public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { - return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), type, originator, null, + return new TbMsg(null, UUID.randomUUID(), System.currentTimeMillis(), null, type, originator, null, metaData.copy(), TbMsgDataType.JSON, data, null, null, null, callback); } @@ -251,7 +251,7 @@ public final class TbMsg implements Serializable { */ @Deprecated(since = "3.5.2") public static TbMsg transformMsg(TbMsg tbMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, null, type, originator, tbMsg.customerId, metaData.copy(), tbMsg.dataType, data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.callback); } @@ -271,82 +271,57 @@ public final class TbMsg implements Serializable { } public static TbMsg transformMsgOriginator(TbMsg tbMsg, EntityId originatorId) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, originatorId, tbMsg.getCustomerId(), tbMsg.metaData, tbMsg.dataType, + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, originatorId, tbMsg.getCustomerId(), tbMsg.metaData, tbMsg.dataType, tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } public static TbMsg transformMsgData(TbMsg tbMsg, String data) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } public static TbMsg transformMsgMetadata(TbMsg tbMsg, TbMsgMetaData metadata) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata.copy(), tbMsg.dataType, + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata.copy(), tbMsg.dataType, tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } public static TbMsg transformMsg(TbMsg tbMsg, TbMsgMetaData metadata, String data) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata, tbMsg.dataType, + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, metadata, tbMsg.dataType, data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } public static TbMsg transformMsgCustomerId(TbMsg tbMsg, CustomerId customerId) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType, + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, tbMsg.ruleChainId, tbMsg.ruleNodeId, tbMsg.ctx.copy(), tbMsg.getCallback()); } public static TbMsg transformMsgRuleChainId(TbMsg tbMsg, RuleChainId ruleChainId) { - return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, + return new TbMsg(tbMsg.queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback()); } public static TbMsg transformMsgQueueName(TbMsg tbMsg, String queueName) { - return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, + return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, tbMsg.getRuleChainId(), null, tbMsg.ctx.copy(), tbMsg.getCallback()); } public static TbMsg transformMsg(TbMsg tbMsg, RuleChainId ruleChainId, String queueName) { - return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, + return new TbMsg(queueName, tbMsg.id, tbMsg.ts, tbMsg.internalType, tbMsg.type, tbMsg.originator, tbMsg.customerId, tbMsg.metaData, tbMsg.dataType, tbMsg.data, ruleChainId, null, tbMsg.ctx.copy(), tbMsg.getCallback()); } //used for enqueueForTellNext public static TbMsg newMsg(TbMsg tbMsg, String queueName, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { - return new TbMsg(queueName, UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.customerId, tbMsg.getMetaData().copy(), + return new TbMsg(queueName, UUID.randomUUID(), tbMsg.getTs(), tbMsg.getInternalType(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.customerId, tbMsg.getMetaData().copy(), tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, tbMsg.ctx.copy(), TbMsgCallback.EMPTY); } private TbMsg(String queueName, UUID id, long ts, TbMsgType internalType, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgProcessingCtx ctx, TbMsgCallback callback) { - this.id = id; - this.queueName = queueName; - if (ts > 0) { - this.ts = ts; - } else { - this.ts = System.currentTimeMillis(); - } - this.internalType = internalType; - this.type = internalType.name(); - this.originator = originator; - if (customerId == null || customerId.isNullUid()) { - if (originator != null && originator.getEntityType() == EntityType.CUSTOMER) { - this.customerId = (CustomerId) originator; - } else { - this.customerId = null; - } - } else { - this.customerId = customerId; - } - this.metaData = metaData; - this.dataType = dataType; - this.data = data; - this.ruleChainId = ruleChainId; - this.ruleNodeId = ruleNodeId; - this.ctx = ctx != null ? ctx : new TbMsgProcessingCtx(); - this.callback = Objects.requireNonNullElse(callback, TbMsgCallback.EMPTY); + this(queueName, id, ts, internalType, internalType.name(), originator, customerId, metaData, dataType, data, ruleChainId, ruleNodeId, ctx, callback); } - private TbMsg(String queueName, UUID id, long ts, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, + private TbMsg(String queueName, UUID id, long ts, TbMsgType internalType, String type, EntityId originator, CustomerId customerId, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgProcessingCtx ctx, TbMsgCallback callback) { this.id = id; this.queueName = queueName; @@ -356,7 +331,7 @@ public final class TbMsg implements Serializable { this.ts = System.currentTimeMillis(); } this.type = type; - this.internalType = getInternalType(); + this.internalType = internalType != null ? internalType : getInternalType(type); this.originator = originator; if (customerId == null || customerId.isNullUid()) { if (originator != null && originator.getEntityType() == EntityType.CUSTOMER) { @@ -442,7 +417,7 @@ public final class TbMsg implements Serializable { } TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; - return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, customerId, + return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), null, proto.getType(), entityId, customerId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, ctx, callback); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException("Could not parse protobuf for TbMsg", e); @@ -454,17 +429,17 @@ public final class TbMsg implements Serializable { } public TbMsg copyWithRuleChainId(RuleChainId ruleChainId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, + return new TbMsg(this.queueName, msgId, this.ts, this.internalType, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, null, this.ctx, callback); } public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId, UUID msgId) { - return new TbMsg(this.queueName, msgId, this.ts, this.type, this.originator, this.customerId, + return new TbMsg(this.queueName, msgId, this.ts, this.internalType, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ctx, callback); } public TbMsg copyWithNewCtx() { - return new TbMsg(this.queueName, this.id, this.ts, this.type, this.originator, this.customerId, + return new TbMsg(this.queueName, this.id, this.ts, this.internalType, this.type, this.originator, this.customerId, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, this.ctx.copy(), TbMsgCallback.EMPTY); } @@ -500,10 +475,7 @@ public final class TbMsg implements Serializable { return ts; } - public TbMsgType getInternalType() { - if (internalType != null) { - return internalType; - } + private TbMsgType getInternalType(String type) { try { return TbMsgType.valueOf(type); } catch (IllegalArgumentException e) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java index 068d342ea7..d5b06b4537 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; @@ -50,7 +49,7 @@ public class TbMsgTypeSwitchNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { - ctx.tellNext(msg, TbMsgType.getRuleNodeConnectionOrElseOther(msg.getInternalType())); + ctx.tellNext(msg, msg.getInternalType().getRuleNodeConnection()); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java index 7861b2f489..603c23cd05 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNodeTest.java @@ -84,7 +84,7 @@ class TbMsgTypeSwitchNodeTest { assertThat(msg.getType()).isEqualTo(msg.getInternalType().name()); assertThat(msg).isSameAs(tbMsgList.get(i)); assertThat(resultNodeConnections.get(i)) - .isEqualTo(TbMsgType.getRuleNodeConnectionOrElseOther(msg.getInternalType())); + .isEqualTo(msg.getInternalType().getRuleNodeConnection()); } } From ea5a8552723e09f333be10d9b5785e4b20acd044 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 11 Aug 2023 20:34:17 +0300 Subject: [PATCH 408/421] renamed custom msg type to NA --- .../org/thingsboard/server/common/data/msg/TbMsgType.java | 2 +- .../org/thingsboard/server/common/data/msg/TbMsgTypeTest.java | 4 ++-- .../main/java/org/thingsboard/server/common/msg/TbMsg.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java index f7c9a5b05f..1f7691c7f5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java @@ -78,7 +78,7 @@ public enum TbMsgType { MSG_COUNT_SELF_MSG(null, true), // Custom or N/A type: - CUSTOM_OR_NA_TYPE(null, false); + NA(null, false); public static final List NODE_CONNECTIONS = EnumSet.allOf(TbMsgType.class).stream() .filter(tbMsgType -> !tbMsgType.isTellSelfOnly()) diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java index c77d109814..870d5a2804 100644 --- a/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java +++ b/common/data/src/test/java/org/thingsboard/server/common/data/msg/TbMsgTypeTest.java @@ -22,7 +22,7 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM; import static org.thingsboard.server.common.data.msg.TbMsgType.ALARM_DELETE; -import static org.thingsboard.server.common.data.msg.TbMsgType.CUSTOM_OR_NA_TYPE; +import static org.thingsboard.server.common.data.msg.TbMsgType.NA; import static org.thingsboard.server.common.data.msg.TbMsgType.DEDUPLICATION_TIMEOUT_SELF_MSG; import static org.thingsboard.server.common.data.msg.TbMsgType.DELAY_TIMEOUT_SELF_MSG; import static org.thingsboard.server.common.data.msg.TbMsgType.ENTITY_ASSIGNED_TO_EDGE; @@ -53,7 +53,7 @@ class TbMsgTypeTest { DEDUPLICATION_TIMEOUT_SELF_MSG, DELAY_TIMEOUT_SELF_MSG, MSG_COUNT_SELF_MSG, - CUSTOM_OR_NA_TYPE + NA ); // backward-compatibility tests diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index afd3d0268c..8b76677c76 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -479,7 +479,7 @@ public final class TbMsg implements Serializable { try { return TbMsgType.valueOf(type); } catch (IllegalArgumentException e) { - return TbMsgType.CUSTOM_OR_NA_TYPE; + return TbMsgType.NA; } } From e1b18e7bed022d0a54680946cd124fe2bf2f6f59 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Sat, 12 Aug 2023 09:17:21 +0300 Subject: [PATCH 409/421] additional updates after review --- .../server/common/data/msg/TbMsgType.java | 20 +++++++++++-------- .../thingsboard/server/common/msg/TbMsg.java | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java index 1f7691c7f5..23149c79c1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/msg/TbMsgType.java @@ -38,10 +38,10 @@ public enum TbMsgType { ENTITY_UNASSIGNED("Entity Unassigned"), ATTRIBUTES_UPDATED("Attributes Updated"), ATTRIBUTES_DELETED("Attributes Deleted"), - ALARM(null), + ALARM, ALARM_ACK("Alarm Acknowledged"), ALARM_CLEAR("Alarm Cleared"), - ALARM_DELETE(null), + ALARM_DELETE, ALARM_ASSIGNED("Alarm Assigned"), ALARM_UNASSIGNED("Alarm Unassigned"), COMMENT_CREATED("Comment Created"), @@ -49,8 +49,8 @@ public enum TbMsgType { RPC_CALL_FROM_SERVER_TO_DEVICE("RPC Request to Device"), ENTITY_ASSIGNED_FROM_TENANT("Entity Assigned From Tenant"), ENTITY_ASSIGNED_TO_TENANT("Entity Assigned To Tenant"), - ENTITY_ASSIGNED_TO_EDGE(null), - ENTITY_UNASSIGNED_FROM_EDGE(null), + ENTITY_ASSIGNED_TO_EDGE, + ENTITY_UNASSIGNED_FROM_EDGE, TIMESERIES_UPDATED("Timeseries Updated"), TIMESERIES_DELETED("Timeseries Deleted"), RPC_QUEUED("RPC Queued"), @@ -64,9 +64,9 @@ public enum TbMsgType { RELATION_ADD_OR_UPDATE("Relation Added or Updated"), RELATION_DELETED("Relation Deleted"), RELATIONS_DELETED("All Relations Deleted"), - PROVISION_SUCCESS(null), - PROVISION_FAILURE(null), - SEND_EMAIL(null), + PROVISION_SUCCESS, + PROVISION_FAILURE, + SEND_EMAIL, // tellSelfOnly types GENERATOR_NODE_SELF_MSG(null, true), @@ -78,7 +78,7 @@ public enum TbMsgType { MSG_COUNT_SELF_MSG(null, true), // Custom or N/A type: - NA(null, false); + NA; public static final List NODE_CONNECTIONS = EnumSet.allOf(TbMsgType.class).stream() .filter(tbMsgType -> !tbMsgType.isTellSelfOnly()) @@ -101,4 +101,8 @@ public enum TbMsgType { this(ruleNodeConnection, false); } + TbMsgType() { + this(null, false); + } + } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index 8b76677c76..63c1e27385 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -484,7 +484,7 @@ public final class TbMsg implements Serializable { } public boolean isTypeOf(TbMsgType tbMsgType) { - return tbMsgType != null && tbMsgType.equals(getInternalType()); + return internalType.equals(tbMsgType); } public boolean isTypeOneOf(TbMsgType... types) { From f647fca59c61130aa5f16d2691d404c10aa5be19 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Sat, 12 Aug 2023 09:38:49 +0300 Subject: [PATCH 410/421] refactoring of test base --- .../coap/CoapTransportResourceTest.java | 71 ++++++++----------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java index 666f6c95df..2e5b367e4c 100644 --- a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java +++ b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java @@ -18,7 +18,9 @@ package org.thingsboard.server.transport.coap; import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.OptionSet; import org.eclipse.californium.core.coap.Request; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.thingsboard.server.coapserver.CoapServerService; @@ -48,10 +50,10 @@ class CoapTransportResourceTest { private static final Random RANDOM = new Random(); - private CoapTransportResource coapTransportResource; + private static CoapTransportResource coapTransportResource; - @BeforeEach - void setUp() { + @BeforeAll + static void setUp() { var ctxMock = mock(CoapTransportContext.class); var coapServerServiceMock = mock(CoapServerService.class); @@ -67,16 +69,12 @@ class CoapTransportResourceTest { coapTransportResource = new CoapTransportResource(ctxMock, coapServerServiceMock, V1); } - @AfterEach - void tearDown() { - } - // accessToken based tests @Test void givenPostTelemetryAccessTokenRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { // GIVEN - var request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), TELEMETRY); + var request = toAccessTokenRequest(CoAP.Code.POST, TELEMETRY); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -89,7 +87,7 @@ class CoapTransportResourceTest { @Test void givenPostAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), ATTRIBUTES); + Request request = toAccessTokenRequest(CoAP.Code.POST, ATTRIBUTES); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -102,7 +100,7 @@ class CoapTransportResourceTest { @Test void givenGetAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { // GIVEN - Request request = toGetAttributesAccessTokenRequest(StringUtils.randomAlphanumeric(20)); + Request request = toGetAttributesAccessTokenRequest(); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -114,7 +112,7 @@ class CoapTransportResourceTest { @Test void givenSubscribeForAttributesUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.GET, StringUtils.randomAlphanumeric(20), ATTRIBUTES); + Request request = toAccessTokenRequest(CoAP.Code.GET, ATTRIBUTES); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -126,7 +124,7 @@ class CoapTransportResourceTest { @Test void givenSubscribeForRpcUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.GET, StringUtils.randomAlphanumeric(20), RPC); + Request request = toAccessTokenRequest(CoAP.Code.GET, RPC); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -138,7 +136,7 @@ class CoapTransportResourceTest { @Test void givenRpcResponseAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { // GIVEN - Request request = toRpcResponseAccessTokenRequest(StringUtils.randomAlphanumeric(20), RANDOM.nextInt(100)); + Request request = toRpcResponseAccessTokenRequest(); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -150,7 +148,7 @@ class CoapTransportResourceTest { @Test void givenClientSideRpcAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), RPC); + Request request = toAccessTokenRequest(CoAP.Code.POST, RPC); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -162,7 +160,7 @@ class CoapTransportResourceTest { @Test void givenClaimingAccessTokenRequest_whenGetFeatureType_thenFeatureTypeClaim() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), CLAIM); + Request request = toAccessTokenRequest(CoAP.Code.POST, CLAIM); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -241,7 +239,7 @@ class CoapTransportResourceTest { @Test void givenRpcResponseCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { // GIVEN - Request request = toRpcResponseCertificateRequest(RANDOM.nextInt(100)); + Request request = toRpcResponseCertificateRequest(); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -291,16 +289,16 @@ class CoapTransportResourceTest { assertEquals(FeatureType.PROVISION, featureTypeOptional.get(), "Feature type is invalid"); } - private Request toAccessTokenRequest(CoAP.Code method, String accessToken, String featureType) { - return getAccessTokenRequest(method, accessToken, featureType, null, null); + private Request toAccessTokenRequest(CoAP.Code method, String featureType) { + return getAccessTokenRequest(method, featureType, null, null); } - private Request toGetAttributesAccessTokenRequest(String accessToken) { - return getAccessTokenRequest(CoAP.Code.GET, accessToken, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); + private Request toGetAttributesAccessTokenRequest() { + return getAccessTokenRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); } - private Request toRpcResponseAccessTokenRequest(String accessToken, Integer requestId) { - return getAccessTokenRequest(CoAP.Code.POST, accessToken, CoapTransportResourceTest.RPC, requestId, null); + private Request toRpcResponseAccessTokenRequest() { + return getAccessTokenRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); } private Request toCertificateRequest(CoAP.Code method, String featureType) { @@ -311,32 +309,26 @@ class CoapTransportResourceTest { return getCertificateRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); } - private Request toRpcResponseCertificateRequest(Integer requestId) { - return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, requestId, null); + private Request toRpcResponseCertificateRequest() { + return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); } - private Request getAccessTokenRequest(CoAP.Code method, String accessToken, String featureType, Integer requestId, String uriQuery) { - var request = new Request(method); - var options = new OptionSet(); - options.addUriPath(API); - options.addUriPath(V1); - options.addUriPath(accessToken); - options.addUriPath(featureType); - if (requestId != null) { - options.addUriPath(String.valueOf(requestId)); - } - if (uriQuery != null) { - options.setUriQuery(uriQuery); - } - request.setOptions(options); - return request; + private Request getAccessTokenRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + return getRequest(method, featureType, false, requestId, uriQuery); } private Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + return getRequest(method, featureType, true, requestId, uriQuery); + } + + private Request getRequest(CoAP.Code method, String featureType, boolean dtls, Integer requestId, String uriQuery) { var request = new Request(method); var options = new OptionSet(); options.addUriPath(API); options.addUriPath(V1); + if (!dtls) { + options.addUriPath(StringUtils.randomAlphanumeric(20)); + } options.addUriPath(featureType); if (requestId != null) { options.addUriPath(String.valueOf(requestId)); @@ -348,5 +340,4 @@ class CoapTransportResourceTest { return request; } - } From c5ff8b4229af3adfde1e5c8436540afca1d71512 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Sat, 12 Aug 2023 09:52:36 +0300 Subject: [PATCH 411/421] refactored to parameterized test --- .../coap/CoapTransportResourceTest.java | 270 +++--------------- 1 file changed, 44 insertions(+), 226 deletions(-) diff --git a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java index 2e5b367e4c..c7f33e3694 100644 --- a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java +++ b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java @@ -18,11 +18,10 @@ package org.thingsboard.server.transport.coap; import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.OptionSet; import org.eclipse.californium.core.coap.Request; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.thingsboard.server.coapserver.CoapServerService; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.msg.session.FeatureType; @@ -31,6 +30,7 @@ import org.thingsboard.server.queue.scheduler.SchedulerComponent; import org.thingsboard.server.transport.coap.client.CoapClientContext; import java.util.Random; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -69,259 +69,77 @@ class CoapTransportResourceTest { coapTransportResource = new CoapTransportResource(ctxMock, coapServerServiceMock, V1); } - // accessToken based tests - - @Test - void givenPostTelemetryAccessTokenRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { - // GIVEN - var request = toAccessTokenRequest(CoAP.Code.POST, TELEMETRY); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.TELEMETRY, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenPostAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, ATTRIBUTES); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenGetAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - Request request = toGetAttributesAccessTokenRequest(); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenSubscribeForAttributesUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.GET, ATTRIBUTES); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenSubscribeForRpcUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.GET, RPC); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenRpcResponseAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toRpcResponseAccessTokenRequest(); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenClientSideRpcAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, RPC); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenClaimingAccessTokenRequest_whenGetFeatureType_thenFeatureTypeClaim() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, CLAIM); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.CLAIM, featureTypeOptional.get(), "Feature type is invalid"); - } - - // certificate based tests - - @Test - void givenPostTelemetryCertificateRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { - // GIVEN - var request = toCertificateRequest(CoAP.Code.POST, TELEMETRY); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.TELEMETRY, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenPostAttributesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - var request = toCertificateRequest(CoAP.Code.POST, ATTRIBUTES); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenGetAttributesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - var request = toGetAttributesCertificateRequest(); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenSubscribeForAttributesUpdatesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - var request = toCertificateRequest(CoAP.Code.GET, ATTRIBUTES); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenSubscribeForRpcUpdatesCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - var request = toCertificateRequest(CoAP.Code.GET, RPC); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenRpcResponseCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toRpcResponseCertificateRequest(); - - // WHEN + @ParameterizedTest + @MethodSource("provideRequestAndFeatureType") + void givenRequest_whenGetFeatureType_thenReturnedExpectedFeatureType(Request request, FeatureType expectedFeatureType) { var featureTypeOptional = coapTransportResource.getFeatureType(request); - // THEN assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + assertEquals(expectedFeatureType, featureTypeOptional.get(), "Feature type is invalid"); } - @Test - void givenClientSideRpcCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toCertificateRequest(CoAP.Code.POST, RPC); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + static Stream provideRequestAndFeatureType() { + return Stream.of( + // accessToken based tests + Arguments.of(toAccessTokenRequest(CoAP.Code.POST, TELEMETRY), FeatureType.TELEMETRY), + Arguments.of(toAccessTokenRequest(CoAP.Code.POST, ATTRIBUTES), FeatureType.ATTRIBUTES), + Arguments.of(toGetAttributesAccessTokenRequest(), FeatureType.ATTRIBUTES), + Arguments.of(toAccessTokenRequest(CoAP.Code.GET, ATTRIBUTES), FeatureType.ATTRIBUTES), + Arguments.of(toAccessTokenRequest(CoAP.Code.GET, RPC), FeatureType.RPC), + Arguments.of(toRpcResponseAccessTokenRequest(), FeatureType.RPC), + Arguments.of(toAccessTokenRequest(CoAP.Code.POST, RPC), FeatureType.RPC), + Arguments.of(toAccessTokenRequest(CoAP.Code.POST, CLAIM), FeatureType.CLAIM), + // certificate based tests + Arguments.of(toCertificateRequest(CoAP.Code.POST, TELEMETRY), FeatureType.TELEMETRY), + Arguments.of(toCertificateRequest(CoAP.Code.POST, ATTRIBUTES), FeatureType.ATTRIBUTES), + Arguments.of(toGetAttributesCertificateRequest(), FeatureType.ATTRIBUTES), + Arguments.of(toCertificateRequest(CoAP.Code.GET, ATTRIBUTES), FeatureType.ATTRIBUTES), + Arguments.of(toCertificateRequest(CoAP.Code.GET, RPC), FeatureType.RPC), + Arguments.of(toRpcResponseCertificateRequest(), FeatureType.RPC), + Arguments.of(toCertificateRequest(CoAP.Code.POST, RPC), FeatureType.RPC), + Arguments.of(toCertificateRequest(CoAP.Code.POST, CLAIM), FeatureType.CLAIM), + // provision request + Arguments.of(toProvisionRequest(), FeatureType.PROVISION) + ); } - @Test - void givenClaimingCertificateRequest_whenGetFeatureType_thenFeatureTypeClaim() { - // GIVEN - Request request = toCertificateRequest(CoAP.Code.POST, CLAIM); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.CLAIM, featureTypeOptional.get(), "Feature type is invalid"); - } - - // provision request - - @Test - void givenProvisionRequest_whenGetFeatureType_thenFeatureTypeProvision() { - // GIVEN - Request request = toCertificateRequest(CoAP.Code.POST, PROVISION); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.PROVISION, featureTypeOptional.get(), "Feature type is invalid"); - } - - private Request toAccessTokenRequest(CoAP.Code method, String featureType) { + private static Request toAccessTokenRequest(CoAP.Code method, String featureType) { return getAccessTokenRequest(method, featureType, null, null); } - private Request toGetAttributesAccessTokenRequest() { + private static Request toGetAttributesAccessTokenRequest() { return getAccessTokenRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); } - private Request toRpcResponseAccessTokenRequest() { + private static Request toRpcResponseAccessTokenRequest() { return getAccessTokenRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); } - private Request toCertificateRequest(CoAP.Code method, String featureType) { + private static Request toCertificateRequest(CoAP.Code method, String featureType) { return getCertificateRequest(method, featureType, null, null); } - private Request toGetAttributesCertificateRequest() { + private static Request toGetAttributesCertificateRequest() { return getCertificateRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); } - private Request toRpcResponseCertificateRequest() { + private static Request toRpcResponseCertificateRequest() { return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); } - private Request getAccessTokenRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + private static Request getAccessTokenRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { return getRequest(method, featureType, false, requestId, uriQuery); } - private Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + private static Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { return getRequest(method, featureType, true, requestId, uriQuery); } - private Request getRequest(CoAP.Code method, String featureType, boolean dtls, Integer requestId, String uriQuery) { + private static Request toProvisionRequest() { + return getRequest(CoAP.Code.POST, PROVISION, true, null, null); + } + + private static Request getRequest(CoAP.Code method, String featureType, boolean dtls, Integer requestId, String uriQuery) { var request = new Request(method); var options = new OptionSet(); options.addUriPath(API); From 928962898e266cfabebd949bd2e1b7f106b84769 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 11 Aug 2023 19:23:51 +0300 Subject: [PATCH 412/421] PROD-2339: fix getFeatureType method to handle RPC server-side response over DTLS --- .../transport/coap/CoapTransportResource.java | 11 +- .../coap/CoapTransportResourceTest.java | 352 ++++++++++++++++++ 2 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index 7dde25bfd0..263df9e7a2 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java @@ -30,6 +30,7 @@ import org.thingsboard.server.coapserver.TbCoapDtlsSessionInfo; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.security.DeviceTokenCredentials; import org.thingsboard.server.common.msg.session.FeatureType; @@ -380,12 +381,16 @@ public class CoapTransportResource extends AbstractCoapTransportResource { } } - private Optional getFeatureType(Request request) { + protected Optional getFeatureType(Request request) { List uriPath = request.getOptions().getUriPath(); try { - if (uriPath.size() >= FEATURE_TYPE_POSITION) { + int size = uriPath.size(); + if (size >= FEATURE_TYPE_POSITION) { + if (size == FEATURE_TYPE_POSITION && StringUtils.isNumeric(uriPath.get(size - 1))) { + return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 2).toUpperCase())); + } return Optional.of(FeatureType.valueOf(uriPath.get(FEATURE_TYPE_POSITION - 1).toUpperCase())); - } else if (uriPath.size() >= FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST) { + } else if (size == FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST) { if (uriPath.contains(DataConstants.PROVISION)) { return Optional.of(FeatureType.valueOf(DataConstants.PROVISION.toUpperCase())); } diff --git a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java new file mode 100644 index 0000000000..666f6c95df --- /dev/null +++ b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java @@ -0,0 +1,352 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.coap; + +import org.eclipse.californium.core.coap.CoAP; +import org.eclipse.californium.core.coap.OptionSet; +import org.eclipse.californium.core.coap.Request; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.thingsboard.server.coapserver.CoapServerService; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.common.msg.session.FeatureType; +import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.queue.scheduler.SchedulerComponent; +import org.thingsboard.server.transport.coap.client.CoapClientContext; + +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class CoapTransportResourceTest { + + private static final String V1 = "v1"; + private static final String API = "api"; + private static final String TELEMETRY = "telemetry"; + private static final String ATTRIBUTES = "attributes"; + private static final String RPC = "rpc"; + private static final String CLAIM = "claim"; + private static final String PROVISION = "provision"; + private static final String GET_ATTRIBUTES_URI_QUERY = "clientKeys=attribute1,attribute2&sharedKeys=shared1,shared2"; + + private static final Random RANDOM = new Random(); + + private CoapTransportResource coapTransportResource; + + @BeforeEach + void setUp() { + + var ctxMock = mock(CoapTransportContext.class); + var coapServerServiceMock = mock(CoapServerService.class); + var transportServiceMock = mock(TransportService.class); + var clientContextMock = mock(CoapClientContext.class); + var schedulerComponentMock = mock(SchedulerComponent.class); + + when(ctxMock.getTransportService()).thenReturn(transportServiceMock); + when(ctxMock.getClientContext()).thenReturn(clientContextMock); + when(ctxMock.getSessionReportTimeout()).thenReturn(1L); + when(ctxMock.getScheduler()).thenReturn(schedulerComponentMock); + + coapTransportResource = new CoapTransportResource(ctxMock, coapServerServiceMock, V1); + } + + @AfterEach + void tearDown() { + } + + // accessToken based tests + + @Test + void givenPostTelemetryAccessTokenRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { + // GIVEN + var request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), TELEMETRY); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.TELEMETRY, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenPostAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), ATTRIBUTES); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenGetAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + Request request = toGetAttributesAccessTokenRequest(StringUtils.randomAlphanumeric(20)); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenSubscribeForAttributesUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.GET, StringUtils.randomAlphanumeric(20), ATTRIBUTES); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenSubscribeForRpcUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.GET, StringUtils.randomAlphanumeric(20), RPC); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenRpcResponseAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toRpcResponseAccessTokenRequest(StringUtils.randomAlphanumeric(20), RANDOM.nextInt(100)); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenClientSideRpcAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), RPC); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenClaimingAccessTokenRequest_whenGetFeatureType_thenFeatureTypeClaim() { + // GIVEN + Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), CLAIM); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.CLAIM, featureTypeOptional.get(), "Feature type is invalid"); + } + + // certificate based tests + + @Test + void givenPostTelemetryCertificateRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { + // GIVEN + var request = toCertificateRequest(CoAP.Code.POST, TELEMETRY); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.TELEMETRY, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenPostAttributesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + var request = toCertificateRequest(CoAP.Code.POST, ATTRIBUTES); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenGetAttributesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + var request = toGetAttributesCertificateRequest(); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenSubscribeForAttributesUpdatesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { + // GIVEN + var request = toCertificateRequest(CoAP.Code.GET, ATTRIBUTES); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenSubscribeForRpcUpdatesCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + var request = toCertificateRequest(CoAP.Code.GET, RPC); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenRpcResponseCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toRpcResponseCertificateRequest(RANDOM.nextInt(100)); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenClientSideRpcCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { + // GIVEN + Request request = toCertificateRequest(CoAP.Code.POST, RPC); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + } + + @Test + void givenClaimingCertificateRequest_whenGetFeatureType_thenFeatureTypeClaim() { + // GIVEN + Request request = toCertificateRequest(CoAP.Code.POST, CLAIM); + + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.CLAIM, featureTypeOptional.get(), "Feature type is invalid"); + } + + // provision request + + @Test + void givenProvisionRequest_whenGetFeatureType_thenFeatureTypeProvision() { + // GIVEN + Request request = toCertificateRequest(CoAP.Code.POST, PROVISION); + // WHEN + var featureTypeOptional = coapTransportResource.getFeatureType(request); + + // THEN + assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); + assertEquals(FeatureType.PROVISION, featureTypeOptional.get(), "Feature type is invalid"); + } + + private Request toAccessTokenRequest(CoAP.Code method, String accessToken, String featureType) { + return getAccessTokenRequest(method, accessToken, featureType, null, null); + } + + private Request toGetAttributesAccessTokenRequest(String accessToken) { + return getAccessTokenRequest(CoAP.Code.GET, accessToken, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); + } + + private Request toRpcResponseAccessTokenRequest(String accessToken, Integer requestId) { + return getAccessTokenRequest(CoAP.Code.POST, accessToken, CoapTransportResourceTest.RPC, requestId, null); + } + + private Request toCertificateRequest(CoAP.Code method, String featureType) { + return getCertificateRequest(method, featureType, null, null); + } + + private Request toGetAttributesCertificateRequest() { + return getCertificateRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); + } + + private Request toRpcResponseCertificateRequest(Integer requestId) { + return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, requestId, null); + } + + private Request getAccessTokenRequest(CoAP.Code method, String accessToken, String featureType, Integer requestId, String uriQuery) { + var request = new Request(method); + var options = new OptionSet(); + options.addUriPath(API); + options.addUriPath(V1); + options.addUriPath(accessToken); + options.addUriPath(featureType); + if (requestId != null) { + options.addUriPath(String.valueOf(requestId)); + } + if (uriQuery != null) { + options.setUriQuery(uriQuery); + } + request.setOptions(options); + return request; + } + + private Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + var request = new Request(method); + var options = new OptionSet(); + options.addUriPath(API); + options.addUriPath(V1); + options.addUriPath(featureType); + if (requestId != null) { + options.addUriPath(String.valueOf(requestId)); + } + if (uriQuery != null) { + options.setUriQuery(uriQuery); + } + request.setOptions(options); + return request; + } + + +} From 14ad1df873200ef8d69b82f98bab9cd6f8416d39 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Sat, 12 Aug 2023 09:38:49 +0300 Subject: [PATCH 413/421] refactoring of test base --- .../coap/CoapTransportResourceTest.java | 71 ++++++++----------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java index 666f6c95df..2e5b367e4c 100644 --- a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java +++ b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java @@ -18,7 +18,9 @@ package org.thingsboard.server.transport.coap; import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.OptionSet; import org.eclipse.californium.core.coap.Request; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.thingsboard.server.coapserver.CoapServerService; @@ -48,10 +50,10 @@ class CoapTransportResourceTest { private static final Random RANDOM = new Random(); - private CoapTransportResource coapTransportResource; + private static CoapTransportResource coapTransportResource; - @BeforeEach - void setUp() { + @BeforeAll + static void setUp() { var ctxMock = mock(CoapTransportContext.class); var coapServerServiceMock = mock(CoapServerService.class); @@ -67,16 +69,12 @@ class CoapTransportResourceTest { coapTransportResource = new CoapTransportResource(ctxMock, coapServerServiceMock, V1); } - @AfterEach - void tearDown() { - } - // accessToken based tests @Test void givenPostTelemetryAccessTokenRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { // GIVEN - var request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), TELEMETRY); + var request = toAccessTokenRequest(CoAP.Code.POST, TELEMETRY); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -89,7 +87,7 @@ class CoapTransportResourceTest { @Test void givenPostAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), ATTRIBUTES); + Request request = toAccessTokenRequest(CoAP.Code.POST, ATTRIBUTES); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -102,7 +100,7 @@ class CoapTransportResourceTest { @Test void givenGetAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { // GIVEN - Request request = toGetAttributesAccessTokenRequest(StringUtils.randomAlphanumeric(20)); + Request request = toGetAttributesAccessTokenRequest(); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -114,7 +112,7 @@ class CoapTransportResourceTest { @Test void givenSubscribeForAttributesUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.GET, StringUtils.randomAlphanumeric(20), ATTRIBUTES); + Request request = toAccessTokenRequest(CoAP.Code.GET, ATTRIBUTES); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -126,7 +124,7 @@ class CoapTransportResourceTest { @Test void givenSubscribeForRpcUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.GET, StringUtils.randomAlphanumeric(20), RPC); + Request request = toAccessTokenRequest(CoAP.Code.GET, RPC); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -138,7 +136,7 @@ class CoapTransportResourceTest { @Test void givenRpcResponseAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { // GIVEN - Request request = toRpcResponseAccessTokenRequest(StringUtils.randomAlphanumeric(20), RANDOM.nextInt(100)); + Request request = toRpcResponseAccessTokenRequest(); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -150,7 +148,7 @@ class CoapTransportResourceTest { @Test void givenClientSideRpcAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), RPC); + Request request = toAccessTokenRequest(CoAP.Code.POST, RPC); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -162,7 +160,7 @@ class CoapTransportResourceTest { @Test void givenClaimingAccessTokenRequest_whenGetFeatureType_thenFeatureTypeClaim() { // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, StringUtils.randomAlphanumeric(20), CLAIM); + Request request = toAccessTokenRequest(CoAP.Code.POST, CLAIM); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -241,7 +239,7 @@ class CoapTransportResourceTest { @Test void givenRpcResponseCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { // GIVEN - Request request = toRpcResponseCertificateRequest(RANDOM.nextInt(100)); + Request request = toRpcResponseCertificateRequest(); // WHEN var featureTypeOptional = coapTransportResource.getFeatureType(request); @@ -291,16 +289,16 @@ class CoapTransportResourceTest { assertEquals(FeatureType.PROVISION, featureTypeOptional.get(), "Feature type is invalid"); } - private Request toAccessTokenRequest(CoAP.Code method, String accessToken, String featureType) { - return getAccessTokenRequest(method, accessToken, featureType, null, null); + private Request toAccessTokenRequest(CoAP.Code method, String featureType) { + return getAccessTokenRequest(method, featureType, null, null); } - private Request toGetAttributesAccessTokenRequest(String accessToken) { - return getAccessTokenRequest(CoAP.Code.GET, accessToken, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); + private Request toGetAttributesAccessTokenRequest() { + return getAccessTokenRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); } - private Request toRpcResponseAccessTokenRequest(String accessToken, Integer requestId) { - return getAccessTokenRequest(CoAP.Code.POST, accessToken, CoapTransportResourceTest.RPC, requestId, null); + private Request toRpcResponseAccessTokenRequest() { + return getAccessTokenRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); } private Request toCertificateRequest(CoAP.Code method, String featureType) { @@ -311,32 +309,26 @@ class CoapTransportResourceTest { return getCertificateRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); } - private Request toRpcResponseCertificateRequest(Integer requestId) { - return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, requestId, null); + private Request toRpcResponseCertificateRequest() { + return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); } - private Request getAccessTokenRequest(CoAP.Code method, String accessToken, String featureType, Integer requestId, String uriQuery) { - var request = new Request(method); - var options = new OptionSet(); - options.addUriPath(API); - options.addUriPath(V1); - options.addUriPath(accessToken); - options.addUriPath(featureType); - if (requestId != null) { - options.addUriPath(String.valueOf(requestId)); - } - if (uriQuery != null) { - options.setUriQuery(uriQuery); - } - request.setOptions(options); - return request; + private Request getAccessTokenRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + return getRequest(method, featureType, false, requestId, uriQuery); } private Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + return getRequest(method, featureType, true, requestId, uriQuery); + } + + private Request getRequest(CoAP.Code method, String featureType, boolean dtls, Integer requestId, String uriQuery) { var request = new Request(method); var options = new OptionSet(); options.addUriPath(API); options.addUriPath(V1); + if (!dtls) { + options.addUriPath(StringUtils.randomAlphanumeric(20)); + } options.addUriPath(featureType); if (requestId != null) { options.addUriPath(String.valueOf(requestId)); @@ -348,5 +340,4 @@ class CoapTransportResourceTest { return request; } - } From a90653d6606eee59345943e41d7ec2b27fceb266 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Sat, 12 Aug 2023 09:52:36 +0300 Subject: [PATCH 414/421] refactored to parameterized test --- .../coap/CoapTransportResourceTest.java | 270 +++--------------- 1 file changed, 44 insertions(+), 226 deletions(-) diff --git a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java index 2e5b367e4c..c7f33e3694 100644 --- a/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java +++ b/common/transport/coap/src/test/java/org/thingsboard/server/transport/coap/CoapTransportResourceTest.java @@ -18,11 +18,10 @@ package org.thingsboard.server.transport.coap; import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.OptionSet; import org.eclipse.californium.core.coap.Request; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.thingsboard.server.coapserver.CoapServerService; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.msg.session.FeatureType; @@ -31,6 +30,7 @@ import org.thingsboard.server.queue.scheduler.SchedulerComponent; import org.thingsboard.server.transport.coap.client.CoapClientContext; import java.util.Random; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -69,259 +69,77 @@ class CoapTransportResourceTest { coapTransportResource = new CoapTransportResource(ctxMock, coapServerServiceMock, V1); } - // accessToken based tests - - @Test - void givenPostTelemetryAccessTokenRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { - // GIVEN - var request = toAccessTokenRequest(CoAP.Code.POST, TELEMETRY); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.TELEMETRY, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenPostAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, ATTRIBUTES); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenGetAttributesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - Request request = toGetAttributesAccessTokenRequest(); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenSubscribeForAttributesUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.GET, ATTRIBUTES); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenSubscribeForRpcUpdatesAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.GET, RPC); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenRpcResponseAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toRpcResponseAccessTokenRequest(); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenClientSideRpcAccessTokenRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, RPC); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenClaimingAccessTokenRequest_whenGetFeatureType_thenFeatureTypeClaim() { - // GIVEN - Request request = toAccessTokenRequest(CoAP.Code.POST, CLAIM); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.CLAIM, featureTypeOptional.get(), "Feature type is invalid"); - } - - // certificate based tests - - @Test - void givenPostTelemetryCertificateRequest_whenGetFeatureType_thenFeatureTypeTelemetry() { - // GIVEN - var request = toCertificateRequest(CoAP.Code.POST, TELEMETRY); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.TELEMETRY, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenPostAttributesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - var request = toCertificateRequest(CoAP.Code.POST, ATTRIBUTES); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenGetAttributesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - var request = toGetAttributesCertificateRequest(); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenSubscribeForAttributesUpdatesCertificateRequest_whenGetFeatureType_thenFeatureTypeAttributes() { - // GIVEN - var request = toCertificateRequest(CoAP.Code.GET, ATTRIBUTES); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.ATTRIBUTES, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenSubscribeForRpcUpdatesCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - var request = toCertificateRequest(CoAP.Code.GET, RPC); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); - } - - @Test - void givenRpcResponseCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toRpcResponseCertificateRequest(); - - // WHEN + @ParameterizedTest + @MethodSource("provideRequestAndFeatureType") + void givenRequest_whenGetFeatureType_thenReturnedExpectedFeatureType(Request request, FeatureType expectedFeatureType) { var featureTypeOptional = coapTransportResource.getFeatureType(request); - // THEN assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + assertEquals(expectedFeatureType, featureTypeOptional.get(), "Feature type is invalid"); } - @Test - void givenClientSideRpcCertificateRequest_whenGetFeatureType_thenFeatureTypeRpc() { - // GIVEN - Request request = toCertificateRequest(CoAP.Code.POST, RPC); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.RPC, featureTypeOptional.get(), "Feature type is invalid"); + static Stream provideRequestAndFeatureType() { + return Stream.of( + // accessToken based tests + Arguments.of(toAccessTokenRequest(CoAP.Code.POST, TELEMETRY), FeatureType.TELEMETRY), + Arguments.of(toAccessTokenRequest(CoAP.Code.POST, ATTRIBUTES), FeatureType.ATTRIBUTES), + Arguments.of(toGetAttributesAccessTokenRequest(), FeatureType.ATTRIBUTES), + Arguments.of(toAccessTokenRequest(CoAP.Code.GET, ATTRIBUTES), FeatureType.ATTRIBUTES), + Arguments.of(toAccessTokenRequest(CoAP.Code.GET, RPC), FeatureType.RPC), + Arguments.of(toRpcResponseAccessTokenRequest(), FeatureType.RPC), + Arguments.of(toAccessTokenRequest(CoAP.Code.POST, RPC), FeatureType.RPC), + Arguments.of(toAccessTokenRequest(CoAP.Code.POST, CLAIM), FeatureType.CLAIM), + // certificate based tests + Arguments.of(toCertificateRequest(CoAP.Code.POST, TELEMETRY), FeatureType.TELEMETRY), + Arguments.of(toCertificateRequest(CoAP.Code.POST, ATTRIBUTES), FeatureType.ATTRIBUTES), + Arguments.of(toGetAttributesCertificateRequest(), FeatureType.ATTRIBUTES), + Arguments.of(toCertificateRequest(CoAP.Code.GET, ATTRIBUTES), FeatureType.ATTRIBUTES), + Arguments.of(toCertificateRequest(CoAP.Code.GET, RPC), FeatureType.RPC), + Arguments.of(toRpcResponseCertificateRequest(), FeatureType.RPC), + Arguments.of(toCertificateRequest(CoAP.Code.POST, RPC), FeatureType.RPC), + Arguments.of(toCertificateRequest(CoAP.Code.POST, CLAIM), FeatureType.CLAIM), + // provision request + Arguments.of(toProvisionRequest(), FeatureType.PROVISION) + ); } - @Test - void givenClaimingCertificateRequest_whenGetFeatureType_thenFeatureTypeClaim() { - // GIVEN - Request request = toCertificateRequest(CoAP.Code.POST, CLAIM); - - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.CLAIM, featureTypeOptional.get(), "Feature type is invalid"); - } - - // provision request - - @Test - void givenProvisionRequest_whenGetFeatureType_thenFeatureTypeProvision() { - // GIVEN - Request request = toCertificateRequest(CoAP.Code.POST, PROVISION); - // WHEN - var featureTypeOptional = coapTransportResource.getFeatureType(request); - - // THEN - assertTrue(featureTypeOptional.isPresent(), "Optional is empty"); - assertEquals(FeatureType.PROVISION, featureTypeOptional.get(), "Feature type is invalid"); - } - - private Request toAccessTokenRequest(CoAP.Code method, String featureType) { + private static Request toAccessTokenRequest(CoAP.Code method, String featureType) { return getAccessTokenRequest(method, featureType, null, null); } - private Request toGetAttributesAccessTokenRequest() { + private static Request toGetAttributesAccessTokenRequest() { return getAccessTokenRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); } - private Request toRpcResponseAccessTokenRequest() { + private static Request toRpcResponseAccessTokenRequest() { return getAccessTokenRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); } - private Request toCertificateRequest(CoAP.Code method, String featureType) { + private static Request toCertificateRequest(CoAP.Code method, String featureType) { return getCertificateRequest(method, featureType, null, null); } - private Request toGetAttributesCertificateRequest() { + private static Request toGetAttributesCertificateRequest() { return getCertificateRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); } - private Request toRpcResponseCertificateRequest() { + private static Request toRpcResponseCertificateRequest() { return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); } - private Request getAccessTokenRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + private static Request getAccessTokenRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { return getRequest(method, featureType, false, requestId, uriQuery); } - private Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { + private static Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { return getRequest(method, featureType, true, requestId, uriQuery); } - private Request getRequest(CoAP.Code method, String featureType, boolean dtls, Integer requestId, String uriQuery) { + private static Request toProvisionRequest() { + return getRequest(CoAP.Code.POST, PROVISION, true, null, null); + } + + private static Request getRequest(CoAP.Code method, String featureType, boolean dtls, Integer requestId, String uriQuery) { var request = new Request(method); var options = new OptionSet(); options.addUriPath(API); From 5f39e743ec338e1925c3a9926c4cd2d9a15421c4 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 14 Aug 2023 16:35:42 +0300 Subject: [PATCH 415/421] Update form.scss --- ui-ngx/src/form.scss | 3 --- 1 file changed, 3 deletions(-) diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 79f141e9d5..8bf8aef2ab 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -380,9 +380,6 @@ gap: 12px; padding-left: 12px; padding-right: 12px; - &.no-padding-right { - padding-right: 0; - } } &-cell { font-weight: 400; From ce06ea10cabefcfe8bdc5c00d87dc6e24bf53704 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Mon, 14 Aug 2023 17:43:39 +0300 Subject: [PATCH 416/421] Use user settings api instead of additionalInfo --- .../controller/NotificationController.java | 3 +- .../DefaultNotificationCenter.java | 2 +- .../TestNotificationSettingsService.java | 6 ++-- .../NotificationSettingsService.java | 3 +- .../data/settings/UserSettingsType.java | 2 +- .../DefaultNotificationSettingsService.java | 33 ++++++++++--------- 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java index 04cf3d440b..e57fb9ec00 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -448,8 +448,7 @@ public class NotificationController extends BaseController { @GetMapping("/notification/settings/user") @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") public UserNotificationSettings getUserNotificationSettings(@AuthenticationPrincipal SecurityUser user) { - return notificationSettingsService.getUserNotificationSettings(user.getTenantId(), - userService.findUserById(user.getTenantId(), user.getId()), true); + return notificationSettingsService.getUserNotificationSettings(user.getTenantId(), user.getId(), true); } } diff --git a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java index 21105950a4..042d5cbf00 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/DefaultNotificationCenter.java @@ -243,7 +243,7 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple } if (recipient instanceof User) { - UserNotificationSettings settings = notificationSettingsService.getUserNotificationSettings(ctx.getTenantId(), (User) recipient, false); + UserNotificationSettings settings = notificationSettingsService.getUserNotificationSettings(ctx.getTenantId(), ((User) recipient).getId(), false); if (!settings.isEnabled(ctx.getNotificationType(), deliveryMethod)) { throw new RuntimeException("User disabled " + deliveryMethod.getName() + " notifications of this type"); } diff --git a/application/src/test/java/org/thingsboard/server/service/notification/TestNotificationSettingsService.java b/application/src/test/java/org/thingsboard/server/service/notification/TestNotificationSettingsService.java index 3b21b35a73..9b4ced8567 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/TestNotificationSettingsService.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/TestNotificationSettingsService.java @@ -22,7 +22,7 @@ import org.thingsboard.server.dao.notification.DefaultNotificationSettingsServic import org.thingsboard.server.dao.notification.NotificationTargetService; import org.thingsboard.server.dao.notification.NotificationTemplateService; import org.thingsboard.server.dao.settings.AdminSettingsService; -import org.thingsboard.server.dao.user.UserService; +import org.thingsboard.server.dao.user.UserSettingsService; @Service @Primary @@ -31,8 +31,8 @@ public class TestNotificationSettingsService extends DefaultNotificationSettings public TestNotificationSettingsService(AdminSettingsService adminSettingsService, NotificationTargetService notificationTargetService, NotificationTemplateService notificationTemplateService, - UserService userService) { - super(adminSettingsService, notificationTargetService, notificationTemplateService, null, userService); + UserSettingsService userSettingsService) { + super(adminSettingsService, notificationTargetService, notificationTemplateService, null, userSettingsService); } @Override diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java index 5c956e6b70..9fca174b3a 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/notification/NotificationSettingsService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.notification; -import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.settings.NotificationSettings; @@ -29,7 +28,7 @@ public interface NotificationSettingsService { UserNotificationSettings saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings); - UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user, boolean format); + UserNotificationSettings getUserNotificationSettings(TenantId tenantId, UserId userId, boolean format); void createDefaultNotificationConfigs(TenantId tenantId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsType.java b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsType.java index b19dbbbaee..cd627821ac 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/settings/UserSettingsType.java @@ -19,7 +19,7 @@ import lombok.Getter; public enum UserSettingsType { - GENERAL, VISITED_DASHBOARDS(true), QUICK_LINKS, DOC_LINKS, DASHBOARDS, GETTING_STARTED; + GENERAL, VISITED_DASHBOARDS(true), QUICK_LINKS, DOC_LINKS, DASHBOARDS, GETTING_STARTED, NOTIFICATIONS; @Getter private final boolean reserved; diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java index 805cc31571..04ffc4762e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java @@ -15,8 +15,6 @@ */ package org.thingsboard.server.dao.notification; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; @@ -26,7 +24,6 @@ import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.CacheConstants; -import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.notification.NotificationType; @@ -44,8 +41,10 @@ import org.thingsboard.server.common.data.notification.targets.platform.TenantAd import org.thingsboard.server.common.data.notification.targets.platform.UsersFilter; import org.thingsboard.server.common.data.notification.targets.platform.UsersFilterType; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.settings.UserSettings; +import org.thingsboard.server.common.data.settings.UserSettingsType; import org.thingsboard.server.dao.settings.AdminSettingsService; -import org.thingsboard.server.dao.user.UserService; +import org.thingsboard.server.dao.user.UserSettingsService; import java.util.Collections; import java.util.EnumMap; @@ -62,10 +61,9 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS private final NotificationTargetService notificationTargetService; private final NotificationTemplateService notificationTemplateService; private final DefaultNotifications defaultNotifications; - private final UserService userService; + private final UserSettingsService userSettingsService; private static final String SETTINGS_KEY = "notifications"; - private static final String USER_SETTINGS_KEY = "notificationSettings"; @CacheEvict(cacheNames = CacheConstants.NOTIFICATION_SETTINGS_CACHE, key = "#tenantId") @Override @@ -95,20 +93,23 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS @Override public UserNotificationSettings saveUserNotificationSettings(TenantId tenantId, UserId userId, UserNotificationSettings settings) { - User user = userService.findUserById(tenantId, userId); - ObjectNode additionalInfo = (ObjectNode) Optional.ofNullable(user.getAdditionalInfo()).orElseGet(JacksonUtil::newObjectNode); - additionalInfo.set(USER_SETTINGS_KEY, JacksonUtil.valueToTree(settings)); - user.setAdditionalInfo(additionalInfo); - userService.saveUser(user); + UserSettings userSettings = new UserSettings(); + userSettings.setUserId(userId); + userSettings.setType(UserSettingsType.NOTIFICATIONS); + userSettings.setSettings(JacksonUtil.valueToTree(settings)); + userSettingsService.saveUserSettings(tenantId, userSettings); return formatUserNotificationSettings(settings); } @Override - public UserNotificationSettings getUserNotificationSettings(TenantId tenantId, User user, boolean format) { - UserNotificationSettings settings = Optional.ofNullable(user.getAdditionalInfo()) - .filter(JsonNode::isObject).map(info -> info.get(USER_SETTINGS_KEY)).filter(JsonNode::isObject) - .map(json -> JacksonUtil.treeToValue(json, UserNotificationSettings.class)) - .orElse(UserNotificationSettings.DEFAULT); + public UserNotificationSettings getUserNotificationSettings(TenantId tenantId, UserId userId, boolean format) { + UserSettings userSettings = userSettingsService.findUserSettings(tenantId, userId, UserSettingsType.NOTIFICATIONS); + UserNotificationSettings settings; + if (userSettings != null) { + settings = JacksonUtil.treeToValue(userSettings.getSettings(), UserNotificationSettings.class); + } else { + settings = UserNotificationSettings.DEFAULT; + } if (format) { settings = formatUserNotificationSettings(settings); } From a8f560203694523765a792c985c8f8ca6a70f590 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 15 Aug 2023 00:25:50 +0200 Subject: [PATCH 417/421] SQL partial index added idx_notification_recipient_id_unread for cheap and fast notification count on UI --- .../server/service/install/SqlDatabaseUpgradeService.java | 4 ++++ dao/src/main/resources/sql/schema-entities-idx.sql | 2 ++ 2 files changed, 6 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 34515f827d..2e2b3e96be 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -756,6 +756,10 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService conn.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_rule_node_type_configuration_version ON rule_node(type, configuration_version);"); } catch (Exception e) { } + try { + conn.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_unread ON notification(recipient_id) WHERE status <> 'READ';"); + } catch (Exception e) { + } conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3005002;"); } diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index 12e0bfddba..675fcd3ec0 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -113,3 +113,5 @@ CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_reque CREATE INDEX IF NOT EXISTS idx_notification_id ON notification(id); CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_created_time ON notification(recipient_id, created_time DESC); + +CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_unread ON notification(recipient_id) WHERE status <> 'READ'; From 3f2578b6d0416500319be402b3a9e20d7972bfef Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 15 Aug 2023 00:39:08 +0200 Subject: [PATCH 418/421] JpaNotificationDao: JavaDoc added for countUnreadByRecipientId for the reference to the idx_notification_recipient_id_unread --- .../server/dao/sql/notification/JpaNotificationDao.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java index 5fa156725d..3d24c6221f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java @@ -81,6 +81,9 @@ public class JpaNotificationDao extends JpaAbstractDao Date: Tue, 15 Aug 2023 16:52:35 +0300 Subject: [PATCH 419/421] UI: Aggregated value card widget --- ui-ngx/src/app/core/auth/auth.service.ts | 8 +- ui-ngx/src/app/core/utils.ts | 12 +- .../basic/basic-widget-config.module.ts | 18 +- .../aggregated-data-key-row.component.html | 94 ++++++ .../aggregated-data-key-row.component.scss | 88 ++++++ .../aggregated-data-key-row.component.ts | 229 ++++++++++++++ .../aggregated-data-keys-panel.component.html | 51 +++ .../aggregated-data-keys-panel.component.scss | 69 +++++ .../aggregated-data-keys-panel.component.ts | 173 +++++++++++ ...ted-value-card-basic-config.component.html | 136 ++++++++ ...gated-value-card-basic-config.component.ts | 291 ++++++++++++++++++ .../data-key-config-dialog.component.html | 1 + .../data-key-config-dialog.component.ts | 9 +- .../config/data-key-config.component.html | 2 +- .../config/data-key-config.component.ts | 13 +- .../widget/config/datasource.component.ts | 6 +- .../widget/config/datasources.component.ts | 4 + .../timewindow-style-panel.component.html | 5 + .../timewindow-style-panel.component.ts | 3 +- .../config/widget-config.component.models.ts | 59 +++- ...ggregated-value-card-widget.component.html | 90 ++++++ ...ggregated-value-card-widget.component.scss | 156 ++++++++++ .../aggregated-value-card-widget.component.ts | 260 ++++++++++++++++ .../lib/cards/aggregated-value-card.models.ts | 232 ++++++++++++++ .../cards/value-card-widget.component.html | 2 +- .../lib/entities-hierarchy-widget.models.ts | 2 +- .../widget/lib/flot-widget.models.ts | 1 + .../home/components/widget/lib/flot-widget.ts | 46 ++- ...ted-value-card-key-settings.component.html | 48 +++ ...gated-value-card-key-settings.component.ts | 64 ++++ .../chart/flot-widget-settings.component.ts | 3 +- .../common/color-settings.component.html | 2 +- .../common/color-settings.component.ts | 2 +- .../lib/settings/widget-settings.module.ts | 12 +- .../widget/widget-components.module.ts | 9 +- .../components/time/timewindow.component.ts | 10 +- .../shared/models/widget-settings.models.ts | 60 +++- .../assets/locale/locale.constant-en_US.json | 26 +- ui-ngx/src/form.scss | 27 +- 39 files changed, 2258 insertions(+), 65 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component.ts diff --git a/ui-ngx/src/app/core/auth/auth.service.ts b/ui-ngx/src/app/core/auth/auth.service.ts index f1af3b745a..8a838b4130 100644 --- a/ui-ngx/src/app/core/auth/auth.service.ts +++ b/ui-ngx/src/app/core/auth/auth.service.ts @@ -385,10 +385,10 @@ export class AuthService { } else if (authPayload.authUser) { authPayload.authUser.authority = Authority.ANONYMOUS; } - if (authPayload.authUser.isPublic) { + if (authPayload.authUser?.isPublic) { authPayload.forceFullscreen = true; } - if (authPayload.authUser.isPublic) { + if (authPayload.authUser?.isPublic) { this.loadSystemParams().subscribe( (sysParams) => { authPayload = {...authPayload, ...sysParams}; @@ -399,10 +399,10 @@ export class AuthService { loadUserSubject.error(err); } ); - } else if (authPayload.authUser.authority === Authority.PRE_VERIFICATION_TOKEN) { + } else if (authPayload.authUser?.authority === Authority.PRE_VERIFICATION_TOKEN) { loadUserSubject.next(authPayload); loadUserSubject.complete(); - } else if (authPayload.authUser.userId) { + } else if (authPayload.authUser?.userId) { this.userService.getUser(authPayload.authUser.userId).subscribe( (user) => { authPayload.userDetails = user; diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 2a2f664c3a..8d48c5f038 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -130,7 +130,7 @@ export function isLiteralObject(value: any) { return (!!value) && (value.constructor === Object); } -export function formatValue(value: any, dec?: number, units?: string, showZeroDecimals?: boolean): string | undefined { +export const formatValue = (value: any, dec?: number, units?: string, showZeroDecimals?: boolean): string | undefined => { if (isDefinedAndNotNull(value) && isNumeric(value) && (isDefinedAndNotNull(dec) || isDefinedAndNotNull(units) || Number(value).toString() === value)) { let formatted: string | number = Number(value); @@ -150,6 +150,16 @@ export function formatValue(value: any, dec?: number, units?: string, showZeroDe } } +export const formatNumberValue = (value: any, dec?: number): number | undefined => { + if (isDefinedAndNotNull(value) && isNumeric(value)) { + let formatted: string | number = Number(value); + if (isDefinedAndNotNull(dec)) { + formatted = formatted.toFixed(dec); + } + return Number(formatted); + } +} + export function objectValues(obj: any): any[] { return Object.keys(obj).map(e => obj[e]); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 795d46984c..7c4168a786 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -40,6 +40,15 @@ import { import { ValueCardBasicConfigComponent } from '@home/components/widget/config/basic/cards/value-card-basic-config.component'; +import { + AggregatedValueCardBasicConfigComponent +} from '@home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component'; +import { + AggregatedDataKeyRowComponent +} from '@home/components/widget/config/basic/cards/aggregated-data-key-row.component'; +import { + AggregatedDataKeysPanelComponent +} from '@home/components/widget/config/basic/cards/aggregated-data-keys-panel.component'; @NgModule({ declarations: [ @@ -50,6 +59,9 @@ import { FlotBasicConfigComponent, AlarmsTableBasicConfigComponent, ValueCardBasicConfigComponent, + AggregatedValueCardBasicConfigComponent, + AggregatedDataKeyRowComponent, + AggregatedDataKeysPanelComponent, DataKeyRowComponent, DataKeysPanelComponent ], @@ -66,6 +78,9 @@ import { FlotBasicConfigComponent, AlarmsTableBasicConfigComponent, ValueCardBasicConfigComponent, + AggregatedValueCardBasicConfigComponent, + AggregatedDataKeyRowComponent, + AggregatedDataKeysPanelComponent, DataKeyRowComponent, DataKeysPanelComponent ] @@ -79,5 +94,6 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type +
+ + + + {{ aggregatedValueCardKeyPositionTranslationMap.get(position) | translate }} + + + + + + +
+
+
+ +
+
+ +
+
+
+ +
+
+ + +
+
+ + + +
+
+ + +
+
+ + +
+
+ +
+
+ + + f() + + + + + + + + {{ (modelValue?.aggregationType || aggregationTypes.NONE) }} + ({{ 'datakey.latest-value' | translate }}) + + + ({{ 'datakey.delta' | translate }}:{{ (modelValue?.comparisonResultType === comparisonResultTypes.DELTA_PERCENT ? 'datakey.percent' : 'datakey.absolute') | translate }}) + ({{ 'datakey.delta-calculation-result-previous-value' | translate }}) + + diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.scss new file mode 100644 index 0000000000..e07b9fa9ad --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.scss @@ -0,0 +1,88 @@ +/** + * Copyright © 2016-2023 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-aggregated-data-key-row { + .mat-mdc-form-field.tb-inline-field.tb-aggregation-field { + .mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) { + padding-left: 8px; + padding-right: 0; + .mat-mdc-form-field-infix { + padding-top: 0; + padding-bottom: 6px; + .mdc-evolution-chip-set .mdc-evolution-chip { + margin: 0; + } + input.mat-mdc-chip-input { + height: 32px; + margin-left: 0; + } + } + } + .mat-mdc-chip.mat-mdc-standard-chip.tb-datakey-chip { + .tb-attribute-chip { + .tb-chip-labels { + background: transparent; + } + } + } + } + + .tb-position-field { + width: 132px; + min-width: 132px; + } + + .tb-aggregation-field { + flex: 1; + min-width: 150px; + } + + .tb-units-field, .tb-decimals-field, .tb-font-field, .tb-color-field { + display: flex; + flex-direction: row; + place-content: center; + align-items: center; + } + + .tb-units-field { + width: 80px; + min-width: 80px; + } + + .tb-decimals-field { + width: 60px; + min-width: 60px; + } + + .tb-font-field { + width: 40px; + min-width: 40px; + } + + .tb-color-field { + width: 40px; + min-width: 40px; + } + + .tb-units-field, .tb-decimals-field { + display: none; + @media #{$mat-gt-sm} { + display: block; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts new file mode 100644 index 0000000000..106412cab0 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts @@ -0,0 +1,229 @@ +/// +/// Copyright © 2016-2023 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, + EventEmitter, + forwardRef, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, + ViewEncapsulation +} from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { + ComparisonResultType, + DataKey, + DataKeyConfigMode, + DatasourceType, + widgetType +} from '@shared/models/widget.models'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { AggregationType } from '@shared/models/time/time.models'; +import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models'; +import { TranslateService } from '@ngx-translate/core'; +import { TruncatePipe } from '@shared/pipe/truncate.pipe'; +import { + DataKeyConfigDialogComponent, + DataKeyConfigDialogData +} from '@home/components/widget/config/data-key-config-dialog.component'; +import { deepClone, formatValue } from '@core/utils'; +import { + AggregatedValueCardKeyPosition, + aggregatedValueCardKeyPositionTranslations, + AggregatedValueCardKeySettings +} from '@home/components/widget/lib/cards/aggregated-value-card.models'; + +@Component({ + selector: 'tb-aggregated-data-key-row', + templateUrl: './aggregated-data-key-row.component.html', + styleUrls: ['./aggregated-data-key-row.component.scss', '../../data-keys.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => AggregatedDataKeyRowComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None +}) +export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnInit, OnChanges { + + aggregatedValueCardKeyPositions: AggregatedValueCardKeyPosition[] = + Object.keys(AggregatedValueCardKeyPosition).map(value => AggregatedValueCardKeyPosition[value]); + + aggregatedValueCardKeyPositionTranslationMap = aggregatedValueCardKeyPositionTranslations; + + dataKeyTypes = DataKeyType; + + aggregationTypes = AggregationType; + + comparisonResultTypes = ComparisonResultType; + + @Input() + disabled: boolean; + + @Input() + datasourceType: DatasourceType; + + @Input() + keyName: string; + + @Output() + keyRemoved = new EventEmitter(); + + keyRowFormGroup: UntypedFormGroup; + + modelValue: DataKey; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + get callbacks(): DataKeysCallbacks { + return this.widgetConfigComponent.widgetConfigCallbacks; + } + + get isEntityDatasource(): boolean { + return [DatasourceType.device, DatasourceType.entity].includes(this.datasourceType); + } + + private propagateChange = (_val: any) => {}; + + constructor(private fb: UntypedFormBuilder, + private dialog: MatDialog, + private cd: ChangeDetectorRef, + public translate: TranslateService, + public truncate: TruncatePipe, + private widgetConfigComponent: WidgetConfigComponent) { + } + + ngOnInit() { + this.keyRowFormGroup = this.fb.group({ + position: [null, []], + units: [null, []], + decimals: [null, []], + font: [null, []], + color: [null, []] + }); + this.keyRowFormGroup.valueChanges.subscribe( + () => this.updateModel() + ); + } + + ngOnChanges(changes: SimpleChanges): void { + for (const propName of Object.keys(changes)) { + const change = changes[propName]; + if (!change.firstChange && change.currentValue !== change.previousValue) { + if (['keyName'].includes(propName)) { + if (change.currentValue) { + this.modelValue.name = change.currentValue; + setTimeout(() => { + this.updateModel(); + }, 0); + } + } + } + } + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (isDisabled) { + this.keyRowFormGroup.disable({emitEvent: false}); + } else { + this.keyRowFormGroup.enable({emitEvent: false}); + } + } + + writeValue(value: DataKey): void { + this.modelValue = value || {} as DataKey; + const settings: AggregatedValueCardKeySettings = (this.modelValue.settings || {}); + this.keyRowFormGroup.patchValue( + { + position: settings.position || AggregatedValueCardKeyPosition.center, + units: value?.units, + decimals: value?.decimals, + font: settings.font, + color: settings.color + }, {emitEvent: false} + ); + this.cd.markForCheck(); + } + + dataKeyHasPostprocessing(): boolean { + return !!this.modelValue?.postFuncBody; + } + + editKey() { + this.dialog.open(DataKeyConfigDialogComponent, + { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + dataKey: deepClone(this.modelValue), + dataKeyConfigMode: DataKeyConfigMode.general, + dataKeySettingsSchema: null, + dataKeySettingsDirective: null, + dashboard: null, + aliasController: null, + widget: null, + widgetType: widgetType.latest, + deviceId: null, + entityAliasId: null, + showPostProcessing: true, + callbacks: this.callbacks, + hideDataKeyName: true, + hideDataKeyLabel: true, + hideDataKeyColor: true + } + }).afterClosed().subscribe((updatedDataKey) => { + if (updatedDataKey) { + this.modelValue = updatedDataKey; + this.keyRowFormGroup.get('units').patchValue(this.modelValue.units, {emitEvent: false}); + this.keyRowFormGroup.get('decimals').patchValue(this.modelValue.decimals, {emitEvent: false}); + this.updateModel(); + } + }); + } + + private updateModel() { + const value = this.keyRowFormGroup.value; + this.modelValue.settings = this.modelValue.settings || {}; + this.modelValue.settings.position = value.position; + this.modelValue.settings.font = value.font; + this.modelValue.settings.color = value.color; + this.modelValue.units = value.units; + this.modelValue.decimals = value.decimals; + this.propagateChange(this.modelValue); + } + + private _valuePreviewFn(): string { + const units: string = this.keyRowFormGroup.get('units').value; + const decimals: number = this.keyRowFormGroup.get('decimals').value; + return formatValue(22, decimals, units, true); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html new file mode 100644 index 0000000000..cee5b14dde --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html @@ -0,0 +1,51 @@ + +
+
{{ 'widgets.aggregated-value-card.values' | translate }}
+
+
+
widgets.aggregated-value-card.position
+
widgets.aggregated-value-card.aggregation
+
widget-config.units-short
+
widget-config.decimals-short
+
widgets.aggregated-value-card.font
+
widgets.aggregated-value-card.color
+
+
+
+
+ + +
+
+
+
+ +
+
+ + {{ 'widgets.aggregated-value-card.no-values' | translate }} + diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.scss new file mode 100644 index 0000000000..9280b98ff6 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.scss @@ -0,0 +1,69 @@ +/** + * Copyright © 2016-2023 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-aggregated-data-keys-panel { + .tb-form-table-header-cell { + &.tb-position-header { + width: 132px; + min-width: 132px; + } + + &.tb-aggregation-header { + flex: 1; + min-width: 150px; + } + + &.tb-units-header { + width: 80px; + min-width: 80px; + } + + &.tb-decimals-header { + width: 60px; + min-width: 60px; + } + + &.tb-font-header { + width: 40px; + min-width: 40px; + } + + &.tb-color-header { + width: 40px; + min-width: 40px; + } + + &.tb-actions-header { + width: 40px; + min-width: 40px; + } + + &.tb-units-header, &.tb-decimals-header { + display: none; + @media #{$mat-gt-sm} { + display: block; + } + } + } + .tb-form-table-body { + tb-aggregated-data-key-row { + overflow: hidden; + } + } +} + diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.ts new file mode 100644 index 0000000000..d8b7f07f92 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.ts @@ -0,0 +1,173 @@ +/// +/// Copyright © 2016-2023 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, + OnChanges, + OnInit, + SimpleChanges, + ViewEncapsulation +} from '@angular/core'; +import { + AbstractControl, + ControlValueAccessor, + NG_VALUE_ACCESSOR, + UntypedFormArray, + UntypedFormBuilder, + UntypedFormGroup +} from '@angular/forms'; +import { MatDialog } from '@angular/material/dialog'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKey, DatasourceType, widgetType } from '@shared/models/widget.models'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { UtilsService } from '@core/services/utils.service'; +import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models'; +import { aggregatedValueCardDefaultKeySettings } from '@home/components/widget/lib/cards/aggregated-value-card.models'; + +@Component({ + selector: 'tb-aggregated-data-keys-panel', + templateUrl: './aggregated-data-keys-panel.component.html', + styleUrls: ['./aggregated-data-keys-panel.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => AggregatedDataKeysPanelComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None +}) +export class AggregatedDataKeysPanelComponent implements ControlValueAccessor, OnInit, OnChanges { + + @Input() + disabled: boolean; + + @Input() + datasourceType: DatasourceType; + + @Input() + keyName: string; + + dataKeyType: DataKeyType; + + keysListFormGroup: UntypedFormGroup; + + get widgetType(): widgetType { + return this.widgetConfigComponent.widgetType; + } + + get callbacks(): DataKeysCallbacks { + return this.widgetConfigComponent.widgetConfigCallbacks; + } + + get noKeys(): boolean { + const keys: DataKey[] = this.keysListFormGroup.get('keys').value; + return keys.length === 0; + } + + private propagateChange = (_val: any) => {}; + + constructor(private fb: UntypedFormBuilder, + private dialog: MatDialog, + private cd: ChangeDetectorRef, + private utils: UtilsService, + private widgetConfigComponent: WidgetConfigComponent) { + } + + ngOnInit() { + this.keysListFormGroup = this.fb.group({ + keys: [this.fb.array([]), []] + }); + this.keysListFormGroup.valueChanges.subscribe( + (val) => this.propagateChange(this.keysListFormGroup.get('keys').value) + ); + this.updateParams(); + } + + ngOnChanges(changes: SimpleChanges): void { + for (const propName of Object.keys(changes)) { + const change = changes[propName]; + if (!change.firstChange && change.currentValue !== change.previousValue) { + if (['datasourceType'].includes(propName)) { + this.updateParams(); + } + } + } + } + + private updateParams() { + if (this.datasourceType === DatasourceType.function) { + this.dataKeyType = DataKeyType.function; + } else { + this.dataKeyType = DataKeyType.timeseries; + } + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (isDisabled) { + this.keysListFormGroup.disable({emitEvent: false}); + } else { + this.keysListFormGroup.enable({emitEvent: false}); + } + } + + writeValue(value: DataKey[] | undefined): void { + this.keysListFormGroup.setControl('keys', this.prepareKeysFormArray(value), {emitEvent: false}); + } + + keysFormArray(): UntypedFormArray { + return this.keysListFormGroup.get('keys') as UntypedFormArray; + } + + trackByKey(index: number, keyControl: AbstractControl): any { + return keyControl; + } + + removeKey(index: number) { + (this.keysListFormGroup.get('keys') as UntypedFormArray).removeAt(index); + } + + addKey() { + const dataKey = this.callbacks.generateDataKey(this.keyName, this.dataKeyType, null); + dataKey.decimals = 0; + dataKey.settings = {...aggregatedValueCardDefaultKeySettings}; + const keysArray = this.keysListFormGroup.get('keys') as UntypedFormArray; + const keyControl = this.fb.control(dataKey, []); + keysArray.push(keyControl); + } + + private prepareKeysFormArray(keys: DataKey[] | undefined): UntypedFormArray { + const keysControls: Array = []; + if (keys) { + keys.forEach((key) => { + keysControls.push(this.fb.control(key, [])); + }); + } + return this.fb.array(keysControls); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.html new file mode 100644 index 0000000000..4c2742173b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.html @@ -0,0 +1,136 @@ + + + + + + +
+
widget-config.appearance
+
+ + {{ 'widget-config.title' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widgets.value-card.icon' | translate }} + +
+ + + + + + + + +
+
+
+ + {{ 'widgets.aggregated-value-card.subtitle' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widgets.value-card.date' | translate }} + +
+ + + + + +
+
+
+ + {{ 'widgets.aggregated-value-card.chart' | translate }} + + + +
+
+ + +
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts new file mode 100644 index 0000000000..65003ebb03 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts @@ -0,0 +1,291 @@ +/// +/// Copyright © 2016-2023 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, Injector } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DataKey, Datasource, WidgetConfig, } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; +import { isUndefined } from '@core/utils'; +import { + cssSizeToStrSize, + DateFormatProcessor, + DateFormatSettings, getDataKey, + resolveCssSize +} from '@shared/models/widget-settings.models'; +import { + aggregatedValueCardDefaultSettings, + AggregatedValueCardWidgetSettings, + createDefaultAggregatedValueLatestDataKeys +} from '@home/components/widget/lib/cards/aggregated-value-card.models'; +import { + AggregationType, + HistoryWindowType, + HOUR, + QuickTimeInterval, + TimewindowType +} from '@shared/models/time/time.models'; + +@Component({ + selector: 'tb-aggregated-value-card-basic-config', + templateUrl: './aggregated-value-card-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigComponent { + + public get datasource(): Datasource { + const datasources: Datasource[] = this.aggregatedValueCardWidgetConfigForm.get('datasources').value; + if (datasources && datasources.length) { + return datasources[0]; + } else { + return null; + } + } + + public get keyName(): string { + const dataKey = getDataKey(this.aggregatedValueCardWidgetConfigForm.get('datasources').value); + if (dataKey) { + return dataKey.name; + } else { + return null; + } + } + + aggregatedValueCardWidgetConfigForm: UntypedFormGroup; + + datePreviewFn = this._datePreviewFn.bind(this); + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private cd: ChangeDetectorRef, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.aggregatedValueCardWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + this.setupDefaultDatasource(configData, [ + { name: 'watermeter', label: 'Watermeter', type: DataKeyType.timeseries } + ], + createDefaultAggregatedValueLatestDataKeys('watermeter', 'm³') + ); + configData.config.useDashboardTimewindow = false; + configData.config.displayTimewindow = true; + configData.config.timewindow = { + selectedTab: TimewindowType.HISTORY, + history: { + historyType: HistoryWindowType.INTERVAL, + quickInterval: QuickTimeInterval.CURRENT_MONTH_SO_FAR, + }, + aggregation: { + type: AggregationType.AVG, + interval: 12 * HOUR, + limit: 5000 + } + }; + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: AggregatedValueCardWidgetSettings = {...aggregatedValueCardDefaultSettings, ...(configData.config.settings || {})}; + const iconSize = resolveCssSize(configData.config.iconSize); + this.aggregatedValueCardWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + datasources: [configData.config.datasources, []], + + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], + + showIcon: [configData.config.showTitleIcon, []], + iconSize: [iconSize[0], [Validators.min(0)]], + iconSizeUnit: [iconSize[1], []], + icon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + + showSubtitle: [settings.showSubtitle, []], + subtitle: [settings.subtitle, []], + subtitleFont: [settings.subtitleFont, []], + subtitleColor: [settings.subtitleColor, []], + + showDate: [settings.showDate, []], + dateFormat: [settings.dateFormat, []], + dateFont: [settings.dateFont, []], + dateColor: [settings.dateColor, []], + + showChart: [settings.showChart, []], + chartColor: [settings.chartColor, []], + + values: [this.getValues(configData.config.datasources), []], + + background: [settings.background, []], + + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); + this.widgetConfig.config.datasources = config.datasources; + + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.title = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; + + this.widgetConfig.config.showTitleIcon = config.showIcon; + this.widgetConfig.config.iconSize = cssSizeToStrSize(config.iconSize, config.iconSizeUnit); + this.widgetConfig.config.titleIcon = config.icon; + this.widgetConfig.config.iconColor = config.iconColor; + + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + + this.widgetConfig.config.settings.showSubtitle = config.showSubtitle; + this.widgetConfig.config.settings.subtitle = config.subtitle; + this.widgetConfig.config.settings.subtitleFont = config.subtitleFont; + this.widgetConfig.config.settings.subtitleColor = config.subtitleColor; + + this.widgetConfig.config.settings.showDate = config.showDate; + this.widgetConfig.config.settings.dateFormat = config.dateFormat; + this.widgetConfig.config.settings.dateFont = config.dateFont; + this.widgetConfig.config.settings.dateColor = config.dateColor; + + this.widgetConfig.config.settings.showChart = config.showChart; + this.widgetConfig.config.settings.chartColor = config.chartColor; + + this.setValues(config.values, this.widgetConfig.config.datasources); + + this.widgetConfig.config.settings.background = config.background; + + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showIcon', 'showSubtitle', 'showDate', 'showChart']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.aggregatedValueCardWidgetConfigForm.get('showTitle').value; + const showIcon: boolean = this.aggregatedValueCardWidgetConfigForm.get('showIcon').value; + const showSubtitle: boolean = this.aggregatedValueCardWidgetConfigForm.get('showSubtitle').value; + const showDate: boolean = this.aggregatedValueCardWidgetConfigForm.get('showDate').value; + const showChart: boolean = this.aggregatedValueCardWidgetConfigForm.get('showChart').value; + + if (showTitle) { + this.aggregatedValueCardWidgetConfigForm.get('title').enable(); + this.aggregatedValueCardWidgetConfigForm.get('titleFont').enable(); + this.aggregatedValueCardWidgetConfigForm.get('titleColor').enable(); + this.aggregatedValueCardWidgetConfigForm.get('showIcon').enable({emitEvent: false}); + if (showIcon) { + this.aggregatedValueCardWidgetConfigForm.get('iconSize').enable(); + this.aggregatedValueCardWidgetConfigForm.get('iconSizeUnit').enable(); + this.aggregatedValueCardWidgetConfigForm.get('icon').enable(); + this.aggregatedValueCardWidgetConfigForm.get('iconColor').enable(); + } else { + this.aggregatedValueCardWidgetConfigForm.get('iconSize').disable(); + this.aggregatedValueCardWidgetConfigForm.get('iconSizeUnit').disable(); + this.aggregatedValueCardWidgetConfigForm.get('icon').disable(); + this.aggregatedValueCardWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.aggregatedValueCardWidgetConfigForm.get('title').disable(); + this.aggregatedValueCardWidgetConfigForm.get('titleFont').disable(); + this.aggregatedValueCardWidgetConfigForm.get('titleColor').disable(); + this.aggregatedValueCardWidgetConfigForm.get('showIcon').disable({emitEvent: false}); + this.aggregatedValueCardWidgetConfigForm.get('iconSize').disable(); + this.aggregatedValueCardWidgetConfigForm.get('iconSizeUnit').disable(); + this.aggregatedValueCardWidgetConfigForm.get('icon').disable(); + this.aggregatedValueCardWidgetConfigForm.get('iconColor').disable(); + } + + if (showSubtitle) { + this.aggregatedValueCardWidgetConfigForm.get('subtitle').enable(); + this.aggregatedValueCardWidgetConfigForm.get('subtitleFont').enable(); + this.aggregatedValueCardWidgetConfigForm.get('subtitleColor').enable(); + } else { + this.aggregatedValueCardWidgetConfigForm.get('subtitle').disable(); + this.aggregatedValueCardWidgetConfigForm.get('subtitleFont').disable(); + this.aggregatedValueCardWidgetConfigForm.get('subtitleColor').disable(); + } + + if (showDate) { + this.aggregatedValueCardWidgetConfigForm.get('dateFormat').enable(); + this.aggregatedValueCardWidgetConfigForm.get('dateFont').enable(); + this.aggregatedValueCardWidgetConfigForm.get('dateColor').enable(); + } else { + this.aggregatedValueCardWidgetConfigForm.get('dateFormat').disable(); + this.aggregatedValueCardWidgetConfigForm.get('dateFont').disable(); + this.aggregatedValueCardWidgetConfigForm.get('dateColor').disable(); + } + + if (showChart) { + this.aggregatedValueCardWidgetConfigForm.get('chartColor').enable(); + } else { + this.aggregatedValueCardWidgetConfigForm.get('chartColor').disable(); + } + } + + private getValues(datasources?: Datasource[]): DataKey[] { + if (datasources && datasources.length) { + return datasources[0].latestDataKeys || []; + } + return []; + } + + private setValues(values: DataKey[], datasources?: Datasource[]) { + if (datasources && datasources.length) { + datasources[0].latestDataKeys = values; + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + + private _datePreviewFn(): string { + const dateFormat: DateFormatSettings = this.aggregatedValueCardWidgetConfigForm.get('dateFormat').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/config/data-key-config-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.html index 19ad94d76d..68ef7e4c63 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.html @@ -45,6 +45,7 @@ [widgetType]="data.widgetType" [showPostProcessing]="data.showPostProcessing" [callbacks]="data.callbacks" + [hideDataKeyName]="data.hideDataKeyName" [hideDataKeyLabel]="data.hideDataKeyLabel" [hideDataKeyColor]="data.hideDataKeyColor" [hideDataKeyUnits]="data.hideDataKeyUnits" diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.ts index 2b3f67a296..f98fb097a0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config-dialog.component.ts @@ -50,10 +50,11 @@ export interface DataKeyConfigDialogData { entityAliasId?: string; showPostProcessing?: boolean; callbacks?: DataKeysCallbacks; - hideDataKeyLabel: boolean; - hideDataKeyColor: boolean; - hideDataKeyUnits: boolean; - hideDataKeyDecimals: boolean; + hideDataKeyName?: boolean; + hideDataKeyLabel?: boolean; + hideDataKeyColor?: boolean; + hideDataKeyUnits?: boolean; + hideDataKeyDecimals?: boolean; } @Component({ diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html index 4a4a2c4d90..e265ea01d3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-key-config.component.html @@ -20,7 +20,7 @@
datakey.general
- + {{ 'entity.key' | translate }}
+
+ + {{ 'timewindow.displayTypePrefix' | translate }} + +
timewindow.preview
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts index e0e4ee5615..85e7e5a4be 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-style-panel.component.ts @@ -63,7 +63,8 @@ export class TimewindowStylePanelComponent extends PageComponent implements OnIn icon: [computedTimewindowStyle.icon, []], iconPosition: [computedTimewindowStyle.iconPosition, []], font: [computedTimewindowStyle.font, []], - color: [computedTimewindowStyle.color, []] + color: [computedTimewindowStyle.color, []], + displayTypePrefix: [computedTimewindowStyle.displayTypePrefix, []] } ); this.updatePreviewStyle(this.timewindowStyle); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts index 9bda9345dc..fb5dd252b6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts @@ -119,7 +119,7 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement return this.configForm().valid; } - protected setupDefaultDatasource(configData: WidgetConfigComponentData, keys?: DataKey[]) { + protected setupDefaultDatasource(configData: WidgetConfigComponentData, keys?: DataKey[], latestKeys?: DataKey[]) { let datasources = configData.config.datasources; if (!datasources || !datasources.length) { datasources = [ @@ -135,23 +135,58 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement dataKeys = []; datasources[0].dataKeys = dataKeys; } + let latestDataKeys = datasources[0].latestDataKeys; + if (!latestDataKeys) { + latestDataKeys = []; + datasources[0].latestDataKeys = latestDataKeys; + } if (keys && keys.length) { dataKeys.length = 0; keys.forEach(key => { - const dataKey = - this.widgetConfigComponent.widgetConfigCallbacks.generateDataKey(key.name, key.type, configData.dataKeySettingsSchema); - if (key.label) { - dataKey.label = key.label; - } - if (key.units) { - dataKey.units = key.units; - } - if (isDefinedAndNotNull(key.decimals)) { - dataKey.decimals = key.decimals; - } + const dataKey = this.constructDataKey(configData, key); dataKeys.push(dataKey); }); } + if (latestKeys && latestKeys.length) { + latestDataKeys.length = 0; + latestKeys.forEach(key => { + const dataKey = this.constructDataKey(configData, key); + latestDataKeys.push(dataKey); + }); + } + } + + protected constructDataKey(configData: WidgetConfigComponentData, key: DataKey): DataKey { + const dataKey = + this.widgetConfigComponent.widgetConfigCallbacks.generateDataKey(key.name, key.type, configData.dataKeySettingsSchema); + if (key.label) { + dataKey.label = key.label; + } + if (key.units) { + dataKey.units = key.units; + } + if (isDefinedAndNotNull(key.decimals)) { + dataKey.decimals = key.decimals; + } + if (isDefinedAndNotNull(key.settings)) { + dataKey.settings = key.settings; + } + if (isDefinedAndNotNull(key.aggregationType)) { + dataKey.aggregationType = key.aggregationType; + } + if (isDefinedAndNotNull(key.comparisonEnabled)) { + dataKey.comparisonEnabled = key.comparisonEnabled; + } + if (isDefinedAndNotNull(key.timeForComparison)) { + dataKey.timeForComparison = key.timeForComparison; + } + if (isDefinedAndNotNull(key.comparisonCustomIntervalValue)) { + dataKey.comparisonCustomIntervalValue = key.comparisonCustomIntervalValue; + } + if (isDefinedAndNotNull(key.comparisonResultType)) { + dataKey.comparisonResultType = key.comparisonResultType; + } + return dataKey; } protected abstract configForm(): UntypedFormGroup; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.html new file mode 100644 index 0000000000..b20431fa64 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.html @@ -0,0 +1,90 @@ + +
+
+
+ + +
+ + + +
+ + +
{{ subtitle$ | async }}
+
+ +
+
+
+ + + + + + +
+
+ + + +
+
+ + + + + + +
+
+
+
+ +
+
+
{{tickMax$ | async}}
+
{{tickMin$ | async}}
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+ + arrow_upward + arrow_downward +
+
+ {{ value.value }} + {{ value.units }} +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.scss new file mode 100644 index 0000000000..6dee828c36 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.scss @@ -0,0 +1,156 @@ +/** + * Copyright © 2016-2023 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-aggregated-value-card-panel { + width: 100%; + height: 100%; + position: relative; + display: flex; + flex-direction: column; + align-items: stretch; + gap: 8px; + padding: 20px 24px 24px; + > div:not(.tb-value-card-overlay) { + z-index: 1; + } + .tb-aggregated-value-card-overlay { + position: absolute; + top: 12px; + left: 12px; + bottom: 12px; + right: 12px; + } + > div.tb-aggregated-value-card-title-panel { + display: flex; + flex-direction: column; + .tb-aggregated-value-card-subtitle { + margin-left: 28px; + } + } + .tb-aggregated-value-card-values, .tb-aggregated-value-card-chart { + flex: 1; + min-height: 0; + overflow: hidden; + } + .tb-aggregated-value-card-values-container { + width: 100%; + height: 100%; + padding: 8px 0; + display: grid; + grid-template-columns: minmax(0, 1fr) fit-content(100%) minmax(0, 1fr); + .tb-aggregated-value-card-values-section { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + &.left { + align-items: flex-start; + } + &.center { + align-items: center; + } + &.right { + align-items: flex-end; + } + } + } + .tb-aggregated-value-card-chart { + display: flex; + gap: 8px; + flex-direction: row; + .tb-aggregated-value-card-chart-ticks { + height: 100%; + display: flex; + flex-direction: column; + place-content: flex-end space-between; + align-items: flex-end; + font-size: 11px; + line-height: 16px; + font-weight: 400; + color: rgba(0, 0, 0, 0.38); + } + .tb-aggregated-value-card-chart-container { + position: relative; + flex: 1; + margin-top: 8px; + margin-bottom: 8px; + .tb-aggregated-value-card-chart-element { + width: 100%; + height: 100%; + } + .tb-aggregated-value-card-chart-boundary { + position: absolute; + width: 6px; + height: 6px; + &.top { + top: 0; + border-top: 2px solid rgba(0,0,0,0.38); + } + &.left { + left: 0; + border-left: 2px solid rgba(0,0,0,0.38); + } + &.right { + right: 0; + border-right: 2px solid rgba(0,0,0,0.38); + } + &.bottom { + bottom: 0; + border-bottom: 2px solid rgba(0,0,0,0.38); + } + } + } + } + .tb-aggregated-value-card-value { + white-space: nowrap; + min-height: 0; + display: flex; + flex-direction: row; + place-content: center; + align-items: center; + .value-arrow-container { + display: flex; + } + .value-text { + line-height: 1; + } + .value-arrow { + font-size: 1.1em; + height: 1.1em; + line-height: 1.1em; + min-width: 1em; + width: 1em; + } + .units { + font-size: 85%; + padding-left: 0.2em; + &.small { + font-size: 50%; + } + } + } + } +} + +:host ::ng-deep { + .tb-aggregated-value-card-panel { + > div.tb-aggregated-value-card-title-panel { + .tb-widget-title { + padding: 0; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts new file mode 100644 index 0000000000..95f605e7be --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts @@ -0,0 +1,260 @@ +/// +/// Copyright © 2016-2023 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 { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + Input, + OnInit, + TemplateRef, + ViewChild +} from '@angular/core'; +import { + aggregatedValueCardDefaultSettings, + AggregatedValueCardKeyPosition, + AggregatedValueCardValue, + AggregatedValueCardWidgetSettings, + computeAggregatedCardValue, + getTsValueByLatestDataKey +} from '@home/components/widget/lib/cards/aggregated-value-card.models'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { Observable } from 'rxjs'; +import { + backgroundStyle, + ColorProcessor, + ComponentStyle, + DateFormatProcessor, getDataKey, + getLatestSingleTsValue, + overlayStyle, + textStyle +} from '@shared/models/widget-settings.models'; +import { DatePipe } from '@angular/common'; +import { TbFlot } from '@home/components/widget/lib/flot-widget'; +import { TbFlotKeySettings, TbFlotSettings } from '@home/components/widget/lib/flot-widget.models'; +import { DataKey } from '@shared/models/widget.models'; +import { formatNumberValue, formatValue, isDefined, isNumeric } from '@core/utils'; +import { map } from 'rxjs/operators'; + +@Component({ + selector: 'tb-aggregated-value-card-widget', + templateUrl: './aggregated-value-card-widget.component.html', + styleUrls: ['./aggregated-value-card-widget.component.scss'] +}) +export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit { + + @ViewChild('chartElement', {static: false}) chartElement: ElementRef; + + aggregatedValueCardKeyPosition = AggregatedValueCardKeyPosition; + + settings: AggregatedValueCardWidgetSettings; + + @Input() + ctx: WidgetContext; + + @Input() + widgetTitlePanel: TemplateRef; + + showSubtitle = true; + subtitle$: Observable; + subtitleStyle: ComponentStyle = {}; + subtitleColor: ColorProcessor; + + showValues = false; + + values: {[key: string]: AggregatedValueCardValue} = {}; + + showChart = true; + chartColor: ColorProcessor; + + showDate = true; + dateFormat: DateFormatProcessor; + dateStyle: ComponentStyle = {}; + dateColor: ColorProcessor; + + backgroundStyle: ComponentStyle = {}; + overlayStyle: ComponentStyle = {}; + + private flot: TbFlot; + private flotDataKey: DataKey; + + private lastUpdateTs: number; + + tickMin$: Observable; + tickMax$: Observable; + + constructor(private date: DatePipe, + private cd: ChangeDetectorRef) { + } + + ngOnInit(): void { + this.ctx.$scope.aggregatedValueCardWidget = this; + this.settings = {...aggregatedValueCardDefaultSettings, ...this.ctx.settings}; + this.showSubtitle = this.settings.showSubtitle; + const subtitle = this.settings.subtitle; + this.subtitle$ = this.ctx.registerLabelPattern(subtitle, this.subtitle$); + this.subtitleStyle = textStyle(this.settings.subtitleFont, '0.25px'); + this.subtitleColor = ColorProcessor.fromSettings(this.settings.subtitleColor); + + const dataKey = getDataKey(this.ctx.defaultSubscription.datasources); + if (dataKey?.name && this.ctx.defaultSubscription.firstDatasource?.latestDataKeys?.length) { + const dataKeys = this.ctx.defaultSubscription.firstDatasource?.latestDataKeys; + for (const position of Object.keys(AggregatedValueCardKeyPosition)) { + const value = computeAggregatedCardValue(dataKeys, dataKey?.name, AggregatedValueCardKeyPosition[position]); + if (value) { + this.values[position] = value; + } + } + this.showValues = !!Object.keys(this.values).length; + } + + this.showChart = this.settings.showChart; + this.chartColor = ColorProcessor.fromSettings(this.settings.chartColor); + if (this.showChart) { + if (this.ctx.defaultSubscription.firstDatasource?.dataKeys?.length) { + this.flotDataKey = this.ctx.defaultSubscription.firstDatasource?.dataKeys[0]; + this.flotDataKey.settings = { + fillLines: false, + showLines: true, + lineWidth: 2 + } as TbFlotKeySettings; + this.flotDataKey.color = this.chartColor.color; + } + } + + this.showDate = this.settings.showDate; + this.dateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.dateFormat); + this.dateStyle = textStyle(this.settings.dateFont, '0.25px'); + this.dateColor = ColorProcessor.fromSettings(this.settings.dateColor); + + this.backgroundStyle = backgroundStyle(this.settings.background); + this.overlayStyle = overlayStyle(this.settings.background.overlay); + } + + ngAfterViewInit(): void { + if (this.showChart) { + const settings = { + shadowSize: 0, + smoothLines: false, + grid: { + tickColor: 'rgba(0,0,0,0.12)', + horizontalLines: true, + verticalLines: false, + outlineWidth: 0, + minBorderMargin: 0, + margin: 0 + }, + yaxis: { + showLabels: false, + tickGenerator: 'return [(axis.max + axis.min) / 2];' + }, + xaxis: { + showLabels: false + } + } as TbFlotSettings; + this.flot = new TbFlot(this.ctx, 'line', $(this.chartElement.nativeElement), settings); + this.tickMin$ = this.flot.yMin$.pipe( + map((value) => formatValue(value, (this.flotDataKey?.decimals || this.ctx.decimals), + (this.flotDataKey?.units || this.ctx.units)) + )); + this.tickMax$ = this.flot.yMax$.pipe( + map((value) => formatValue(value, (this.flotDataKey?.decimals || this.ctx.decimals), + (this.flotDataKey?.units || this.ctx.units)) + )); + } + } + + public onInit() { + const borderRadius = this.ctx.$widgetElement.css('borderRadius'); + this.overlayStyle = {...this.overlayStyle, ...{borderRadius}}; + this.cd.detectChanges(); + } + + public onDataUpdated() { + const tsValue = getLatestSingleTsValue(this.ctx.data); + let ts; + let value; + if (tsValue) { + ts = tsValue[0]; + value = tsValue[1]; + } + this.subtitleColor.update(value); + this.dateColor.update(value); + + if (this.showChart) { + this.chartColor.update(value); + this.flot.updateSeriesColor(this.chartColor.color); + this.flot.update(); + } + + this.updateLastUpdateTs(ts); + this.cd.detectChanges(); + } + + public onLatestDataUpdated() { + if (this.showValues) { + for (const aggValue of Object.values(this.values)) { + const tsValue = getTsValueByLatestDataKey(this.ctx.latestData, aggValue.key); + let ts; + let value; + if (tsValue) { + ts = tsValue[0]; + value = tsValue[1]; + aggValue.value = formatValue(value, (aggValue.key.decimals || this.ctx.decimals), null, false); + } else { + aggValue.value = 'N/A'; + } + const numeric = formatNumberValue(value, (aggValue.key.decimals || this.ctx.decimals)); + aggValue.color.update(numeric); + if (aggValue.showArrow && isDefined(numeric)) { + aggValue.upArrow = numeric > 0; + aggValue.downArrow = numeric < 0; + } else { + aggValue.upArrow = aggValue.downArrow = false; + } + this.updateLastUpdateTs(ts); + } + this.cd.detectChanges(); + } + } + + public onResize() { + if (this.showChart) { + this.flot.resize(); + } + } + + public onEditModeChanged() { + if (this.showChart) { + this.flot.checkMouseEvents(); + } + } + + public onDestroy() { + if (this.showChart) { + this.flot.destroy(); + } + } + + private updateLastUpdateTs(ts: number) { + if (ts && (!this.lastUpdateTs || ts > this.lastUpdateTs)) { + this.lastUpdateTs = ts; + this.dateFormat.update(ts); + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts new file mode 100644 index 0000000000..273ca1edaa --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts @@ -0,0 +1,232 @@ +/// +/// Copyright © 2016-2023 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 { + BackgroundSettings, + BackgroundType, + ColorProcessor, + ColorSettings, + ColorType, + ComponentStyle, + constantColor, + DateFormatSettings, + Font, + iconStyle, + lastUpdateAgoDateFormat, + textStyle +} from '@shared/models/widget-settings.models'; +import { ComparisonResultType, DataKey, DatasourceData } from '@shared/models/widget.models'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { AggregationType } from '@shared/models/time/time.models'; + +export interface AggregatedValueCardWidgetSettings { + showSubtitle: boolean; + subtitle: string; + subtitleFont: Font; + subtitleColor: ColorSettings; + showDate: boolean; + dateFormat: DateFormatSettings; + dateFont: Font; + dateColor: ColorSettings; + showChart: boolean; + chartColor: ColorSettings; + background: BackgroundSettings; +} + +export enum AggregatedValueCardKeyPosition { + center = 'center', + rightTop = 'rightTop', + rightBottom = 'rightBottom', + leftTop = 'leftTop', + leftBottom = 'leftBottom' +} + +export const aggregatedValueCardKeyPositionTranslations = new Map( + [ + [AggregatedValueCardKeyPosition.center, 'widgets.aggregated-value-card.position-center'], + [AggregatedValueCardKeyPosition.rightTop, 'widgets.aggregated-value-card.position-right-top'], + [AggregatedValueCardKeyPosition.rightBottom, 'widgets.aggregated-value-card.position-right-bottom'], + [AggregatedValueCardKeyPosition.leftTop, 'widgets.aggregated-value-card.position-left-top'], + [AggregatedValueCardKeyPosition.leftBottom, 'widgets.aggregated-value-card.position-left-bottom'] + ] +); + +export interface AggregatedValueCardKeySettings { + position: AggregatedValueCardKeyPosition; + font: Font; + color: ColorSettings; + showArrow: boolean; +} + +export interface AggregatedValueCardValue { + key: DataKey; + value: string; + units: string; + style: ComponentStyle; + color: ColorProcessor; + center: boolean; + showArrow: boolean; + upArrow: boolean; + downArrow: boolean; +} + +export const computeAggregatedCardValue = (dataKeys: DataKey[], keyName: string, position: AggregatedValueCardKeyPosition): AggregatedValueCardValue => { + const key = dataKeys.find(dataKey => ( dataKey.name === keyName && (dataKey.settings?.position === position || + (!dataKey.settings?.position && position === AggregatedValueCardKeyPosition.center)) )); + if (key) { + const settings: AggregatedValueCardKeySettings = key.settings; + return { + key, + value: '', + units: key.units, + style: textStyle(settings.font, '0.25px'), + color: ColorProcessor.fromSettings(settings.color), + center: position === AggregatedValueCardKeyPosition.center, + showArrow: settings.showArrow, + upArrow: false, + downArrow: false + }; + } +}; + +export const getTsValueByLatestDataKey = (latestData: Array, dataKey: DataKey): [number, any] => { + if (latestData?.length) { + const dsData = latestData.find(data => data.dataKey === dataKey); + if (dsData?.data?.length) { + return dsData.data[0]; + } + } + return null; +}; + +export const aggregatedValueCardDefaultSettings: AggregatedValueCardWidgetSettings = { + showSubtitle: true, + subtitle: '${entityName}', + subtitleFont: { + family: 'Roboto', + size: 12, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '16px' + }, + subtitleColor: constantColor('rgba(0, 0, 0, 0.38)'), + showDate: true, + dateFormat: lastUpdateAgoDateFormat(), + dateFont: { + family: 'Roboto', + size: 12, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '16px' + }, + dateColor: constantColor('rgba(0, 0, 0, 0.38)'), + showChart: true, + chartColor: constantColor('rgba(0, 0, 0, 0.87)'), + background: { + type: BackgroundType.color, + color: '#fff', + overlay: { + enabled: false, + color: 'rgba(255,255,255,0.72)', + blur: 3 + } + } +}; + +export const aggregatedValueCardDefaultKeySettings: AggregatedValueCardKeySettings = { + position: AggregatedValueCardKeyPosition.center, + font: { + family: 'Roboto', + size: 14, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '1' + }, + color: constantColor('rgba(0, 0, 0, 0.87)'), + showArrow: false +}; + +export const createDefaultAggregatedValueLatestDataKeys = (keyName: string, units): DataKey[] => [ + { + name: keyName, label: keyName, type: DataKeyType.timeseries, units, decimals: 0, + aggregationType: AggregationType.NONE, + settings: { + position: AggregatedValueCardKeyPosition.center, + font: { + family: 'Roboto', + size: 52, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '1' + }, + color: constantColor('rgba(0, 0, 0, 0.87)'), + showArrow: false + } as AggregatedValueCardKeySettings + }, + { + name: keyName, label: 'Delta percent ' + keyName, type: DataKeyType.timeseries, units: '%', decimals: 0, + aggregationType: AggregationType.AVG, + comparisonEnabled: true, + timeForComparison: 'previousInterval', + comparisonResultType: ComparisonResultType.DELTA_PERCENT, + settings: { + position: AggregatedValueCardKeyPosition.rightTop, + font: { + family: 'Roboto', + size: 14, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '1' + }, + color: { + color: 'rgba(0, 0, 0, 0.87)', + type: ColorType.range, + rangeList: [ + {to: 0, color: '#198038'}, + {from: 0, to: 0, color: 'rgba(0, 0, 0, 0.87)'}, + {from: 0, color: '#D12730'} + ], + colorFunction: '' + }, + showArrow: true + } as AggregatedValueCardKeySettings + }, + { + name: keyName, label: 'Delta absolute ' + keyName, type: DataKeyType.timeseries, units, decimals: 1, + aggregationType: AggregationType.AVG, + comparisonEnabled: true, + timeForComparison: 'previousInterval', + comparisonResultType: ComparisonResultType.DELTA_ABSOLUTE, + settings: { + position: AggregatedValueCardKeyPosition.rightBottom, + font: { + family: 'Roboto', + size: 11, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '1' + }, + color: constantColor('rgba(0, 0, 0, 0.38)'), + showArrow: false + } as AggregatedValueCardKeySettings + } + ]; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html index fee7dc5259..377e0a31f8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.html @@ -66,7 +66,7 @@
{{ label$ | async }}
-
{{ dateFormat.formatted }}
+
{{ valueText }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.models.ts index 64267a5637..907878368d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.models.ts @@ -83,7 +83,7 @@ export function loadNodeCtxFunction any>(functionB } export function materialIconHtml(materialIcon: string): string { - return '' + materialIcon + ''; + return '' + materialIcon + ''; } export function iconUrlHtml(iconUrl: string): string { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts index 844d7540ff..7faa9e9de3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts @@ -132,6 +132,7 @@ export interface TbFlotYAxisSettings { ticksFormatter: string; tickDecimals: number; tickSize: number; + tickGenerator: string; } export interface TbFlotBaseSettings { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index 1d20068e20..e38bb3b098 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -18,7 +18,8 @@ import { WidgetContext } from '@home/models/widget-component.models'; import { createLabelFromDatasource, - deepClone, formattedDataFormDatasourceData, + deepClone, + formattedDataFormDatasourceData, insertVariable, isDefined, isDefinedAndNotNull, @@ -59,6 +60,7 @@ import { AggregationType } from '@shared/models/time/time.models'; import { CancelAnimationFrame } from '@core/services/raf.service'; import { UtilsService } from '@core/services/utils.service'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { BehaviorSubject } from 'rxjs'; import Timeout = NodeJS.Timeout; const moment = moment_; @@ -130,9 +132,15 @@ export class TbFlot { private pieAnimationLastTime: number; private pieAnimationCaf: CancelAnimationFrame; - constructor(private ctx: WidgetContext, private readonly chartType: ChartType, private $flotElement?: JQuery) { + private yMinSubject = new BehaviorSubject(-1); + private yMaxSubject = new BehaviorSubject(1); + + yMin$ = this.yMinSubject.asObservable(); + yMax$ = this.yMaxSubject.asObservable(); + + constructor(private ctx: WidgetContext, private readonly chartType: ChartType, private $flotElement?: JQuery, settings?: TbFlotSettings) { this.chartType = this.chartType || 'line'; - this.settings = ctx.settings as TbFlotSettings; + this.settings = settings || (ctx.settings as TbFlotSettings); this.utils = this.ctx.$injector.get(UtilsService); this.enableSelection = isDefined(this.settings.enableSelection) ? this.settings.enableSelection : true; this.selectionMode = this.enableSelection ? 'x' : null; @@ -209,6 +217,12 @@ export class TbFlot { } else { this.yaxis.tickSize = null; } + if (this.settings.yaxis.tickGenerator?.length) { + try { + this.yaxis.ticks = new Function('axis', + this.settings.yaxis.tickGenerator); + } catch (e) {} + } if (isNumber(this.settings.yaxis.tickDecimals)) { this.yaxis.tickDecimals = this.settings.yaxis.tickDecimals; } else { @@ -717,6 +731,15 @@ export class TbFlot { } } + public updateSeriesColor(color: string) { + if (this.subscription?.data?.length) { + const series = this.subscription.data[0] as TbFlotSeries; + series.dataKey.color = color; + series.color = color; + series.highlightColor = tinycolor(color).setAlpha(.75).toRgbString(); + } + } + private latestDataByDataIndex(index: number): FormattedData { if (this.latestData[index]) { return this.latestData[index]; @@ -802,6 +825,8 @@ export class TbFlot { clearTimeout(this.resizeTimeoutHandle); this.resizeTimeoutHandle = null; } + this.yMinSubject.complete(); + this.yMaxSubject.complete(); } private createPlot() { @@ -818,6 +843,7 @@ export class TbFlot { } else { this.plot = $.plot(this.$element, this.subscription.data, this.options) as JQueryPlot; } + this.updateYMinMax(); } else { this.createPlotTimeoutHandle = setTimeout(this.createPlot.bind(this), 30); } @@ -830,6 +856,20 @@ export class TbFlot { this.plot.setupGrid(); } this.plot.draw(); + this.updateYMinMax(); + } + + private updateYMinMax() { + if (this.plot?.getYAxes().length) { + const min = this.plot?.getYAxes()[0].min; + const max = this.plot?.getYAxes()[0].max; + if (this.yMinSubject.value !== min) { + this.yMinSubject.next(min); + } + if (this.yMaxSubject.value !== max) { + this.yMaxSubject.next(max); + } + } } private redrawPlot() { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component.html new file mode 100644 index 0000000000..32d48347ac --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component.html @@ -0,0 +1,48 @@ + + +
+
widgets.aggregated-value-card.value-appearance
+
+
{{ 'widgets.aggregated-value-card.position' | translate }}
+ + + + {{ aggregatedValueCardKeyPositionTranslationMap.get(position) | translate }} + + + +
+
+
{{ 'widgets.aggregated-value-card.font' | translate }}
+ + +
+
+
{{ 'widgets.aggregated-value-card.color' | translate }}
+ + +
+
+ + {{ 'widgets.aggregated-value-card.display-up-down-arrow' | translate }} + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component.ts new file mode 100644 index 0000000000..e527c3b3d4 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component.ts @@ -0,0 +1,64 @@ +/// +/// Copyright © 2016-2023 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 } from '@angular/core'; +import { 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 { + aggregatedValueCardDefaultKeySettings, + AggregatedValueCardKeyPosition, + aggregatedValueCardKeyPositionTranslations +} from '@home/components/widget/lib/cards/aggregated-value-card.models'; +import { constantColor } from '@shared/models/widget-settings.models'; + +@Component({ + selector: 'tb-aggregated-value-card-key-settings', + templateUrl: './aggregated-value-card-key-settings.component.html', + styleUrls: ['./../widget-settings.scss'] +}) +export class AggregatedValueCardKeySettingsComponent extends WidgetSettingsComponent { + + aggregatedValueCardKeyPositions: AggregatedValueCardKeyPosition[] = + Object.keys(AggregatedValueCardKeyPosition).map(value => AggregatedValueCardKeyPosition[value]); + + aggregatedValueCardKeyPositionTranslationMap = aggregatedValueCardKeyPositionTranslations; + + aggregatedValueCardKeySettingsForm: UntypedFormGroup; + + constructor(protected store: Store, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.aggregatedValueCardKeySettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...aggregatedValueCardDefaultKeySettings}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.aggregatedValueCardKeySettingsForm = this.fb.group({ + position: [settings.position, []], + font: [settings.font, []], + color: [settings.color, []], + showArrow: [settings.showArrow, []] + }); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts index 46454937f6..9241f60dda 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-widget-settings.component.ts @@ -74,7 +74,8 @@ export const flotDefaultSettings = (chartType: ChartType): Partial - mdi:function-variant + mdi:function-variant
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts index 6d8ad1eefe..f92203459e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/color-settings.component.ts @@ -99,7 +99,7 @@ export class ColorSettingsComponent implements OnInit, ControlValueAccessor { } private updateColorStyle() { - if (!this.disabled) { + if (!this.disabled && this.modelValue) { let colors: string[] = [this.modelValue.color]; if (this.modelValue.type === ColorType.range && this.modelValue.rangeList?.length) { const rangeColors = this.modelValue.rangeList.slice(0, Math.min(2, this.modelValue.rangeList.length)).map(r => r.color); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index 1e4010faaa..0f467ba917 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -267,6 +267,9 @@ import { ValueCardWidgetSettingsComponent } from '@home/components/widget/lib/settings/cards/value-card-widget-settings.component'; import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings/common/widget-settings-common.module'; +import { + AggregatedValueCardKeySettingsComponent +} from '@home/components/widget/lib/settings/cards/aggregated-value-card-key-settings.component'; @NgModule({ declarations: [ @@ -366,7 +369,8 @@ import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings TripAnimationWidgetSettingsComponent, DocLinksWidgetSettingsComponent, QuickLinksWidgetSettingsComponent, - ValueCardWidgetSettingsComponent + ValueCardWidgetSettingsComponent, + AggregatedValueCardKeySettingsComponent ], imports: [ CommonModule, @@ -471,7 +475,8 @@ import { WidgetSettingsCommonModule } from '@home/components/widget/lib/settings TripAnimationWidgetSettingsComponent, DocLinksWidgetSettingsComponent, QuickLinksWidgetSettingsComponent, - ValueCardWidgetSettingsComponent + ValueCardWidgetSettingsComponent, + AggregatedValueCardKeySettingsComponent ] }) export class WidgetSettingsModule { @@ -541,5 +546,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type ({ @@ -117,18 +119,44 @@ export const constantColor = (color: string): ColorSettings => ({ 'return \'blue\';' }); +export const cssSizeToStrSize = (size?: number, unit?: cssUnit): string => (isDefinedAndNotNull(size) ? size + '' : '0') + (unit || 'px'); + +export const resolveCssSize = (strSize?: string): [number, cssUnit] => { + if (!strSize || !strSize.trim().length) { + return [0, 'px']; + } + let resolvedUnit: cssUnit; + let resolvedSize = strSize; + for (const unit of cssUnits) { + if (strSize.endsWith(unit)) { + resolvedUnit = unit; + break; + } + } + if (resolvedUnit) { + resolvedSize = strSize.substring(0, strSize.length - resolvedUnit.length); + } + resolvedUnit = resolvedUnit || 'px'; + let numericSize = 0; + if (isNumeric(resolvedSize)) { + numericSize = Number(resolvedSize); + } + return [numericSize, resolvedUnit]; +}; + type ValueColorFunction = (value: any) => string; export abstract class ColorProcessor { static fromSettings(color: ColorSettings): ColorProcessor { - switch (color.type) { + const settings = color || constantColor('rgba(0, 0, 0, 0.87)'); + switch (settings.type) { case ColorType.constant: - return new ConstantColorProcessor(color); + return new ConstantColorProcessor(settings); case ColorType.range: - return new RangeColorProcessor(color); + return new RangeColorProcessor(settings); case ColorType.function: - return new FunctionColorProcessor(color); + return new FunctionColorProcessor(settings); } } @@ -164,13 +192,19 @@ class RangeColorProcessor extends ColorProcessor { if (this.settings.rangeList?.length && isDefinedAndNotNull(value) && isNumeric(value)) { const num = Number(value); for (const range of this.settings.rangeList) { - if ((!isNumber(range.from) || num >= range.from) && (!isNumber(range.to) || num < range.to)) { + if (this.constantRange(range) && range.from === num) { + return range.color; + } else if ((!isNumber(range.from) || num >= range.from) && (!isNumber(range.to) || num < range.to)) { return range.color; } } } return this.settings.color; } + + private constantRange(range: ColorRange): boolean { + return isNumber(range.from) && isNumber(range.to) && range.from === range.to; + } } class FunctionColorProcessor extends ColorProcessor { @@ -242,7 +276,7 @@ export abstract class DateFormatProcessor { } } - formatted = ''; + formatted = ' '; protected constructor(protected $injector: Injector, protected settings: DateFormatSettings) { @@ -412,3 +446,13 @@ export const getSingleTsValue = (data: Array): [number, any] => } return null; }; + +export const getLatestSingleTsValue = (data: Array): [number, any] => { + if (data.length) { + const dsData = data[0]; + if (dsData.data.length) { + return dsData.data[dsData.data.length - 1]; + } + } + return null; +}; 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 f90a34fe8e..78728005de 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1208,7 +1208,11 @@ "delta-calculation-result-delta-absolute": "Delta (absolute)", "delta-calculation-result-delta-percent": "Delta (percent)", "source": "Source", - "latest": "Latest" + "latest": "Latest", + "latest-value": "Latest value", + "delta": "delta", + "percent": "percent", + "absolute": "absolute" }, "datasource": { "type": "Datasource type", @@ -3911,6 +3915,7 @@ "icon-position-right": "Right", "font": "Font", "color": "Color", + "displayTypePrefix": "Display Realtime/History prefix", "preview": "Preview" }, "unit": { @@ -5718,6 +5723,25 @@ "date": "Date", "value-card-style": "Value card style" }, + "aggregated-value-card": { + "subtitle": "Subtitle", + "chart": "Chart", + "values": "Values", + "value-appearance": "Value appearance", + "position": "Position", + "position-center": "Center", + "position-right-top": "Right top", + "position-right-bottom": "Right bottom", + "position-left-top": "Left top", + "position-left-bottom": "Left bottom", + "font": "Font", + "color": "Color", + "display-up-down-arrow": "Display Up/Down arrow", + "add-value": "Add value", + "remove-value": "Remove value", + "no-values": "No values configured", + "aggregation": "Aggregation" + }, "table": { "common-table-settings": "Common Table Settings", "enable-search": "Enable search", diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index bef8bf621e..7d255e6ccf 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -122,18 +122,6 @@ font: inherit; } } - .mat-slide { - margin: 0; - &.margin { - margin: 8px 0; - } - .mdc-form-field>label { - font-weight: 400; - font-size: 16px; - line-height: 24px; - margin-left: 12px; - } - } } .tb-form-panel-title { @@ -200,6 +188,21 @@ } } + .tb-form-panel, .tb-form-row { + .mat-slide { + margin: 0; + &.margin { + margin: 8px 0; + } + .mdc-form-field>label { + font-weight: 400; + font-size: 16px; + line-height: 24px; + margin-left: 12px; + } + } + } + .tb-form-row .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { &.mat-form-field-appearance-fill { .mdc-text-field--filled:not(.mdc-text-field--disabled) { From d8896fe9dda7194cfbe92cac45e824250e5eca67 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 15 Aug 2023 17:34:10 +0300 Subject: [PATCH 420/421] Minor refactoring for user notification settings --- .../server/controller/NotificationController.java | 2 +- .../server/common/data/page/SortOrder.java | 2 +- .../DefaultNotificationSettingsService.java | 13 ++++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java index e57fb9ec00..f72b2dacae 100644 --- a/application/src/main/java/org/thingsboard/server/controller/NotificationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/NotificationController.java @@ -298,7 +298,7 @@ public class NotificationController extends BaseController { if (targetType == NotificationTargetType.PLATFORM_USERS) { PageData recipients = notificationTargetService.findRecipientsForNotificationTargetConfig(user.getTenantId(), (PlatformUsersNotificationTargetConfig) target.getConfiguration(), new PageLink(recipientsPreviewSize, 0, null, - SortOrder.byCreatedTimeDesc)); + SortOrder.BY_CREATED_TIME_DESC)); recipientsCount = (int) recipients.getTotalElements(); recipientsPart = recipients.getData().stream().map(r -> (NotificationRecipient) r).collect(Collectors.toList()); } else { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/page/SortOrder.java b/common/data/src/main/java/org/thingsboard/server/common/data/page/SortOrder.java index b99cb93eed..62a6377519 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/page/SortOrder.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/page/SortOrder.java @@ -36,6 +36,6 @@ public class SortOrder { ASC, DESC } - public static final SortOrder byCreatedTimeDesc = new SortOrder("createdTime", Direction.DESC); + public static final SortOrder BY_CREATED_TIME_DESC = new SortOrder("createdTime", Direction.DESC); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java index 04ffc4762e..4faed9cb20 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationSettingsService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.notification; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @@ -55,6 +56,7 @@ import java.util.Optional; @Service @RequiredArgsConstructor +@Slf4j public class DefaultNotificationSettingsService implements NotificationSettingsService { private final AdminSettingsService adminSettingsService; @@ -104,10 +106,15 @@ public class DefaultNotificationSettingsService implements NotificationSettingsS @Override public UserNotificationSettings getUserNotificationSettings(TenantId tenantId, UserId userId, boolean format) { UserSettings userSettings = userSettingsService.findUserSettings(tenantId, userId, UserSettingsType.NOTIFICATIONS); - UserNotificationSettings settings; + UserNotificationSettings settings = null; if (userSettings != null) { - settings = JacksonUtil.treeToValue(userSettings.getSettings(), UserNotificationSettings.class); - } else { + try { + settings = JacksonUtil.treeToValue(userSettings.getSettings(), UserNotificationSettings.class); + } catch (Exception e) { + log.warn("Failed to parse notification settings for user {}", userId, e); + } + } + if (settings == null) { settings = UserNotificationSettings.DEFAULT; } if (format) { From 943788f25e4ea1cb4373f095db8cd0b798b8a8d2 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 15 Aug 2023 17:39:14 +0300 Subject: [PATCH 421/421] UI: Aggregated value card --- .../json/system/widget_bundles/cards.json | 24 +++++++++++++++++++ .../aggregated-data-key-row.component.ts | 8 +++++-- .../aggregated-data-keys-panel.component.html | 3 +-- ...gated-value-card-basic-config.component.ts | 8 ++++--- .../basic/common/data-key-row.component.html | 2 +- .../common/data-keys-panel.component.html | 2 +- .../aggregated-value-card-widget.component.ts | 1 + ui-ngx/src/form.scss | 16 +++++++++---- 8 files changed, 50 insertions(+), 14 deletions(-) diff --git a/application/src/main/data/json/system/widget_bundles/cards.json b/application/src/main/data/json/system/widget_bundles/cards.json index 858d816338..be46aebec1 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -267,6 +267,30 @@ "basicModeDirective": "tb-value-card-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"constant\",\"color\":\"#5469FF\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" } + }, + { + "alias": "aggregated_value_card", + "name": "Aggregated value card", + "image": null, + "description": null, + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"watermeter\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 10 - 5;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 80) {\\n\\tvalue = 80;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Avg watermeter\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 10 - 5;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 80) {\\n\\tvalue = 80;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m³\",\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent watermeter\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random 2\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m³\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Aggregated value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"water_drop\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false}}" + } } ] } \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts index 106412cab0..411a6a03b6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-key-row.component.ts @@ -33,7 +33,7 @@ import { ComparisonResultType, DataKey, DataKeyConfigMode, - DatasourceType, + DatasourceType, Widget, widgetType } from '@shared/models/widget.models'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; @@ -100,6 +100,10 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn return this.widgetConfigComponent.widgetConfigCallbacks; } + get widget(): Widget { + return this.widgetConfigComponent.widget; + } + get isEntityDatasource(): boolean { return [DatasourceType.device, DatasourceType.entity].includes(this.datasourceType); } @@ -190,7 +194,7 @@ export class AggregatedDataKeyRowComponent implements ControlValueAccessor, OnIn dataKeySettingsDirective: null, dashboard: null, aliasController: null, - widget: null, + widget: this.widget, widgetType: widgetType.latest, deviceId: null, entityAliasId: null, diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html index cee5b14dde..5ffbc2a018 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-data-keys-panel.component.html @@ -28,8 +28,7 @@
-
+
k.name === keyName); } return []; } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html index 05275e0a70..63f936195a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-key-row.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
{{ 'datakey.timeseries' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html index 4c2c9a834a..78f96d8264 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/common/data-keys-panel.component.html @@ -32,7 +32,7 @@ [cdkDropListDisabled]="!dragEnabled" (cdkDropListDropped)="keyDrop($event)">